ASP.NET Core 運行原理剖析2:Startup 和 Middleware(中間件)

在上一節(文章連接)中提到ASP.NET Core WebApp 必須含有Startup類,在本節中將重點講解Startup類以及Middleware(中間件)在Startup類中的使用。html

Startup Class

Startup Class中含有兩個重要方法:Configure方法用於每次http請求的處理,好比後面要講的中間件(Middleware),就是在configure方法中配置。而ConfigureServices方法在Configure方法前調用,它是一個可選的方法,可在configureServices依賴注入接口或一些全局的框架,好比EntityFramework、MVC等。Startup 類的 執行順序:構造 -> configureServices->configuregit

一、Startup Constructor(構造函數)

主要實現一些配置的工做,方法參數以下:github

  • IHostingEnvironment: 用於訪問應用程序的特殊屬性,好比applicationName,applicationVersion。經過IHostingEnvironment對象下的屬性能夠在構造中實現配置工做。好比獲取當前根路徑找到配置json文件地址,而後ConfigurationBuilder初始化配置文件,最後能夠經過GetSection()方法獲取配置文件。代碼清單以下:
var builder = new ConfigurationBuilder()
                            .SetBasePath(env.ContentRootPath)
                             .AddJsonFile("appsettings.json");
                     var configuration = builder.Build();
                     var connStr = configuration.GetSection("Data:DefaultConnection:ConnectionString").Value;

根目錄下的配置文件以下:json

{
    "Data": {
        "DefaultConnection": {
            "ConnectionString": "Server=(localdb)\\MSSQLLocalDB;Database=_CHANGE_ME;Trusted_Connection=True;"
        }
    }
}
  • ILoggerFactory: 提供建立日誌的接口,能夠選用已經實現接口的類或自行實現此接口,下面代碼使用最簡單的控制檯做爲日誌輸出。
public Startup(IHostingEnvironment env, ILoggerFactory logger)
 {
         var log = logger.CreateLogger("default");
         logger.AddConsole();
         log.LogInformation("start configure");
 }

logger

二、ConfigureServices

主要實現了依賴注入(DI)的配置,方法參數以下:跨域

  • IServiceCollection:整個ASP.NET Core 默認帶有依賴注入(DI),IServiceCollection是依賴注入的容器,首先建立一個類(Foo)和接口(IFoo),代碼清單以下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WebApplication1
{
   public interface IFoo
    {
        string GetFoo();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WebApplication1
{
    public class Foo : IFoo
    {
        public string GetFoo()
        {
            return "foo";
        }
    }
}

在ConfigureServices 中將接口和實現注入至容器mvc

public void ConfigureServices(IServiceCollection services)
       {
           services.AddTransient<IFoo, Foo>();
       }

若是想在每次Http請求後都使用IFoo的GetFoo()方法來處理,上面講到能夠在Configure方法中註冊函數,在註冊過程當中因爲使用了依賴注入(DI),所以能夠直接經過RequestServices.GetRequiredService<IFoo>()泛型方法將IFoo對象在容器中取出。app

app.Run((context) =>
           {
               var str = context.RequestServices.GetRequiredService<IFoo>().GetFoo();
               return context.Response.WriteAsync(str);
           });

除了本身的接口外,還支持經過擴展方法添加更多的注入方法,好比EntityFramework、mvc框架都實現本身的添加方法。框架

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddMvc();

    // Add application services.
     services.AddTransient<IFoo, Foo>();

}

三、Configure方法

主要是http處理管道配置和一些系統配置,參數以下:asp.net

  • IApplicationBuilder: 用於構建應用請求管道。經過IApplicationBuilder下的run方法傳入管道處理方法。這是最經常使用方法,對於一個真實環境的應用基本上都須要好比權限驗證、跨域、異常處理等。下面代碼調用IApplicationBuilder.Run方法註冊處理函數。攔截每一個http請求,輸出Hello World。
public void Configure(IApplicationBuilder app)
{
    app.Run((context) => context.Response.WriteAsync("Hello World!"));
}
  • IHostingEnvironment: 同構造參數ide

  • ILoggerFactory: 同構造參數

Middleware

中間件是一個處理http請求和響應的組件,多箇中間件構成了處理管道(Handler pipeline),每一箇中間件能夠決定是否傳遞至管道中的下一中間件。一旦註冊中間件後,每次請求和響應均會被調用。

調用示意

一、中間件註冊

中間件的註冊在startup中的Configure方法完成,在configure方法中使用IApplicationBuilder對象的Run、Map、Use方法傳入匿名委託(delegate)。上文示例註冊IFoo.GetFoo()方法就是一個典型的中間件。

  • Run & Use: 添加一箇中間件至請求管道。它們在功能很相似可是也存在一些區別,先來看下兩個方法的定義。
public static IApplicationBuilder Use(this IApplicationBuilder app, Func<HttpContext, Func<Task>, Task> middleware);

 public static void Run(this IApplicationBuilder app, RequestDelegate handler);

Run是經過擴展方法語法來定義,傳入入參是RequestDelegate的委託,執行完一個第一個run後是不會激活管道中的第二個run方法,這樣代碼執行結果只會輸出一個「hello world!」

app.Run((context) => context.Response.WriteAsync("Hello World!"));

app.Run((context) => context.Response.WriteAsync("Hello World 1!"));

run

而use方法的入參則是Func<>的委託包含兩個入參和一個返回值,這樣在第一個函數執行完成後能夠選擇是否繼續執行後續管道中的中間件仍是中斷。

app.Use((context, next) =>
                     {
                             context.Response.WriteAsync("ok");
                             return next();
                     });
app.Use((context, next) =>
                     {
                             return context.Response.WriteAsync("ok");
                     });

Use

  • Map: 含有兩個參數pathMatche和configuration,經過請求的url地址匹配相應的configuration。例如能夠將url路徑是/admin的處理函數指定爲以下代碼:
app.Map("/admin", builder =>
                    {
                            builder.Use((context, next) => context.Response.WriteAsync("admin"));
                    });

二、經常使用中間件

Middleware 功能描述
Authentication 提供權限支持
CORS 跨域的配置
Routing 配置http請求路由
Session 管理用戶會話
Static Files 提供對靜態文件的瀏覽

這裏有一些官方的示例,連接


做者:帥蟲哥 出處: http://www.cnblogs.com/vipyoumay/p/5640645.html

參考連接

[1] https://docs.asp.net/en/latest/fundamentals/middleware.html

[2] http://www.talkingdotnet.com/app-use-vs-app-run-asp-net-core-middleware/

相關文章
相關標籤/搜索