来自ASP.Net Web API 2的统一,一致的错误响应

har*_*don 15 c# asp.net asp.net-web-api asp.net-web-api2

我正在开发一个Web API 2应用程序,我正在尝试以统一的方式格式化错误重定位(这样消费者也将知道他们可以检查哪些数据对象/结构以获得有关错误的更多信息).这是我到目前为止所得到的:

{   
    "Errors":
    [
        {
            "ErrorType":5003,
            "Message":"Error summary here",
            "DeveloperAction":"Some more detail for API consumers (in some cases)",
            "HelpUrl":"link to the docs etc."
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

这适用于应用程序本身抛出的异常(即内部控制器).但是,如果用户请求错误的URI(并获得404)或使用错误的动词(并获得405)等,Web Api 2会发出默认错误消息,例如

{
     Message: "No HTTP resource was found that matches the request URI 'http://localhost/abc'."
}
Run Code Online (Sandbox Code Playgroud)

是否有任何方法可以捕获这些类型的错误(404,405等)并将它们格式化为上面第一个示例中的错误响应?

到目前为止,我已经尝试过:

  • 自定义ExceptionAttribute inherting ExceptionFilterAttribute
  • 自定义ControllerActionInvoker inherting ApiControllerActionInvoker
  • IExceptionHandler (Web API 2.1中新的全局错误处理功能)

但是,这些方法都不能捕获这些类型的错误(404,405等).关于如何实现这一目标的任何想法?

......或者,我是以错误的方式解决这个问题的?我是否应该仅针对应用程序/用户级别错误格式化我的特定样式的错误响应,并依赖于404之类的默认错误响应?

Dan*_*n H 9

您可以覆盖DelegatingHandler抽象类并拦截对客户端的响应.这将使您能够返回您想要的内容.

这是关于它的一些信息. http://msdn.microsoft.com/en-us/library/system.net.http.delegatinghandler(v=vs.118).aspx

这是Web Api管道的海报,显示了可以覆盖的内容. http://www.asp.net/posters/web-api/asp.net-web-api-poster.pdf

像这样创建一个Handler类来覆盖响应

public class MessageHandler1 : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
    {
        Debug.WriteLine("Process request");
        // Call the inner handler.
        var response = base.SendAsync(request, cancellationToken);

        Debug.WriteLine("Process response");
        if (response.Result.StatusCode == HttpStatusCode.NotFound)
        {
            //Create new HttpResponseMessage message
        }
        ;
        return response;
    }
}
Run Code Online (Sandbox Code Playgroud)

在WebApiConfig.cs类中添加处理程序.

config.MessageHandlers.Add(new MessageHandler1());
Run Code Online (Sandbox Code Playgroud)

更新 正如Kiran在评论中提到的,您可以使用OwinMiddleware拦截返回给客户端的响应.这适用于在任何主机上运行的MVC和Web Api.

这是一个如何获取响应并在客户端进行更改时的示例.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Use(typeof(MyMiddleware)); 
    }
}

public class MyMiddleware : OwinMiddleware
{
    public MyMiddleware(OwinMiddleware next) : base(next) { }

    public override async Task Invoke(IOwinContext context)
    {
        await Next.Invoke(context);
        if(context.Response.StatusCode== 404)
        {
            context.Response.StatusCode = 403;
            context.Response.ReasonPhrase = "Blah";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)