【.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源码