模块化的介绍一共2篇git
这一篇咱们实现一个功能很是简单的StartupModules模块化。github
第二篇咱们来实现一个ABP的模块化效果。web
其实来简单想一下模块化的实验思路,写个接口=>模块类继承该接口=>项目启动反射检索=>调用接口实现。
那么具体到代码实践应该怎么写呢。app
第一步就是写一个模块化接口类的嘛!
新建类 IStartupModuleide
而后写一个反射检索全文谁继承了这个接口的方法
新建类 StartupModulesOptions模块化
代码解释: Activator.CreateInstance 与指定参数匹配程度最高的构造函数来建立指定类型的实例
ps:白话文就是,你给我Type我给你建立个对应的实例
更一个有意思的是 Assembly.GetEntryAssembly()! 这个! 是否是很好奇怕
ps:我第一次看到这个语法也蒙了,问了好多人你们都没用过,这个语法同TS中的断言,是非null类型断言,意思就是我断言我这个方法返回的内容绝对不是null。函数
到这里来看咱们是否是已经拿到了全部继承接口的模块那么怎么在该调用的地方调用呢,缺啥写啥
学习
运行代码也有了,我该怎么调用呢。
接下来只要在 在Program 的 WebHost 调用.UseStartupModules() 流程就能够加载咱们的 ConfigureServices 了测试
请让我掏出来一个器大的东西来讲 他就是: IStartupFilter
,这个东西是个啥东西呢。来看一段源码ui
namespace Microsoft.AspNetCore.Hosting { public interface IStartupFilter { Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next); } }
这里咱们看到了 Configure 他返回一个 IApplicationBuilder 他是怎么用的呢
咱们新建一个空的Web项目的时候不知道有没有注意过 UseStaticFiles 这个函数
public void Configure(IApplicationBuilder app) { app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}"); }); }
在这个方法中,你能够直接使用方法提供的IApplicationBuilder参数,而且能够向其中添加各类中间件。使用IStartupFilter, 你能够指定并返回一个Action类型的泛型委托,这意味你除了可使用方法提供的泛型委托配置IApplicationBuilder对象, 还须要返回一个泛型委托。
咱们来看一段代码 Build(); 这个会调用BuildApplication方法
public class Program { public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup<Startup>() .Build(); host.Run(); } } private RequestDelegate BuildApplication() { .. IApplicationBuilder builder = builderFactory.CreateBuilder(Server.Features); builder.ApplicationServices = _applicationServices; var startupFilters = _applicationServices.GetService<IEnumerable<IStartupFilter>>(); Action<IApplicationBuilder> configure = _startup.Configure; foreach (var filter in startupFilters.Reverse()) { configure = filter.Configure(configure); } configure(builder); return builder.Build(); }
首先,此方法建立IApplicationBuilder的实例,该实例将用于构建中间件管道,并将ApplicationServices设置为已配置的DI容器。
接下来的代码块很意思。首先,从DI容器中获取了一个集合IEnumerable<IStartupFilter>
咱们能够配置多个IStartupFilter来造成一个管道,因此这个方法只是从容器中取出它们。
如今咱们经过循环遍历每一个IStartupFilter(以相反的顺序),传入Startup.Configure方法,而后更新局部变量configure来建立Configure方法的管道。
咱们本身如何来实现 一个IStartupFilter 让他帮咱们调用 Configure。
在 WebHostBuilderExtensions类 UseStartupModules 方法 ConfigureServices 下用 IStartupFilter 注入实现
这样在Build() 的时候就会调用模块的方法了
ActivatorUtilities.CreateInstance<ModulesStartupFilter>(sp, runner) // 第二个参数是在建立实例的时候 给构造函数注入的第一个参数
Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { // 进行模块映射 webBuilder.UseStartupModules().UseStartup<Startup>(); });
public class HangfireStartupModule : IStartupModule { public void ConfigureServices(IServiceCollection services) { Console.WriteLine("HangfireStartupModule----ConfigureServices"); } public void Configure(IApplicationBuilder app) { Console.WriteLine("HangfireStartupModule----Configure"); } }
一个很是简单的模块化就完工了,固然这个是基础版本,只能拿来借鉴思路学习下。
新建类 ConfigureServicesContext 和 ConfigureMiddlewareContext
public class ConfigureMiddlewareContext { public ConfigureMiddlewareContext(IConfiguration configuration, IWebHostEnvironment hostingEnvironment, IServiceProvider serviceProvider, StartupModulesOptions options) { Configuration = configuration; HostingEnvironment = hostingEnvironment; ServiceProvider = serviceProvider; Options = options; } public IConfiguration Configuration { get; } public IWebHostEnvironment HostingEnvironment { get; } public IServiceProvider ServiceProvider { get; } public StartupModulesOptions Options { get; } } public class ConfigureServicesContext { public ConfigureServicesContext(IConfiguration configuration, IWebHostEnvironment hostingEnvironment, StartupModulesOptions options) { Configuration = configuration; HostingEnvironment = hostingEnvironment; Options = options; } public IConfiguration Configuration { get; } public IWebHostEnvironment HostingEnvironment { get; } public StartupModulesOptions Options { get; } }
修改 StartupModuleRunner 的方法
public void ConfigureServices(IServiceCollection services, IConfiguration configuration, IWebHostEnvironment hostingEnvironment) { var ctx = new ConfigureServicesContext(configuration, hostingEnvironment, _options); foreach (var cfg in _options.StartupModules) { cfg.ConfigureServices(services, ctx); } } public void Configure(IApplicationBuilder app, IConfiguration configuration, IWebHostEnvironment hostingEnvironment) { using (var scope = app.ApplicationServices.CreateScope()) { var ctx = new ConfigureMiddlewareContext(configuration, hostingEnvironment, scope.ServiceProvider, _options); foreach (var cfg in _options.StartupModules) { cfg.Configure(app, ctx); } } }