简体   繁体   English

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

[英].Net Web API returns occasionally no response at all if Exception is thrown

First of all a bit of background. 首先有一点背景。
I am using .Net Framework 4.6.1, Microsoft.AspNet.WebApi 5.2.4 in Visual Studio 2017 Community. 我在Visual Studio 2017社区中使用.Net Framework 4.6.1,Microsoft.AspNet.WebApi 5.2.4。

My ApiController's implement endpoints which throw intended Exceptions for example if certain requirements are not met. 我的ApiController的实现端点会抛出预期的异常,例如,如果不满足某些要求的话。 I added global ExceptionFilterAttribute and ExceptionHandler to handle those Exceptions and to return a proper response. 我添加了全局ExceptionFilterAttribute和ExceptionHandler来处理这些异常并返回正确的响应。 The Exceptions are of a type which are inherited of System.Exception. 异常是从System.Exception继承的类型。
This is only working occasionally as intended. 这只是偶尔按预期工作。 Every second or third or sometimes fifth (no real pattern) request the api server returns no response at all eg for example Postman says: "Could not get any response". 每隔第二个或第三个或第五个(有时不是真实模式)请求,api服务器根本不返回任何响应,例如Postman说:“无法获得任何响应”。
To test this I used the same endpoint with the same input. 为了测试这一点,我使用了具有相同输入的相同端点。

Here are a few things I did to get a better idea of the problem: 为了更好地了解问题,我做了以下几件事:
I added exception logging to Global.asax (to catch First Chance Exceptions) 我向Global.asax添加了异常日志记录(以捕获“第一机会异常”)
I subscribed to Global.asax Application_Error Event 我订阅了Global.asax Application_Error事件
I looked at the IIS logs 我看了看IIS日志

None of those got my closer to the issue. 这些都没有使我更接近这个问题。 The exception was caught and logged in Global.asax like expected but no additional error or exception which could give me more info to my problem. 异常已按预期方式捕获并记录在Global.asax中,但没有其他错误或异常,它可以为我的问题提供更多信息。

Here is my code: 这是我的代码:
I simplified the ApiController's function and removed the business logic. 我简化了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)
    {
    }
}

For now I put a workaround in place which looks like this: 现在,我将一个变通方法放置在这样的地方:

[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;
    }
}

I would appreciate any ideas how to debug this or any suggestions to fix it. 我将不胜感激如何调试或解决它的任何建议。

Can you try inheriting from IHttpActionResult and use it as returning the exception from your GlobalExceptionHandler 您可以尝试从IHttpActionResult继承并将其用作从GlobalExceptionHandler返回异常的方法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);
        }
    }

and call it like, 并称它为

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);
}

From GlobalExceptionHandler : ExceptionHandler 来自GlobalExceptionHandler : ExceptionHandler

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ASP.NET Web API 2-在发布模式下不在响应主体中引发异常 - ASP.NET Web API 2 - thrown Exception not in response body in Release mode 如何处理Web API控制器引发的异常? - How to deal with exception thrown by Web API controller? ASP.NET Web API在json响应中返回空集合 - ASP.NET Web API returns empty collection in json response 在ASP.NET Web API C#上使用Regex引发过滤IEnumerable集合的异常 - Exception thrown filtering IEnumerable collection using Regex on ASP.NET Web API C# API 异常过滤器在 ASP.NET MVC 中返回 200 响应代码 - API exception filter returns 200 response code on exception in ASP.NET MVC 为什么 RestAPI 偶尔会返回 429 TooManyRequest 响应? - Why RestAPI occasionally returns 429 TooManyRequest response? 使用 ASP.NET Core 2.2 Web API 项目中的实体框架类库时抛出异常 - Exception thrown when using Entity Framework class library from ASP.NET Core 2.2 Web API project Web API 中的模型验证 - 在没有 throw 语句的情况下抛出异常? - Model validation in Web API - Exception is thrown with out a throw statement? 在第一个请求上抛出Web API Rest Service空引用异常 - Web api rest service null reference exception thrown on first request Web Api 2字符串响应以字符数组形式返回 - Web Api 2 string response returns as an array of characters
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM