【.NET Core框架】初始化(Startup、IStartupFilter、IHostingStartup)

Startup

Startup类承担应用的启动任务,所以按照约定,起名为Startup,不过你可以修改为任意类名(强烈建议类名为Startup)。
默认的Startup结构很简单,包含:

  • ConfigureServices方法:注册服务
  • Configure方法:注册中间件

省略Startup

Startup类也可以省略,直接进行如下配置即可(虽然可以这样做,但是不推荐):

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            // ConfigureServices 可以调用多次,最终会将结果聚合
            webBuilder.ConfigureServices(services =>
            {
            })
            // Configure 如果调用多次,则只有最后一次生效
            .Configure(app =>
            {
                var env = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();
            });
        });

IStartupFilter

有时,我们想要将一系列相关中间件的注册封装到一起,那么我们通过实现IStartupFilter,并在Startup.ConfigureServices中配置IStartupFilter的依赖注入即可。
在IStartupFilter中配置的中间件,总是比Startup类中Configure方法中的中间件先注册;对于多个IStartupFilter实现,执行顺序与服务注册时的顺序一致

public interface IStartupFilter
{
    Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next);
}

它只有一个Configure方法,是对 Starup 类中Configure方法的拦截器,给我们一个在Configure方法执行之前进行一些配置的机会

public class FooStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return app => {
            app.UseMiddleware<FooMiddleware>();
            next(app);
        };
    }
}

IHostingStartup

在ASP.NET Core中我们可以使用一种机制来增强启动时的操作,它就是HostingStartup。如何叫"增强"操作,相信了解过AOP概念的同学应该都非常的熟悉。我们常说AOP使用了关注点分离的方式,增强了对现有逻辑的操作。而我们今天要说的HostingStartup就是为了"增强"启动操作,这种"增强"的操作甚至可以对现有的程序可以做到无改动的操作。例如,外部程序集可通过HostingStartup实现为应用提供配置服务、注册服务或中间件管道操作等。
一个项目中只能一个Sartup,因为如果配置多个,则最后一个会覆盖之前的。而在一个多层项目中,Sartup类一般是放在展现层中,我们在其它层也需要注册一些服务或者配置请求管道时,通常会写一个扩展方法:

public static class EfRepositoryExtensions
{
    public static void AddEF(this IServiceCollection services,string connectionStringName) { }
    public static void UseEF(IApplicationBuilder app) { }
}

然后在Startup中调用这些扩展方法,除了这种方式我们还可以使用IHostingStartup来实现

[assembly: HostingStartup(typeof(Zero.EntityFramework.EFRepositoryStartup))]
namespace Zero.EntityFramework
{
    public class EFRepositoryStartup : IHostingStartup
    {
        public void Configure(IWebHostBuilder builder)
        {
            builder.ConfigureServices(services =>
            {
                services.AddDbContext<AppDbContext>(options =>
                    options.UseSqlServer(connectionStringName), opt => opt.EnableRetryOnFailure())
                );

                services.TryAddScoped<IDbContext, AppDbContext>();
                services.TryAddScoped(typeof(IRepository<,>), typeof(EfRepository<,>));
            }); 

            builder.Configure(app => {
                app.UseIdentity();
            });
        }
    }
}

如上,只需实现 IHostingStartup 接口,要清爽简单的多,不过,还需要进行注册才会被WebHost执行。
首先添加EFRepositoryStartup 所在程序集的引用,再将HostingStartup从外部程序集引入的话需要手动指定启动程序集的名称。指定启动程序集的方式有两种,一种是指定IWebHostBuilder的扩展UseSetting指定

WebHost.CreateDefaultBuilder(args)
    .UseSetting(WebHostDefaults.HostingStartupAssembliesKey, "Zero.EntityFramework")

                  //如果HostingStartup存在多个程序集中可以使用;分隔
                    //webBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, "StartupEX;StartupEX2");
                    //如果阻止Hosting Startup加载,需要以下设置
                    //webBuilder.UseSetting(WebHostDefaults.PreventHostingStartupKey, "true");
                    //如果排除某些程序集的Hosting Startup加载
                    //webBuilder.UseSetting(WebHostDefaults.HostingStartupExcludeAssembliesKey, "ASSEMBLY1;ASSEMBLY2; ...");

这样便完成了 IHostingStartup 注册。另一种通过添加环境变量ASPNETCORE_HOSTINGSTARTUPASSEMBLIES的方式

"environmentVariables": {
        "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "HostStartupLib"
        //如果HostingStartup存在多个程序集中可以使用;分隔,比如HostStartupLib;HostStartupLib2
        //"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "HostStartupLib;HostStartupLib2"
}

程序集引入

首先我们要在自定义的程序集中至少引入Microsoft.AspNetCore.Hosting包才能使用HostingStartup

<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />

如果你不需要使用注册中间件的逻辑那么仅仅引入Microsoft.AspNetCore.Hosting.Abstractions即可

<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />

IHostingStartup 是由 WebHostBuilder 来调用的,执行时机较早,在创建 WebHost 之前执行,因此可以替换一些在 WebHost 中需要使用的服务。

案例

Furion框架利用IHostingStartup完成功能注入


[assembly: HostingStartup(typeof(Furion.HostingStartup))]

namespace Furion
{
    /// <summary>
    /// 配置程序启动时自动注入
    /// </summary>
    [SuppressSniffer]
    public sealed class HostingStartup : IHostingStartup
    {
        /// <summary>
        /// 配置应用启动
        /// </summary>
        /// <param name="builder"></param>
        public void Configure(IWebHostBuilder builder)
        {
            // 自动装载配置
            builder.ConfigureAppConfiguration((hostingContext, config) =>
            {
                // 存储环境对象
                InternalApp.HostEnvironment = InternalApp.WebHostEnvironment = hostingContext.HostingEnvironment;

                // 加载配置
                InternalApp.AddConfigureFiles(config, InternalApp.HostEnvironment);
            });

            // 自动注入 AddApp() 服务
            builder.ConfigureServices(services =>
            {
                // 添加主机启动停止监听
                services.AddHostedService<AppHostedService>();

                // 注册 Startup 过滤器
                services.AddTransient<IStartupFilter, StartupFilter>();

                // 添加全局配置和存储服务提供器
                InternalApp.InternalServices = services;

                // 初始化应用服务
                services.AddApp();
            });
        }
    }

参考:
https://www.cnblogs.com/artech/p/asp-net-core-program-model-5.html Startup
https://www.cnblogs.com/wucy/p/14013622.html HostingStartup源码

posted @ 2020-01-04 17:03  .Neterr  阅读(1379)  评论(0编辑  收藏  举报