您的位置:首页 > 编程语言 > ASP

ASP.NET Core - 中间件与管道(1)

2016-08-04 19:52 537 查看
  今天来讨论一个ASP.NET Core 很重要概念管道和中间件,在ASP.NET Core中,针对HTTP请求采用pipeline也就是通常说的管道方式来处理,而管道容器内可以挂载很多中间件(处理逻辑)“串联”来处理HTTP请求,每一个中间件都有权决定是否需要执行下一个中间件,或者直接做出响应。这样的机制使得HTTP请求能够很好的被层层处理和控制,并且层次清晰处理起来甚是方便。 示意图如下:

  

/// <summary>
/// web宿主的入口类
/// </summary>
public class Startup
{
//加入服务项到容器, 这个方法将会被runtime调用
public void ConfigureServices(IServiceCollection services)
{

}

/// <summary>
/// Log环境下配置HTTP请求管道
/// </summary>
/// <param name="app"></param>
public void ConfigureLogHelp(IApplicationBuilder app){
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World - ConfigureLogHelp");
});
}

/// <summary>
/// 开发环境下配置HTTP请求管道
/// </summary>
/// <param name="app"></param>
public void ConfigureDevelopment(IApplicationBuilder app){
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World - ConfigureDevelopment");
});
}

/// <summary>
/// 默认情况下配置HTTP请求管道
/// </summary>
/// <param name="app">被用于构建应用程序的请求管道。只可以在 Startup 中的 Configure 方法里使用</param>
/// <param name="env">提供了访问应用程序属性,如环境变量</param>
/// <param name="loggerFactory">提供了创建日志的机制</param>
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{

//管道断路
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}


Startup.cs
  当ASPNETCORE_ENVIRONMENT = “Development

  


  当ASPNETCORE_ENVIRONMENT = “LogHelp”

  


  这样做的好处就是你可以写自己的测试配置而不会影响到其他人或者开发过程。当然环境的作用还在于前端应该引用什么样的CSS和JS,关于这些我们之后在MVC的章节再来讨论, 想了解的博友可以看官方文档

  管道配置与Startup

  说完环境配置和Startup的关系,我们回来接着聊管道的事情,现在我们来说说Configure{ENVIRONMENT}一下Configure简称这个方法。

  Configure这个方法是用于配置中间件到中管道容器(IApplicationBuilder),所以这个方法必须要包含一个IApplicationBuilder参数用来接受管道容器,方便开发者配置。当然他还可以接受其他的可选参数供开发者使用如下:

  (注:下图来源于ASP.NET Core中文文档

  


  需要提一下的是,刚刚我们上文中说的环境名在IHostingEnvironment中可以获取,对于预设值官方还做了判断封装,当然你可以重构它来封装自己的环境名判断。

  HTTP管道容器由三个扩展的方法来控制中间件的路由、挂载等等,分别是Run, Map, User

  a. Run方法会使得可以使管道短路,顾名思义就是终结管道向下执行不会调用next()委托,所以Run方法最好放在管道的最后来执行,如下面的代码:

/// <summary>
/// 开发环境下配置HTTP请求管道
/// </summary>
/// <param name="app"></param>
public void ConfigureDevelopment(IApplicationBuilder app){
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World - ConfigureDevelopment");
});

app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World - ConfigureDevelopment 不会被执行");
});

}


  执行结果:

  


  b. Use不会主动短路整个HTTP管道,但是也不会主动调用下一个中间件,必须自行调用await next.Invoke(); 如果不使用这个方法去调用下一个中间件那么Use此时的效果其实和Run是相同的,我们来看正常的代码:

/// <summary>
/// 开发环境下配置HTTP请求管道
/// </summary>
/// <param name="app"></param>
public void ConfigureDevelopment(IApplicationBuilder app){
var order ="";
app.Use(async (context, next) =>
{
order = $"{order}|Use start";
await next.Invoke();
order = $"{order}|Use end";
});

app.Run(async context =>
{
await context.Response.WriteAsync($"{order}|Run ext");
});

}


  执行结果如下:

  


  可以看到,Use end并没有被执行到,因为在调用下一个中间件时采用了Run,管道被终止了。

  再来看看如果不显式调用next.Invoke()时的代码:

/// <summary>
/// 开发环境下配置HTTP请求管道
/// </summary>
/// <param name="app"></param>
public void ConfigureDevelopment(IApplicationBuilder app){
var order ="";
app.Use(async (context, next) =>
{
order = $"{order}|Use start";
//去掉显示调用下一个中间件
//await next.Invoke();
order = $"{order}|Use end";
await context.Response.WriteAsync(order);
});

app.Run(async context =>
{
await context.Response.WriteAsync($"{order}|Run ext");
});

}


  其结果如下:

  


  可以发现Run这个中间件并没有被执行,而只是单纯的执行了Use这个中间件。所以说 在不显式调用下一个中间件的情况下,效果和Run时一样的会使管道短路。

  c. Map可以根据提供的URL来路由中间件,如下代码判断URL中访问"/test"时就会执行某个中间件逻辑:

/// <summary>
/// 开发环境下配置HTTP请求管道
/// </summary>
/// <param name="app"></param>
public void ConfigureDevelopment(IApplicationBuilder app){
app.Map("/test", HandleMapTest);//手工高亮
}

/// <summary>
/// maptest 处理方法
/// </summary>
public void HandleMapTest(IApplicationBuilder app){
app.Run(async (context) =>
{
await context.Response.WriteAsync("HandleMapTest Handler");
});

}


  结果如下:

  


  如果访问/test就会执行相应的中间件,反之则不会执行。

  MapWhen是Map的一个条件判断的扩展方法,可以通过它来判断某个条件适合的时候执行某一个中间件,如:当携带某一个参数名称时,执行某一个中间件或者反之,代码如下:

/// <summary>
/// 开发环境下配置HTTP请求管道
/// </summary>
/// <param name="app"></param>
public void ConfigureDevelopment(IApplicationBuilder app){
app.MapWhen(context => {
return context.Request.Query.ContainsKey("username");
}, HandleUserName);
app.Run(async context =>
{
await context.Response.WriteAsync("default ext");
});
}

/// <summary>
///
/// </summary>
public void HandleUserName(IApplicationBuilder app){
app.Run(async context =>
{
await context.Response.WriteAsync("UserName Map");
});
}


  结果如下:

  


  


  Map还可以进行嵌套路由中间件,这里不再描述,大家可以参看这里

  今天的管道介绍就写到这里,希望能对大家有帮助,如有不对望多加指正。

  

  

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: