如果引发异常,.Net Web API有时会完全不返回任何响应

时间:2019-03-06 04:52:23

标签: c# .net asp.net-web-api

首先要有一些背景知识。
我在Visual Studio 2017社区中使用.Net Framework 4.6.1,Microsoft.AspNet.WebApi 5.2.4。

我的ApiController的实现端点会抛出预期的异常,例如,如果不满足某些要求。我添加了全局ExceptionFilterAttribute和ExceptionHandler来处理这些异常并返回正确的响应。 异常是从System.Exception继承的类型。
这只是偶尔按预期工作。每隔第二个或第三个或第五个(无实模式)请求,api服务器根本不会返回任何响应,例如例如Postman说:“无法得到任何回应”。
为了测试这一点,我使用了具有相同输入的相同端点。

为帮助更好地了解问题,我做了以下几件事:
我向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;
    }
}

对于任何有关调试方法的建议或修复建议,我将不胜感激。

1 个答案:

答案 0 :(得分:1)

您能否尝试从IHttpActionResult继承并将其用作从GlobalExceptionHandler返回的异常

 private class ErrorMessageResult : IHttpActionResult
    {
        private readonly HttpResponseMessage _httpResponseMessage;
        private HttpRequestMessage _request;

        public ErrorMessageResult(HttpRequestMessage request, HttpResponseMessage httpResponseMessage)
        {
            _request = request;
            _httpResponseMessage = httpResponseMessage;
        }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            return Task.FromResult(_httpResponseMessage);
        }
    }

并称呼它,

public override void Handle(ExceptionHandlerContext context)
{
    var result = new HttpResponseMessage(HttpStatusCode.InternalServerError)
    {
        Content = new StringContent("Internal Server Error Occurred"),
        ReasonPhrase = "Exception"
    };

    context.Result = new ErrorMessageResult(context.Request, result);
}

来自GlobalExceptionHandler : ExceptionHandler