ASP.NET Core 3.1中Middleware和Filter用法实践

ASP.NET Core 3.1中Middleware和Filter用法实践

前言

在我们用ASP.NET Core进行开发的过程中经常使用到两种AOP技术中间件(Middleware)和过滤器(Filter),很多时候两个组件有很多相似的用法,具体什么场景应用什么组件其实是很模糊的,下面我通过自己的实践和举例来进行讲解。

组件介绍

具体Middleware和Filter各自怎么用,已经有很多文章和Demo参考,今天我们来说一下,Filter和Middleware在Request请求中的顺序问题,在微软官网文档中在对Filters介绍之前有这样一段话

Filters run within the ASP.NET Core action invocation pipeline, sometimes referred to as the filter pipeline. The filter pipeline runs after ASP.NET Core selects the action to execute.

还有一张图示如下:

ASP.NET Core 3.1中Middleware和Filter用法实践

通过该段说明和图示我们可以知道,Request首先是经过系统或我们自定义的Middleware之后经过Action Selection,然后才会进入Filter Pipeline。

实践举例

下面来提供一个Middleware和Filter联合使用的场景,分别用到TraceIdMiddleware,ExceptionMiddleware和TokenFilter

TraceIdMiddleware主要用于拦截Request,检查是否带有traceid这个Header,如果没有就添加一个traceid的header到Request请求中,代码如下:

 public class TraceIdMiddleware
    {
        private readonly RequestDelegate _next;

        public TraceIdMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            string traceid = null;
            if (context.Request.Headers.TryGetValue("traceid", out var htraceId))
            {
                traceid = htraceId.ToString();
            }
            if (string.IsNullOrEmpty(traceid))
            {
                traceid = Guid.NewGuid().ToString();
                context.Request.Headers.Add("traceid", traceid);
            }
            await _next.Invoke(context);
        }
    }
    public static class TraceIdMiddlewareExtensions
    {
        public static IApplicationBuilder UseTraceId(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<TraceIdMiddleware>();
        }
    }

ExceptionMiddleware为全局捕获异常中间件,用于全局拦截我们代码中未catch的异常,返回统一格式。代码如下:

 public class ExceptionMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<ExceptionMiddleware> _logger;
        public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }
        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _next.Invoke(context);
            }
            catch (Exception e)
            {
                await HandleException(context, e);
            }
        }
        private async Task HandleException(HttpContext context, Exception e)
        {
            context.Response.StatusCode = 200;
            context.Response.ContentType = "text/json;charset=utf-8;";
            _logger.LogError(e.Message);
            string error = JsonSerializer.Serialize(new { Code = 500, Message = e.Message });
            await context.Response.WriteAsync(error);
        }


    }
    public static class ExceptionMiddlewareExtensions
    {
        public static IApplicationBuilder UseException(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<ExceptionMiddleware>();
        }
    }

TokenFilter实现了接口,获取请求中的token并验证其合法性。具体代码如下:

 public class TokenFilter : Attribute, IAuthorizationFilter
    {
        private readonly ILogger<TokenFilter> _logger;
        public TokenFilter(ILogger<TokenFilter> logger)
        {
            _logger = logger;
        }
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            string token = null;
            if (context.HttpContext.Request.Headers.TryGetValue("token", out var utoken))
            {
                userToken = utoken.ToString();
            }
            if (string.IsNullOrEmpty(userToken))
            {
                var traceId = context.HttpContext.Request.Headers["traceid"].ToString();
                _logger.LogInformation($"traceId:{traceId},Error:认证失败");
                throw new Exception("认证失败");
            }
            // something else
             
        }
    }

三个组件执行时序图如下:

ASP.NET Core 3.1中Middleware和Filter用法实践

Requset请求首先进入TraceIdMiddleware,检测是否有traceid的header,没有则赋值,然后经过ExceptionMiddleware不对Request进行处理,在TokenFilter中验证token,如果token无效则记录日志并抛出异常,日志中包含header中的traceid,在返回路径中ExceptionMiddleware将会捕获返回值中的Exception,统一返回格式并返回。

总结

通过以上的例子我们可以总结出两点:

  1. Middleware执行于Action Selection之前,所以我们应该将一些业务无关的功能放在Middleware中,而将一些业务相关的内容放在Filter中来处理。
  2. 在同时使用Middleware和Filter时,一定要注意使用顺序,以免出现不必要的异常。

ASP.NET Core 3.1中Middleware和Filter用法实践

上一篇:java eclipse工程有叹号解决步骤


下一篇:使用Spring RMI调用远程方法