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/

相关文章
相关标签/搜索