Прежде всего немного фона.
Я использую .Net Framework 4.6.1, Microsoft.AspNet.WebApi 5.2.4 в сообществе Visual Studio 2017.
Конечные точки реализации моего ApiController, которые генерируют ожидаемые исключения, например, если определенные требования не выполняются. Я добавил глобальные ExceptionFilterAttribute и ExceptionHandler для обработки этих исключений и для возврата правильного ответа.
Исключения относятся к типу, который унаследован от System.Exception.
Это работает только изредка, как задумано. Каждый второй, третий или иногда пятый (без реального шаблона) запрос API-сервер не возвращает вообще никакого ответа, например, например, Почтальон говорит: «Не удалось получить ответ».
Чтобы проверить это, я использовал ту же конечную точку с тем же входом.
Вот несколько вещей, которые я сделал, чтобы лучше понять проблему:
Я добавил регистрацию исключений в Global.asax (чтобы отловить исключения первого шанса)
Я подписался на событие Global.asax Application_Error
Я посмотрел журналы IIS
Никто из них не подошел ближе к этому вопросу. Исключение было обнаружено и зарегистрировано в Global.asax, как и ожидалось, но без дополнительной ошибки или исключения, которое могло бы дать мне больше информации о моей проблеме.
Вот мой код:
Я упростил функцию ApiController и удалил бизнес-логику.
[Route("test")]
[HttpGet]
public IHttpActionResult GetTest()
{
throw new ObjectAlreadyExistsException("test");
return ResponseFactory.CreateOkResponse(null);
}
public class ExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is ObjectAlreadyExistsException)
{
context.Response = ResponseFactory.CreateErrorResponseMessage(context.Exception.Message, new Error("OBJECT_ALREADY_EXISTS_ERROR", context.Exception.Message));
}
else if (context.Exception is ObjectNotFoundException)
{
context.Response = ResponseFactory.CreateErrorResponseMessage(context.Exception.Message, new Error("OBJECT_NOT_FOUND_ERROR", context.Exception.Message));
}
base.OnException(context);
}
}
public class GlobalExceptionHandler : ExceptionHandler
{
private static readonly ILogger Log = new LoggerConfiguration()
.WriteTo.File(new CompactJsonFormatter(), Path.Combine(@Properties.Settings.Default.LOG_DIRECTORY, @"error.json"), rollOnFileSizeLimit: true, retainedFileCountLimit: 5, shared: true)
.Enrich.WithWebApiControllerName()
.Enrich.WithWebApiActionName()
.Enrich.WithWebApiRouteTemplate()
.Enrich.WithWebApiRouteData()
.Enrich.With(new AuthTokenEnricher())
.CreateLogger();
public override void Handle(ExceptionHandlerContext context)
{
if (context != null && context.Exception != null)
{
Log.Error("Unexpected Internal Server Error {Exception}", context.Exception);
}
context.Result = ResponseFactory.CreateErrorResponse(HttpStatusCode.InternalServerError, "Unexpected Internal Server Error", new Error("INTERNAL_SERVER_ERROR", "This request failed because of an unexpected server error."));
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//Exception filters
config.Filters.Add(new ExceptionFilter());
config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
// Web API routes
config.MapHttpAttributeRoutes();
}
}
public class ObjectAlreadyExistsException : Exception
{
public ObjectAlreadyExistsException(string message) : base(message)
{
}
public ObjectAlreadyExistsException(string message, Exception inner) : base(message, inner)
{
}
}
Сейчас я поставил обходной путь, который выглядит следующим образом:
[Route("test")]
[HttpGet]
public IHttpActionResult GetTest()
{
try
{
throw new ObjectAlreadyExistsException("test");
}
catch (Exception ex)
{
return CustomExceptionHandler.Handle(ex);
}
}
public class CustomExceptionHandler
{
private static readonly ILogger Log = new LoggerConfiguration()
.WriteTo.File(new CompactJsonFormatter(), Path.Combine(@Properties.Settings.Default.LOG_DIRECTORY, @"error.json"), rollOnFileSizeLimit: true, retainedFileCountLimit: 5, shared: true)
.Enrich.WithWebApiControllerName()
.Enrich.WithWebApiActionName()
.Enrich.WithWebApiRouteTemplate()
.Enrich.WithWebApiRouteData()
.Enrich.With(new AuthTokenEnricher())
.CreateLogger();
public static IHttpActionResult Handle(Exception ex)
{
IHttpActionResult result = null;
if (ex != null)
{
if (ex is ObjectAlreadyExistsException)
{
result = ResponseFactory.CreateErrorResponse(ex.Message, new Error("OBJECT_ALREADY_EXISTS_ERROR", ex.Message));
}
else if (ex is ObjectNotFoundException)
{
result = ResponseFactory.CreateErrorResponse(ex.Message, new Error("OBJECT_NOT_FOUND_ERROR", ex.Message));
}
}
if (result == null)
{
if (ex != null)
{
Log.Error("Unexpected Internal Server Error {Exception}", ex);
}
result = ResponseFactory.CreateErrorResponse(HttpStatusCode.InternalServerError, "Unexpected Internal Server Error", new Error("INTERNAL_SERVER_ERROR", "This request failed because of an unexpected server error."));
}
return result;
}
}
Буду признателен за любые идеи по отладке этого или за любые предложения по его исправлению.