詳解Asp.net 5中的ApplicationBuilder
ApplicationBuilder(IApplicationBuilder接口),是OWIN的基礎(chǔ),而且里面都是代理、代理的代理,各種lambda表達(dá)式,估計(jì)要看這部分代碼,很多人得頭昏腦漲。今天就對(duì)個(gè)類以及幾個(gè)擴(kuò)展方法進(jìn)行講解。
按慣例先貼代碼(這是我修改后的,將接口繼承去掉了、HttpContext類修改成自己的MyHttpContext類)
public class ApplicationBuilder
{
private readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();
public ApplicationBuilder() { }
private ApplicationBuilder(ApplicationBuilder builder)
{
}
public ApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
{
_components.Add(middleware);
return this;
}
public ApplicationBuilder New()
{
return new ApplicationBuilder(this);
}
public RequestDelegate Build()
{
RequestDelegate app = context =>
{
context.StatusCode = "404";
System.Console.WriteLine("404");
return Task.FromResult(0);
};
foreach (var component in _components.Reverse())
{
app = component(app);
}
return app;
}
}RequestDelegate的定義如下:
public delegate Task RequestDelegate(MyHttpContext context);
從ApplicationBuilder的源代碼中我們可以關(guān)注3個(gè)點(diǎn):_components、Use方法、Build方法。
- _components是也一個(gè)列表(IList)對(duì)象,不過里面類型有點(diǎn)特殊——是以代理RequestDelegate為參數(shù)、代理RequestDelegate為返回值的一個(gè)代理。這里用代理說有點(diǎn)別嘴,可以把代理叫做函數(shù),就是里面的類型是一個(gè)函數(shù),這個(gè)函數(shù)的參數(shù)也是函數(shù),返回值也是函數(shù)。
- Use方法,就是在上面的列表對(duì)象后面添加一條新記錄。
- Build方法就是將_components數(shù)組按照反向順序,制作成一個(gè)鏈?zhǔn)浇Y(jié)構(gòu)(有點(diǎn)類似鏈表的感覺)。下面用倆幅圖說明下:
Build之前

Build之后

我們還可以從代碼中看到Item1的參數(shù)給的是“404”,而返回結(jié)果是RequestDelegate類型。也就是說這個(gè)返回類似于voidRequestDelegate(MyHttpContext context)。如果系統(tǒng)給我們一個(gè)context變量,那么這個(gè)管道就可以從頭到尾的跑下去了。而事實(shí)上在Asp.net5中,這個(gè)管道就是用于替代傳統(tǒng)的IHttpModule的(可能不準(zhǔn)確),那現(xiàn)在問題就來了,Item1的參數(shù)是這個(gè)管道的第一環(huán)還是最后一環(huán)呢?從圖形來看應(yīng)該是第一環(huán),但是事實(shí)上這是一個(gè)誤解。因?yàn)榧^兩面一個(gè)是參數(shù),一個(gè)是執(zhí)行體(參數(shù)是一個(gè)方法,會(huì)在執(zhí)行體內(nèi)調(diào)用執(zhí)行)。在執(zhí)行體內(nèi),可能在開始就執(zhí)行參數(shù)的內(nèi)容,之后執(zhí)行具體的內(nèi)容;也可以是先執(zhí)行具體內(nèi)容,之后執(zhí)行參數(shù),最后在執(zhí)行一部分具體內(nèi)容;還可以先執(zhí)行具體內(nèi)容,之后參數(shù);還可能無視參數(shù),直接直接自己的內(nèi)容,那么之前的參數(shù)就會(huì)被忽略。也就是說無所謂順序,404可能是管道的第一環(huán),也可能是最后一環(huán),也可能是中間環(huán)節(jié),還可能壓根就不執(zhí)行。這個(gè)和Item1、Item2等內(nèi)容具體的寫法有關(guān)系。(雖然也是鏈?zhǔn)浇Y(jié)構(gòu)是不是和鏈表感覺不一樣)
是不是感覺太零活了,源碼還對(duì)ApplicationBuilder做了倆個(gè)擴(kuò)展方法,代碼整理如下:
public static class RunExtensions
{
public static ApplicationBuilder Use(this ApplicationBuilder app, Func<MyHttpContext, Func<Task>, Task> middleware)
{
return app.Use(next =>
{
return context =>
{
Func<Task> simpleNext = () => next(context);
return middleware(context, simpleNext);
};
});
}
public static void Run(this ApplicationBuilder app, RequestDelegate handler)
{
if (app == null)
{
throw new ArgumentNullException("why?");
}
if (handler == null)
{
throw new ArgumentNullException("How?");
}
app.Use(_ => handler);
}
}首先說Use方法,改方法是對(duì)之前Use方法的一個(gè)更改。將傳入的參數(shù)更改為Func<MyHttpContext, Func<Task>, Task>。這樣做有什么好處?之前的Func<RequestDelegate, RequestDelegate>對(duì)象并不能給人清楚的明了的感覺,而Func<MyHttpContext, Func<Task>, Task>就非常明確了。傳入的參數(shù):MyHttpContext就是Context對(duì)象,F(xiàn)unc<Task>就是next的執(zhí)行體。返回值是一個(gè)Task(類似于void)。一目了然。
再說Run方法,顯而易見,Run方法只執(zhí)行自己的內(nèi)容,并沒有執(zhí)行參數(shù)體。所以鏈?zhǔn)浇Y(jié)構(gòu)的在其前的都會(huì)被舍棄,不會(huì)被執(zhí)行。
最后把自己的測(cè)試?yán)淤N出來,供大家參考
示例1:
static void Main(string[] args)
{
MyHttpContext context = new MyHttpContext() { StatusCode = "A" };
Func<MyHttpContext, Func<Task>, Task> middleware =
(x, y) => { context.StatusCode += "C"; System.Console.WriteLine(context.StatusCode); return y(); };
Func<MyHttpContext, Func<Task>, Task> middleware2 =
(x, y) => { context.StatusCode += "End1"; System.Console.WriteLine(context.StatusCode); return Task.FromResult(0); };
ApplicationBuilder builder = new ApplicationBuilder();
builder.Use(
next =>
{
return (MyHttpContext o) =>
{
o.StatusCode += "B";
System.Console.WriteLine(context.StatusCode);
next(o);
return Task.FromResult(0);
};
}
);
builder.Use(middleware);
//builder.Use(middleware2);
//builder.Use(middleware);
//builder.Run(o => { o.StatusCode += "End2"; return Task.FromResult(0); });
builder.Build().Invoke(context);
System.Console.ReadLine();
}執(zhí)行結(jié)果:

