专栏首页Vincent-yuanasp.net core 系列之Startup

asp.net core 系列之Startup

这篇文章简单记录 ASP.NET Core中 ,startup类的一些使用。

一.前言

在 Startup类中,一般有两个方法:

  • ConfigureServices 方法: 用来配置应用的 service 。
  • Configure 方法:创建应用的请求处理管道

它们都在应用启动时,被ASP.NET Core runtime 调用:

public class Startup
{
    // Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        ...
    }

    // Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app)
    {
        ...
    }
}

当应用的 host 被built(建立)时,Startup类被指定到应用中。

而在 Program 中,当 host builder 上的 Build 被调用时,应用的 host 被 built 。

而Startup类是通过调用WebHostBuilderExtensions.UseStartup<TStartup>方法指定的。

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run(); //Build方法被调用时,应用的host被建立,同时Startup被指定到应用中
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

在startup类中,一种依赖注入的常见用法:

public class Startup
{
    private readonly IHostingEnvironment _env;
    private readonly IConfiguration _config;
    private readonly ILoggerFactory _loggerFactory;

    public Startup(IHostingEnvironment env, IConfiguration config, 
        ILoggerFactory loggerFactory)
    {
        _env = env;
        _config = config;
        _loggerFactory = loggerFactory;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        var logger = _loggerFactory.CreateLogger<Startup>();

        if (_env.IsDevelopment())
        {
            // Development service configuration

            logger.LogInformation("Development environment");
        }
        else
        {
            // Non-development service configuration
            logger.LogInformation($"Environment: {_env.EnvironmentName}");
        }

        // Configuration is available during startup.
        // Examples:
        //   _config["key"]
        //   _config["subsection:suboption1"]
    }
}

注入IHostingEnvironment , 当定义不同环境的Startup (例如,StartupDevelopment 等),在运行时,选择合适的Startup。

二.ConfigureServices方法

它有三个特点:

  • 可选的
  • 在调用Configure方法之前调用 ConfigureServices
  • Configuration options 按约定设置

1. 比较典型的是调用 Add{Service} 和 services.Configure{Service} 。例如:Configure Identity services.

2. host 可能会 在Startup方法被调用之前,配置一些服务。 例如: The host.

在startup被调用之前,CreateDefaultBuilder方法配置了一个host 。

3. Add{Service}是IServiceCollection的扩展方法,下面是一些使用:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDefaultIdentity<IdentityUser>()
        .AddDefaultUI(UIFramework.Bootstrap4)
        .AddEntityFrameworkStores<ApplicationDbContext>();


    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    // Add application services. 添加应用的服务
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddTransient<ISmsSender, AuthMessageSender>();
}

添加 services 到 service container 使它们在应用和Configure方法中可用。services方法可以通过 dependency injection 或 ApplicationServices 解析。

三.The Configure method

Configure方法用来指定应用怎样 处理HTTP request。请求管道(request pipeline)通过添加中间组件到IApplicationBuilder实例中来配置。

ASP.NET Core 模板 配置的管道:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();

    app.UseMvc();
}

使用Use扩展方法添加一个或多个中间组件到请求管道。例如,UseMvc扩展方法添加 Routing Middleware 到请求管道 并且配置MVC 作为一个默认的处理器。

四.Convenience methods

不使用Startup类配置services和request processing pipeline。在host builder 上调用ConfigureServices和Configure的简便方法。如果存在多个ConfigureServices的调用,会依次添加。如果存在多个Configure方法的调用,最后一个Configure的调用会被使用。

public class Program
{
    public static IHostingEnvironment HostingEnvironment { get; set; }
    public static IConfiguration Configuration { get; set; }

    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
            })
            .ConfigureServices(services =>
            {
                ...
            })
            .Configure(app =>
            {
                var loggerFactory = app.ApplicationServices
                    .GetRequiredService<ILoggerFactory>();
                var logger = loggerFactory.CreateLogger<Program>();
                var env = app.ApplicationServices.GetRequiredServices<IHostingEnvironment>();
                var config = app.ApplicationServices.GetRequiredServices<IConfiguration>();

                logger.LogInformation("Logged in Configure");

                if (env.IsDevelopment())
                {
                    ...
                }
                else
                {
                    ...
                }

                var configValue = config["subsection:suboption1"];

                ...
            });
}

