理解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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM