• 理解ASP.NET 5的中间件


    今天推荐的这篇文章,讲述了如何实现和使用ASP.NET 5的中间件。

    虽然在ASP.NET 5中,微软没有再强调OWIN(Open Web Interface for .NET)及其微软官方的OWIN实现Katana,但是其中涉及到一些原则和设计思想依然被ASP.NET 5以自己的方式所承载下来。比如,解耦服务器和应用程序的关系,应用程序委托,环境状态这些特性都能在ASP.NET 5中找到,且进行了更多加强。

    那么什么是“中间件”呢?OWIN的规范中如此定义:“中间件即是在服务器和应用程序之间的管道传入的一些组件,为了特定目的监测、路由或编辑请求和回应消息。”这样的定义对于ASP.NET 5同样适用,或者可以被认为就是传统ASP.NET中的HTTP模块和处理器。某些中间件会完成一些中间任务,比如处理请求的验证、会话状态获取和持久保持、日志记录诸如此类;有一些中间件会最终生成回应消息。

    要编写ASP.NET 5的中间件,有一种非常简单的方式,一段Lambda表达式就可以搞定:

    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
            app.Run(async context =>
            {
                context.Response.ContentType = "text/plain";
                await context.Response.WriteAsync("Hello ASP.NET 5!");
            });
        }
    }

    在上述代码中,传递给IApplicationBuilder.Run方法的是一个委托:RequestDelegate,其定义如下:

    public delegate Task RequestDelegate(HttpContext context);

    RequestDelegate等效于OWIN中的AppFunc。其接受状态信息HttpContext作为输入参数,返回一个Task。注意,此HttpContext非SystemWeb中的HttpContext,这是封装请求处理状态且对服务器透明(不特定于某种服务器)的上下文状态对象。而返回Task可以让调用者能够等待你的中间件完成工作后才进行后续任务执行。Run方法还有多个重载,以便让你注入相关依赖。

    RequestDelegate同样也可以用于把中间件串接到执行管道中:

    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
            app.Use(next => async context =>
            {
                // do your stuff here before calling the next middleware 
                // in the pipeline
                 
                await next.Invoke(context); // call the next guy
     
                // do some more stuff here as the call is unwinding
            });
     
            app.Run(async context =>
            {
                context.Response.ContentType = "text/plain";
                await context.Response.WriteAsync("Hello ASP.NET 5!");
            });
        }
    }

    通过使用IApplicationBuilder.Use方法就可以把自己的中间件代码串到其他中间件的前面。其中next这个参数,就是下一个中间件的实例。其方法定义如下:

    IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate

    上面是用Lambda表达式来实现中间件,不过在实际开发当中涉及的代码都比较庞杂,所以最好是放到一个单独的类当中,并提供相应的测试代码。这样你可以单独编译打包分发这个中间件。文章作者Andrei Dzimchuk以实现HTTP Basic验证的一个简单中间件为例给出了如下代码:

    public class BasicAuthentication
    {
        private readonly RequestDelegate next;
     
        public BasicAuthentication(RequestDelegate next)
        {
            this.next = next;
        }
     
        public async Task Invoke(HttpContext context, 
                                 IAuthenticationService authenticationService)
        {
            try
            {
                var parser = new BasicAuthenticationParser(context);
                var username = parser.GetUsername();
                var password = parser.GetPassword();
     
                await authenticationService.AuthenticateAsync(username, password);
                await next(context);
            }
            catch (InvalidCredentialsException)
            {
                context.Response.StatusCode = 401;
                context.Response.Headers.Add("WWW-Authenticate", 
                    new[] { "Basic" });
            }
        }
    }
    

    这个类非常有意思。首先让我们非常奇怪的是,它没有继承任何基类或者实现任何接口。由此可知,微软开始在ASP.NET 5中推崇“约定胜于接口”的思想。我们只要实现一个接受RequestDelegate为参数的构造器,和一个方法签名同RequestDelegate一致的Invoke方法。当然本例中Invoke还接受了另外一个参数,这就是第二个奇怪的地方,我们能够在中间件里直接使用依赖注入。本例中就是注入了一个IAuthenticationService。

    要使用编写好的中间件也是非常简单。首先引用一个依赖包“Microsoft.AspNet.RequestContainer ”,然后就可以使用Microsoft.AspNet.Http.Extensions的扩展方法IApplicationBuilder.UseMiddleware来加载中间件,如下:

    builder.UseMiddleware<BasicAuthentication>();

    通常,我们会把单独编写一个扩展类,来提供一个语义根据明确的扩展方法。最终Startup文件就可以编写为:

    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
            app.UseBasicAuthentication();
     
            app.Run(async context =>
            {
                context.Response.ContentType = "text/plain";
                await context.Response.WriteAsync("Hello ASP.NET 5!");
            });
        }
    }
    

    到此,我们就完成了中间件的编写和使用。当然还需要完成注册IAuthenticationService这样的代码,这个就涉及到ASP.NET 5的依赖注入特性,有机会下次介绍。

    原文地址在:http://dzimchuk.net/post/Understanding-ASPNET-5-middleware

  • 相关阅读:
    hdu 1532 网络最大流
    POJ 2407 素数筛
    hdoj 4081 次小生成树
    hdoj 1251 统计难题
    hdoj 1176 免费馅饼
    ouc oj 1066 青蛙过河
    POJ 2533 Longest Ordered Subsequence(单调递增子序列)
    POJ 1159 Palindrome(回文字符串)
    POJ-1458 Common Subsequence (最长公共子序列)
    POJ-2593 Max Sequence(不连续的最大子段和)
  • 原文地址:https://www.cnblogs.com/redmoon/p/4418349.html
Copyright © 2020-2023  润新知