五.Extend Startup with startup filters (使用startup filter扩展 Startup)

使用 IStartupFilter ,在应用的Configure 中间件管道的开头或末尾配置中间件。

IStartupFilter 实现Configure方法,它会接收和返回一个Action<IApplicationBuilder>。而IApplicationBuilder定义了一个类来配置一个应用的请求管道。

这些filters会按照添加到services container的顺序被调用。

下面是一个例子:

RequestSetOptionsMiddleware

public class RequestSetOptionsMiddleware
{
    private readonly RequestDelegate _next;
    private IOptions<AppOptions> _injectedOptions;

    public RequestSetOptionsMiddleware(
        RequestDelegate next, IOptions<AppOptions> injectedOptions)
    {
        _next = next;
        _injectedOptions = injectedOptions;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        Console.WriteLine("RequestSetOptionsMiddleware.Invoke");

        var option = httpContext.Request.Query["option"]; //取请求中的option参数

        if (!string.IsNullOrWhiteSpace(option))
        {
            _injectedOptions.Value.Option = WebUtility.HtmlEncode(option);
        }

        await _next(httpContext);
    }
}

RequestSetOptionsMiddleware 中间件被配置在 RequestSetOptionsStartupFilter 类中:

public class RequestSetOptionsStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder =>
        {
            builder.UseMiddleware<RequestSetOptionsMiddleware>();
            next(builder);
        };
    }
}

IStartupFilter 在 ConfigureServices中被注册到 service container, 并且从Startup类的外部增强Startup:

WebHost.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddTransient<IStartupFilter, 
            RequestSetOptionsStartupFilter>();
    })
    .UseStartup<Startup>()
    .Build();

当option的查询字符串存在时,中间件会在MVC中间件之前处理这个值

中间件的执行顺序是按照IStartupFilter的注册顺序

六. 补充

这里晚上补充下 ApplicationServices 解析services的使用

IApplicationBuilder app

app.ApplicationServices.GetService 方法

如上,IApplicationBuilder类型,即可得到ApplicationServices,然后利用其方法来解析services

参考网址:

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/startup?view=aspnetcore-2.2

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • dotnet core 之 CORS使用示例

    这种比较常见,即在ConfigureServices中添加中间件及定义其策略;而在Configure中把中间件设置到管道中

    Vincent-yuan
  • c#之添加window服务(定时任务)

    3.在下图安装程序 serviceInstaller1 上右键,修改serviceName和Description

    Vincent-yuan
  • 三角形

    输入三角形 3 条边的长度值 (均为正整数),判断能否为直角三角形的 3 个边长。

    Vincent-yuan
  • (项目)在线教育平台(十一)

      首页的全局搜索功能可以对课程,机构,教师进行全局搜索,搜索的代码放在deco-common.js文件中:

    py3study
  • Rxjava2-小白入门(二)

    上篇文章我们主要讲解了观察者模式。那么这节课我们主要讲解Rxjava2的基本使用和操作符。其实网上的关于Rxjava2的优秀文章有很多对我来说都是受益匪浅。可能...

    g小志
  • Go语言基础1 - 代码风格和代码格式化

    格式化问题总是充满了争议,但却始终没有形成统一的定论。在Go中我们另辟蹊径,让机器来处理大部分的格式化问题。 gofmt 程序(也可用 go fmt,它以包为...

    zhangyunfeiVir
  • BootStrap-table的使用实现排序功能

    Dream城堡
  • 【黄仁勋苏州GTC演讲】摩尔定律已终结,计算的未来离不开GPU

    2018年一度被传要“泡汤”的最后一场GTC,今天如期在苏州举行,现场气氛火爆,参与人数可能又创下了历史新高。

    新智元
  • 为什么Android应该转为Go语言开发?

    我能肯定大家最近都了解到了关于Oracle(甲骨文)正在向Google索要Java的专利费,因为他们认为Google开发的Android移动操作系统使用了他们的...

    李海彬
  • 思必驰十年创业,(现在)是一家怎样的公司?

    自AlphaGo以来,AI之风强劲有力,成就不少公司,也让更多技术大牛从幕后被推至台前,甚至还给老城市带来新名片。

    量子位

扫码关注云+社区

领取腾讯云代金券