ASP.NET MVC入门-Startup 类:注册服务和使用中间件

时间:2022-09-04 13:37:44

笔记内容来源于微软 MVP 杨旭老师 solenovex 的视频

Startup 类:注册服务和使用中间件

Startup类默认生成了两个方法,在这个类中主要负责注册服务和使用中间件。

让我们先来看一下Startup类的源码

Startup类的源码

在下面的源码中有ConfigureServices和Configure两个方法。

public void ConfigureServices(IServiceCollection services){}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World!");
    });
}

 

1.ConfigureServices方法

ConfigureServices方法是用来注册服务的,Configure方法是用来使用中间件的。

注册服务就是依赖注入,向Ioc容器中注入类型的对象,注入后就可以直接使用该类型注入实例,而无需再次实例化,减少了代码的耦合。

具体内容可以自行百度依赖注入/控制反转。

2.Configure方法

Configure方法配置了Http请求处理的管道,每个Http请求到达之后,会按照Configure方法中的组件来决定如何处理这些请求。

其中的app.Run方法以及匿名函数,就是不管什么请求到达这里,都会返回 context.Response.WriteAsync("Hello World!") 响应。

注册服务演示

我们先创建一个IWelcomeService接口以及实现该接口的WelcomeService类

public interface IWelcomeService
{
    string GetMessage();
}
public class WelcomeService : IWelcomeService
{
    public string GetMessage()
    {
        return "Hello from IWelcomeService";
    }
}

 

然后在Startup类Configure方法中使用该接口类型对象,调用接口的GetMessage方法输出

事实上,运行后我们会发现直接使用是不行的,因为该类型刚还有在ConfigureServices方法中注册。

下面我们就在ConfigureServices方法中注册接口和实现类。

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IWelcomeService, WelcomeService>();
}

 

运行后的结果

Hello from IWelcomeService

注册服务的几种形式

注册服务时,我们使用的是AddSingleton方法,这是以单例的形式依赖注入对象,单例就是指该类型只有一个实例,具体含义和用法可以自行百度。

还有其他几种形式,如AddTransient方法,每次请求都会生成一个实例,AddScoped方法,每次Http请求都会生成一个实例。

管道和中间件

Configure方法配置了Http请求处理的管道。

假设有个Http请求到达了我们的Web应用,有一个POST请求,那么我们的Web应用就需要处理这个请求。中间件就是负责处理请求的,他将决定如何处理这些请求。

中间件其实就是个对象,每个中间件的角色和功能都不一样,并且局限在特定的领域内。每个中间件都很小,Web应用会用到很多中间件。

一个简单的中间件管道示例

假设一个POST请求Product,首先通过Logger中间件,Logger可以查看到很多的信息,记录下请求的信息,也可以拒绝请求。

然后转送到下个中间件,比如授权中间件。授权中间件会先找一个特定的cookie的值或者token,如果找到了就转发到下一个中间件。

下一个中间件可以是路由中间件。首先查看请求的URL,然后找到可以响应该请求的方法,就可以返回一个JSON/HTML,然后原路返回。

ASP.NET MVC入门-Startup 类:注册服务和使用中间件

Startup类被调用的逻辑

搞清了Startup类中的方法的作用和能做什么后,我们来看一看Startup类是如何被调用的。

上一篇博文提到了Program类的CreateWebHostBuilder方法中调用了  UseStartup<Startup>() ,就是这个方法制定了Startup类为启动类,实例化Starup类得到实例,并调用类中的两个方法。

首先会调用ConfigureServices方法,注册服务。除了预先注册好的服务,自己写的类和一些没注册内置类都需要在该方法中注册。

然后调用Configure方法,该方法只会调用一次。在该方法中,我们使用实现了IApplicationBuilder接口的类型的对象,来配置中间件。

中间件的Use方法

默认的Run方法并不建议使用,项目中常常使用Use方法。除此之外还有内置的很多USeXxx方法。如UseWelcomePage方法就会调用欢迎页。这些方法的参数往往可以传递一个对象来对其进行配置。

还有直接使用Use方法更底层,其参数是一个Func<ReuquestDelegate,ReuquestDelegate>,Func的参数是ReuquestDelegate,

其返回类型也是ReuquestDelegate。ReuquestDelegate类型就是一段可执行的代码,例如下方代码,返回了一个异步Task,Task返回了httpContext对象。

app.Use(next => 
{
    return async httpContext =>
    {
        if (httpContext.Request.Path.StartsWithSegments("/first"))
        {
            await httpContext.Response.WriteAsync("First!");
        }
        else
        {
            await next(httpContext);
        }
    };
});

异常页面的中间件

下方代码首先判断当前环境是不是开发环境,如果是,当出现错误时就会使用开发者异常页面中间件。

因为开发者需要详细的错误信息,但是这些信息不能直接暴露,否则会被黑客轻易利用,因此只能在开发者环境下才需要调用开发者异常页面中间件。

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

判断环境和自定义环境

前面讲到可以判断运行环境,事实上环境是可以自定义的,