Global exception handling in OWIN middleware

泪湿孤枕 提交于 2019-11-28 03:49:47
Taiseer Joudeh

Ok, so this was easier than anticipated, thanks for @Khalid for the heads up, I have ended up creating an owin middleware named OwinExceptionHandlerMiddleware which is dedicated for handling any exception happening in any Owin Middleware (logging it and manipulating the response before returning it to the client).

You need to register this middleware as the first one in the Startup class as the below:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var httpConfig = new HttpConfiguration();

        httpConfig.MapHttpAttributeRoutes();

        httpConfig.Services.Replace(typeof(IExceptionHandler), new ContentNegotiatedExceptionHandler());

        httpConfig.Services.Add(typeof(IExceptionLogger), new NLogExceptionLogger());

        OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new AuthorizationServerProvider()
        };

        //Should be the first handler to handle any exception happening in OWIN middlewares
        app.UseOwinExceptionHandler();

        // Token Generation
        app.UseOAuthAuthorizationServer(OAuthServerOptions);

        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

        app.UseWebApi(httpConfig);
    }
}

And the code used in the OwinExceptionHandlerMiddleware as the below:

using AppFunc = Func<IDictionary<string, object>, Task>;

public class OwinExceptionHandlerMiddleware
{
    private readonly AppFunc _next;

    public OwinExceptionHandlerMiddleware(AppFunc next)
    {
        if (next == null)
        {
            throw new ArgumentNullException("next");
        }

        _next = next;
    }

    public async Task Invoke(IDictionary<string, object> environment)
    {
        try
        {
            await _next(environment);
        }
        catch (Exception ex)
        {
            try
            {

                var owinContext = new OwinContext(environment);

                NLogLogger.LogError(ex, owinContext);

                HandleException(ex, owinContext);

                return;
            }
            catch (Exception)
            {
                // If there's a Exception while generating the error page, re-throw the original exception.
            }
            throw;
        }
    }
    private void HandleException(Exception ex, IOwinContext context)
    {
        var request = context.Request;

        //Build a model to represet the error for the client
        var errorDataModel = NLogLogger.BuildErrorDataModel(ex);

        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
        context.Response.ReasonPhrase = "Internal Server Error";
        context.Response.ContentType = "application/json";
        context.Response.Write(JsonConvert.SerializeObject(errorDataModel));

    }

}

public static class OwinExceptionHandlerMiddlewareAppBuilderExtensions
{
    public static void UseOwinExceptionHandler(this IAppBuilder app)
    {
        app.Use<OwinExceptionHandlerMiddleware>();
    }
}

There are a few ways to do what you want:

  1. Create middleware that is registered first, then all exceptions will bubble up to that middleware. At this point just write out your JSON out via the Response object via the OWIN context.

  2. You can also create a wrapping middleware which wraps the Oauth middleware. In this case it will on capture errors originating from this specific code path.

Ultimately writing your JSON message is about creating it, serializing it, and writing it to the Response via the OWIN context.

It seems like you are on the right path with #1. Hope this helps, and good luck :)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!