ASP.Net WebAPI 中无法捕获的 InternalServerError
Uncatchable InternalServerError in ASP.Net WebAPI
我正在使用 ASP.Net 4.7.2 和 ASP.Net Core 3.1 Web 应用程序作为客户端开发 WebAPI。 WebAPI 托管在我的本地 IIS 上。我还在使用 windows 表单应用程序测试 WebAPI。
在一个操作方法中,我得到一个 InternalServerError 和唯一的消息 "Error"。错误在调用后显示在客户端的 HttpResponseMessage 中,但既不在 WebAPI 操作中也不在全局异常过滤器中。尽管我在各处都设置了断点,但我无法调试它。在行动中我得到了正确的结果。
控制器:
public class LogController : ApiController
{
private readonly ILog _logSrv;
public LogController( ILog logSrv )
{
_logSrv = logSrv;
}
public async Task<IHttpActionResult> Get( [FromUri] LogFilterModel model )
{
await LogAsync( GetCurrentUserLoginId(), "Log", "Get", $"Reading log data." );
var logs = _logSrv.Get(
model.UserLoginId,
DateTime.Parse( model.DateTimeFrom ), DateTime.Parse( model.DateTimeUntil ),
model.PageNumber, model.PageSize );
var result = logs
.Select( l => new LogModel
{
Id = l.Id,
Message = l.Message,
LoginId = l.LoginId,
Username = l.Username,
EventDate = l.EventDate,
EventType = (LogEventType)l.EventType
} );
// testing result data
var list = result.ToList();
return Ok( result );
}
}
服务方式:
public IEnumerable<ExtLog> Get( string[] roles,
long? loginId, DateTime datetimeFrom, DateTime datetimeUntil,
int pageNumber, int pageSize )
{
if ( !roles.Contains( Constants.RoleAdmin ) ) return null;
// preparing parameters
// ...
// and reading data through a stored procedure
return _context.Database.SqlQuery<ExtLog>(
// ...
);
}
来自(windows 表单)客户端的调用:
private async void ReadLogData()
{
var filter = new LogFilterModel
{
UserLoginId = 3,
DateTimeFrom = DateTime.Now.AddDays( -3 ).ToShortDateString(),
DateTimeUntil = DateTime.Now.AddDays( 1 ).ToShortDateString(),
PageNumber = 2,
PageSize = 20
};
try
{
var client = GetHttpClient();
string call = BaseURL + "/api/Log/Get" +
$"?UserLoginId={filter.UserLoginId}&" +
$"DateTimeFrom={filter.DateTimeFrom:d}&DateTimeUntil={filter.DateTimeUntil:d}&" +
$"PageNumber={filter.PageNumber}&PageSize={filter.PageSize}";
HttpResponseMessage msg = await client.GetAsync( call );
if ( msg.IsSuccessStatusCode )
{
tbLog.Text = msg.Content.ReadAsStringAsync().Result;
}
else
{
// error
if ( msg.Content != null && msg.Content.Headers.ContentLength > 0 )
{
try
{
using ( var cs = await msg.Content.ReadAsStreamAsync() )
{
var vt = await JsonSerializer.DeserializeAsync<JsonElement>( cs );
if ( vt.TryGetProperty( "Message", out JsonElement jValue ) )
tbLog.Text = jValue.GetString();
}
}
catch { }
}
}
}
catch ( Exception ex )
{
tbLog.Text = ex.ToString();
}
}
在客户端我得到 InternalServerError 但在 WebAPI 中不会出现异常。我最终将其添加到 WebAPI 配置中:
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
并且在操作方法和全局错误处理程序中都有断点:
public class GlobalErrorHandlingFilterAttribute : ExceptionFilterAttribute
{
public override void OnException( HttpActionExecutedContext context )
{
//......
}
}
这个神秘的错误是从哪里来的,或者我该如何调试它?
现在我找到了问题的原因。对于遇到同样奇怪的不可调试错误的任何人。
我用
读出了客户端中的HttpResponseMessage
var result = msg.Content.ReadAsStringAsync().Result
终于可以阅读异常详细信息了:
"{"Message":"Error",
"ExceptionMessage":
"ExceptionType":"System.InvalidOperationException",
"StackTrace":null,
"InnerException":{
"Message":"Error",
"ExceptionMessage":"The SqlParameter is already contained by another SqlParameterCollection.",
"ExceptionType":"System.ArgumentException",
问题是我在控制器中进行了额外的测试调用:
// testing result data
var list = result.ToList();
意思是调用了两次服务中带sql参数和存储过程的方法,第二次使用了sql参数,这显然是不允许的。我还可以检测到对 SQL Server Profiler 的第二次调用。删除这一行问题就解决了。
但奇怪的是这个异常在网络上的任何地方都没有出现 api 并且不可调试。我不确定这是否是 .NET Framework 中的错误。
更新:
我发现,作为 FilterAttribute 的全局错误处理程序不够全局。 ExceptionLogger 或 ExceptionHandler 应该用于 Web API's (v2),如下所述:
https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/web-api-global-error-handling
我正在使用 ASP.Net 4.7.2 和 ASP.Net Core 3.1 Web 应用程序作为客户端开发 WebAPI。 WebAPI 托管在我的本地 IIS 上。我还在使用 windows 表单应用程序测试 WebAPI。
在一个操作方法中,我得到一个 InternalServerError 和唯一的消息 "Error"。错误在调用后显示在客户端的 HttpResponseMessage 中,但既不在 WebAPI 操作中也不在全局异常过滤器中。尽管我在各处都设置了断点,但我无法调试它。在行动中我得到了正确的结果。
控制器:
public class LogController : ApiController
{
private readonly ILog _logSrv;
public LogController( ILog logSrv )
{
_logSrv = logSrv;
}
public async Task<IHttpActionResult> Get( [FromUri] LogFilterModel model )
{
await LogAsync( GetCurrentUserLoginId(), "Log", "Get", $"Reading log data." );
var logs = _logSrv.Get(
model.UserLoginId,
DateTime.Parse( model.DateTimeFrom ), DateTime.Parse( model.DateTimeUntil ),
model.PageNumber, model.PageSize );
var result = logs
.Select( l => new LogModel
{
Id = l.Id,
Message = l.Message,
LoginId = l.LoginId,
Username = l.Username,
EventDate = l.EventDate,
EventType = (LogEventType)l.EventType
} );
// testing result data
var list = result.ToList();
return Ok( result );
}
}
服务方式:
public IEnumerable<ExtLog> Get( string[] roles,
long? loginId, DateTime datetimeFrom, DateTime datetimeUntil,
int pageNumber, int pageSize )
{
if ( !roles.Contains( Constants.RoleAdmin ) ) return null;
// preparing parameters
// ...
// and reading data through a stored procedure
return _context.Database.SqlQuery<ExtLog>(
// ...
);
}
来自(windows 表单)客户端的调用:
private async void ReadLogData()
{
var filter = new LogFilterModel
{
UserLoginId = 3,
DateTimeFrom = DateTime.Now.AddDays( -3 ).ToShortDateString(),
DateTimeUntil = DateTime.Now.AddDays( 1 ).ToShortDateString(),
PageNumber = 2,
PageSize = 20
};
try
{
var client = GetHttpClient();
string call = BaseURL + "/api/Log/Get" +
$"?UserLoginId={filter.UserLoginId}&" +
$"DateTimeFrom={filter.DateTimeFrom:d}&DateTimeUntil={filter.DateTimeUntil:d}&" +
$"PageNumber={filter.PageNumber}&PageSize={filter.PageSize}";
HttpResponseMessage msg = await client.GetAsync( call );
if ( msg.IsSuccessStatusCode )
{
tbLog.Text = msg.Content.ReadAsStringAsync().Result;
}
else
{
// error
if ( msg.Content != null && msg.Content.Headers.ContentLength > 0 )
{
try
{
using ( var cs = await msg.Content.ReadAsStreamAsync() )
{
var vt = await JsonSerializer.DeserializeAsync<JsonElement>( cs );
if ( vt.TryGetProperty( "Message", out JsonElement jValue ) )
tbLog.Text = jValue.GetString();
}
}
catch { }
}
}
}
catch ( Exception ex )
{
tbLog.Text = ex.ToString();
}
}
在客户端我得到 InternalServerError 但在 WebAPI 中不会出现异常。我最终将其添加到 WebAPI 配置中:
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
并且在操作方法和全局错误处理程序中都有断点:
public class GlobalErrorHandlingFilterAttribute : ExceptionFilterAttribute
{
public override void OnException( HttpActionExecutedContext context )
{
//......
}
}
这个神秘的错误是从哪里来的,或者我该如何调试它?
现在我找到了问题的原因。对于遇到同样奇怪的不可调试错误的任何人。
我用
读出了客户端中的HttpResponseMessagevar result = msg.Content.ReadAsStringAsync().Result
终于可以阅读异常详细信息了:
"{"Message":"Error",
"ExceptionMessage":
"ExceptionType":"System.InvalidOperationException",
"StackTrace":null,
"InnerException":{
"Message":"Error",
"ExceptionMessage":"The SqlParameter is already contained by another SqlParameterCollection.",
"ExceptionType":"System.ArgumentException",
问题是我在控制器中进行了额外的测试调用:
// testing result data
var list = result.ToList();
意思是调用了两次服务中带sql参数和存储过程的方法,第二次使用了sql参数,这显然是不允许的。我还可以检测到对 SQL Server Profiler 的第二次调用。删除这一行问题就解决了。
但奇怪的是这个异常在网络上的任何地方都没有出现 api 并且不可调试。我不确定这是否是 .NET Framework 中的错误。
更新:
我发现,作为 FilterAttribute 的全局错误处理程序不够全局。 ExceptionLogger 或 ExceptionHandler 应该用于 Web API's (v2),如下所述: https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/web-api-global-error-handling