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


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

Startup Class

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

1、Startup Constructor(構造函數)

主要實現一些配置的工作,方法參數如下:

  • 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;

根目錄下的配置文件如下:


{
	"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

2、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 中將接口和實現注入至容器

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

如果想在每次Http請求后都使用IFoo的GetFoo()方法來處理,上面講到可以在Configure方法中注冊函數,在注冊過程中由於使用了依賴注入(DI),因此可以直接通過RequestServices.GetRequiredService<IFoo>()泛型方法將IFoo對象在容器中取出。


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>();

}

3、Configure方法

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

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

  • ILoggerFactory: 同構造參數

Middleware

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

調用示意

1、中間件注冊

中間件的注冊在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"));
					});

2、常用中間件

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/


免責聲明!

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



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