示例2:
static void Main(string[] args)
{
MyHttpContext context = new MyHttpContext() { StatusCode = "A" };
Func<MyHttpContext, Func<Task>, Task> middleware =
(x, y) => { context.StatusCode += "C"; System.Console.WriteLine(context.StatusCode); return y(); };
Func<MyHttpContext, Func<Task>, Task> middleware2 =
(x, y) => { context.StatusCode += "End1"; System.Console.WriteLine(context.StatusCode); return Task.FromResult(0); };
ApplicationBuilder builder = new ApplicationBuilder();
builder.Use(
next =>
{
return (MyHttpContext o) =>
{
o.StatusCode += "B";
System.Console.WriteLine(context.StatusCode);
next(o);
return Task.FromResult(0);
};
}
);
builder.Use(middleware);
builder.Use(middleware2);
//builder.Use(middleware);
//builder.Run(o => { o.StatusCode += "End2"; System.Console.WriteLine(context.StatusCode); return Task.FromResult(0); });
builder.Build().Invoke(context);
System.Console.ReadLine();
}執(zhí)行結(jié)果:

示例3:
static void Main(string[] args)
{
MyHttpContext context = new MyHttpContext() { StatusCode = "A" };
Func<MyHttpContext, Func<Task>, Task> middleware =
(x, y) => { context.StatusCode += "C"; System.Console.WriteLine(context.StatusCode); return y(); };
Func<MyHttpContext, Func<Task>, Task> middleware2 =
(x, y) => { context.StatusCode += "End1"; System.Console.WriteLine(context.StatusCode); return Task.FromResult(0); };
ApplicationBuilder builder = new ApplicationBuilder();
builder.Use(
next =>
{
return (MyHttpContext o) =>
{
o.StatusCode += "B";
System.Console.WriteLine(context.StatusCode);
next(o);
return Task.FromResult(0);
};
}
);
builder.Use(middleware);
//builder.Use(middleware2);
//builder.Use(middleware);
builder.Run(o => { o.StatusCode += "End2"; System.Console.WriteLine(context.StatusCode); return Task.FromResult(0); });
builder.Build().Invoke(context);
System.Console.ReadLine();
}執(zhí)行結(jié)果:

到此這篇關(guān)于詳解Asp.net 5中的ApplicationBuilder的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
ASP.NET?Core托管模型CreateDefaultBuilder()方法
這篇文章介紹了ASP.NET?Core托管模型CreateDefaultBuilder()方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-02-02
Linux下使用Jenkins自動(dòng)化構(gòu)建.NET?Core應(yīng)用
這篇文章介紹了Linux下使用Jenkins自動(dòng)化構(gòu)建.NET?Core應(yīng)用的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
ASP.NET Core MVC中的控制器(Controller)介紹
這篇文章介紹了ASP.NET Core MVC中的控制器(Controller),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04

