• [译]Writing Custom Middleware in ASP.NET Core 1.0


    原文: https://www.exceptionnotfound.net/writing-custom-middleware-in-asp-net-core-1-0/

    Middleware是ASP.NET Core 1.0的新特性。Middleware用来检测request和response的输入输出。

    什么是Middleware?

    Middleware是用来检测request和response的组件。Pipeline如下:

    Middleware可以用来替代HttpModules和HttpHandlers的工作。

    默认的Middleware

    使用VS创建的ASP.NET Core的应用,默认就使用了Middleware.

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
    
        if (env.IsDevelopment())
        {
            app.UseBrowserLink(); //Middleware
            app.UseDeveloperExceptionPage(); //Middleware
        }
        else
        {
            app.UseExceptionHandler("/Home/Error"); //Middleware
        }
    
        app.UseIISPlatformHandler(); //Middleware
    
        app.UseStaticFiles(); //Middleware
    
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });  //Middleware
    }
    

    在上面的方法中,那些app.UserX(),就意味着使用了ASP.NET默认的Middleware组件。

    自定义Middleware组件

    Middleware组件和其他的class基本一样, 不同的是Middleware有一个类型为RequestDelegate的私有属性,如下:

    public class AuthorizationMiddleware  
    {
        private readonly RequestDelegate _next;
    
        public AuthorizationMiddleware(RequestDelegate next)
        {
            _next = next;
        }
    }
    

    _next属性是一个委托,为Pipeline中下一个组件所用。 每个Middleware都实现一个async任务:

    public async Task Invoke(HttpContext context)  
    {
        await _next.Invoke(context);
    }
    

    Middleware任务

    下面我们新建一个Middleware用于检查HTTP头,如果HTTP头有"X-Not-Authorized",直接返回401。代码如下:

    public async Task Invoke(HttpContext context)  
    {
        if (context.Request.Headers.Keys.Contains("X-Not-Authorized"))
        {
            context.Response.StatusCode = 401; //Unauthorized
            return;
        }
    
        await _next.Invoke(context);
    }
    

    Middleware可以做许多事。例如:

    • 你想检查每一次request,如果request请求的是一个图片,将请求redirect的一个图片handler。
    • 你想有一个组件用来记录每一次http请求
    • ..........

    其他Middleware的例子

    定义一个RequestHeaderMiddleware

    public class RequestHeaderMiddleware  
    {
        private readonly RequestDelegate _next;
    
        public RequestHeaderMiddleware(RequestDelegate next)
        {
            _next = next;
        }
    
        public async Task Invoke(HttpContext context)
        {
            if (context.Request.Headers.Keys.Contains("X-Cancel-Request"))
            {
                context.Response.StatusCode = 500;
                return;
            }
    
            await _next.Invoke(context);
    
            if (context.Request.Headers.Keys.Contains("X-Transfer-By"))
            {
                context.Response.Headers.Add("X-Transfer-Success", "true");
            }
        }
    }
    

    这个Middleware可以做两件事情:

    • 如果HTTP请求头包含"X-Cancel-Request"那么服务器之间返回500
    • 如果HTTP请求头包含"X-Transfer-By"服务器给响应头加上"X-Transfer-Success"

    定义一个ProcessingTimeMiddleware

    public class ProcessingTimeMiddleware  
    {
        private readonly RequestDelegate _next;
    
        public ProcessingTimeMiddleware(RequestDelegate next)
        {
            _next = next;
        }
    
        public async Task Invoke(HttpContext context)
        {
            var watch = new Stopwatch();
            watch.Start();
    
            await _next(context);
    
            context.Response.Headers.Add("X-Processing-Time-Milliseconds", new[] { watch.ElapsedMilliseconds.ToString() });
        }
    }
    

    上面的Middleware用到了Stopwatch,这个组件记录请求响应的时间,并将其作为响应头返回给客户。

    添加Middeware到HTTP管道中

    有两种方法将Middleware注册到pipeline中。 一种是在Startup文件的Configure方法中调用IApplicationBuilderUseMiddleware方法:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
    {
        ...
        app.UseMiddleware<AuthorizationMiddleware>();
        ...
    }
    

    另一种是我推荐使用的方法,为每个你想注册的Middleware添加一个扩展方法,然后在Configure中调用。代码如下:

    public static class MiddlewareExtensions  
    {
        public static IApplicationBuilder UseRequestHeaderMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<RequestHeaderMiddleware>();
        }
    
        public static IApplicationBuilder UseAuthorizationMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<AuthorizationMiddleware>();
        }
    
        public static IApplicationBuilder UseProcessingTimeMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<ProcessingTimeMiddleware>();
        }
    }
    

    现在可以在Starup中使用这些扩展方法了(仔细读下面的代码,它包含一个Bug

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
    
        if (env.IsDevelopment())
        {
            app.UseBrowserLink();
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }
    
        app.UseIISPlatformHandler();
        app.UseStaticFiles();
        app.UseProcessingTimeMiddleware();
        app.UseRequestHeaderMiddleware();
        app.UseAuthorizationMiddleware();
    
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
    

    发现这个Bug了没?

    当你注册Middleware时,你添加Middleware的顺序非常重要。上面的代码中,我们首先添加了ProcessingTimeMiddleware, 然后添加RequestHeaderMiddleware,最后添加的是AuthorizationMiddleware。 这个顺序恰好搞反了。 正确的顺序如下:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
    {
        ...
        app.UseAuthorizationMiddleware();
        app.UseRequestHeaderMiddleware();
        app.UseProcessingTimeMiddleware();
        ...
    }
    

    总结

    记住下面3点:

    • Middleware能让我们完全控制Http管道
    • Middleware可以处理验证,重定向,HTTP头,甚至取消HTTP请求
    • 在Startup中注册Middleware的顺序非常重要

    本文源码-github

  • 相关阅读:
    2014年寒假学习规划
    二十进制数的加法--【英雄会】
    使用IBM SVC构建vSphere存储间集群
    游戏服务器学习笔记 2———— 准备工作
    php判断正常访问和外部访问
    游戏服务器学习笔记 3———— firefly 的代码结构,逻辑
    数学基础知识 ——(1)高等数学
    动态内存与智能指针
    Numpy(4)—— 保存和导入文件
    Numpy(3)—— 线性代数相关函数
  • 原文地址:https://www.cnblogs.com/irocker/p/writing-custom-middleware-in-asp-net-core.html
Copyright © 2020-2023  润新知