I'm working on a WebAPI with ASP.Net 4.7.2 and a ASP.Net Core 3.1 Webapplication as a client. The WebAPI is hosted on my local IIS. I'm also testing the WebAPI with a windows forms application.
In one action method I get an InternalServerError with the only message "Error". The error shows up in the client's HttpResponseMessage after the call, but neither in the WebAPI action nor in the global exception filter. I am not able to debug it although I set everywhere breakpoints. In the action I get the result correctly.
The controller:
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 );
}
}
The service method:
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>(
// ...
);
}
The call from the (windows forms) client:
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();
}
}
In the client I get the InternalServerError but no exception could be cought in the WebAPI. I finally added this to the WebAPI configuration:
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
and have breakpoints in the action method and also in the global error handler:
public class GlobalErrorHandlingFilterAttribute : ExceptionFilterAttribute
{
public override void OnException( HttpActionExecutedContext context )
{
//......
}
}
From where could come this mysterious error or how can I debug it?
Now I found out the reason for the problem. For anyone who gets the same strange undebuggable error.
I read out the HttpResponseMessage in the client with
var result = msg.Content.ReadAsStringAsync().Result
and could finally read the exception details:
"{"Message":"Error",
"ExceptionMessage":
"ExceptionType":"System.InvalidOperationException",
"StackTrace":null,
"InnerException":{
"Message":"Error",
"ExceptionMessage":"The SqlParameter is already contained by another SqlParameterCollection.",
"ExceptionType":"System.ArgumentException",
The problem was my additional testing call in the controller:
// testing result data
var list = result.ToList();
That means that the method in the service with the sql parameters and the stored procedure was called twice and the sql parameter was used a second time, which is obviously not allowed. I also could detect the second call int the SQL Server Profiler. With removing this line the problem was solved.
But the mysterious thing is anyway that this exception is not cought in any place in the web api and is not debuggable. I'm not sure whether this a bug in the .NET Framework.
UPDATE:
I found out, that the global error handler as a FilterAttribute it not global enough. A ExceptionLogger or ExceptionHandler should be used for Web API's (v2) like described here: https://learn.microsoft.com/en-us/aspnet/web-api/overview/error-handling/web-api-global-error-handling