<深入理解Abp> 程序启动 - 一切的开始

匿名 (未验证) 提交于 2019-12-02 22:06:11

我们知道NET Core应用程序的核心配置在项目中的Startup.cs 文件.

public class Startup {     public IServiceProvider ConfigureServices(IServiceCollection services)     {         //...                  return services.AddAbp<WebModule>(//...);     }      public void Configure(IApplicationBuilder app)     {         app.UseAbp(//...);          //...     } }
  • public void ConfigureServices(IServiceCollection services)方法主要用于将服务添加到DI容器中并做一些配置.
  • public void Configure(IApplicationBuilder app)配置请求管道.

Abp框架使用自己的DI容器(主要为了兼容之前的NET Framework版本和使用一些高级特性,如拦截器),所以我们在ConfigureServices 方法的底部会看到return services.AddAbp(//...)这时候ConfigureServices的方法返回值也变成了IServiceProvider(关于这点请参考:默认服务容器替换)

框架与ASPNET Core深度集成的地方就在AddAbp方法和UseAbp的内部:

public static class AbpServiceCollectionExtensions {     /// <summary>     /// Integrates ABP to AspNet Core.     /// </summary>     /// <typeparam name="TStartupModule">Startup module of the application which depends on other used modules. Should be derived from <see cref="AbpModule"/>.</typeparam>     /// <param name="services">Services.</param>     /// <param name="optionsAction">An action to get/modify options</param>     public static IServiceProvider AddAbp<TStartupModule>(this IServiceCollection services, [CanBeNull] Action<AbpBootstrapperOptions> optionsAction = null)         where TStartupModule : AbpModule     {         var abpBootstrapper = AddAbpBootstrapper<TStartupModule>(services, optionsAction);          ConfigureAspNetCore(services, abpBootstrapper.IocManager);          return WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services);     }      private static void ConfigureAspNetCore(IServiceCollection services, IIocResolver iocResolver)     {         //See https://github.com/aspnet/Mvc/issues/3936 to know why we added these services.         services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();         services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();                  //Use DI to create controllers         services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());          //Use DI to create view components         services.Replace(ServiceDescriptor.Singleton<IViewComponentActivator, ServiceBasedViewComponentActivator>());          //Change anti forgery filters (to work proper with non-browser clients)         services.Replace(ServiceDescriptor.Transient<AutoValidateAntiforgeryTokenAuthorizationFilter, AbpAutoValidateAntiforgeryTokenAuthorizationFilter>());         services.Replace(ServiceDescriptor.Transient<ValidateAntiforgeryTokenAuthorizationFilter, AbpValidateAntiforgeryTokenAuthorizationFilter>());          //Add feature providers         var partManager = services.GetSingletonServiceOrNull<ApplicationPartManager>();         partManager?.FeatureProviders.Add(new AbpAppServiceControllerFeatureProvider(iocResolver));          //Configure JSON serializer         services.Configure<MvcJsonOptions>(jsonOptions =>         {             jsonOptions.SerializerSettings.ContractResolver = new AbpMvcContractResolver(iocResolver)             {                 NamingStrategy = new CamelCaseNamingStrategy()             };         });          //Configure MVC         services.Configure<MvcOptions>(mvcOptions =>         {             mvcOptions.AddAbp(services);         });          //Configure Razor         services.Insert(0,             ServiceDescriptor.Singleton<IConfigureOptions<RazorViewEngineOptions>>(                 new ConfigureOptions<RazorViewEngineOptions>(                     (options) =>                     {                         options.FileProviders.Add(new EmbeddedResourceViewFileProvider(iocResolver));                     }                 )             )         );     }      private static AbpBootstrapper AddAbpBootstrapper<TStartupModule>(IServiceCollection services, Action<AbpBootstrapperOptions> optionsAction)         where TStartupModule : AbpModule     {         var abpBootstrapper = AbpBootstrapper.Create<TStartupModule>(optionsAction);         services.AddSingleton(abpBootstrapper);         return abpBootstrapper;     } }

AbpBootstrapper作为Abp核心的引导类,负责初始化Abp系统,加载插件,配置Abp和模块以及启动模块(PreInitialize,Initialize, PostInitialize). 这个引导类在console应用程序中同样可以启动Abpϵͳ.

接下来Abp配置和替换了多个MVC的组件,如IControllerActivator,IViewComponentActivator,MvcJsonOptions,MvcOptions更多的配置在mvcOptions.AddAbp(services)方法下:

internal static class   {     public static void AddAbp(this MvcOptions options, IServiceCollection services)     {         AddConventions(options, services);         AddFilters(options);         AddModelBinders(options);     }      private static void AddConventions(MvcOptions options, IServiceCollection services)     {         options.Conventions.Add(new AbpAppServiceConvention(services));     }      private static void AddFilters(MvcOptions options)     {         options.Filters.AddService(typeof(AbpAuthorizationFilter));         options.Filters.AddService(typeof(AbpAuditActionFilter));         options.Filters.AddService(typeof(AbpValidationActionFilter));         options.Filters.AddService(typeof(AbpUowActionFilter));         options.Filters.AddService(typeof(AbpExceptionFilter));         options.Filters.AddService(typeof(AbpResultFilter));     }      private static void AddModelBinders(MvcOptions options)     {         options.ModelBinderProviders.Insert(0, new AbpDateTimeModelBinderProvider());     } }

AbpAppServiceConvention 主要用于配置动态API,这个后面会有一章单独说明.

AbpAuthorizationFilter AbpAuditActionFilter AbpValidationActionFilter AbpUowActionFilter AbpExceptionFilter AbpResultFilter

依次添加6个MVC过滤器分别实现授权,审计,参数验证,工作单元,异常处理以及返回内容的包装.(请注意过滤器顺序很重要)

AbpDateTimeModelBinderProvider 用作DateTime的统一时区处理.

接下来我们再看UseAbp方法:

public static class AbpApplicationBuilderExtensions {     public static void UseAbp(this IApplicationBuilder app)     {         app.UseAbp(null);     }      public static void UseAbp([NotNull] this IApplicationBuilder app, Action<AbpApplicationBuilderOptions> optionsAction)     {         Check.NotNull(app, nameof(app));          var options = new AbpApplicationBuilderOptions();         optionsAction?.Invoke(options);          if (options.UseCastleLoggerFactory)         {             app.UseCastleLoggerFactory();         }          InitializeAbp(app);          if (options.UseAbpRequestLocalization)         {             //TODO: This should be added later than authorization middleware!             app.UseAbpRequestLocalization();         }          if (options.UseSecurityHeaders)         {             app.UseAbpSecurityHeaders();         }     }      public static void UseEmbeddedFiles(this IApplicationBuilder app)     {         app.UseStaticFiles(             new StaticFileOptions             {                 FileProvider = new EmbeddedResourceFileProvider(                     app.ApplicationServices.GetRequiredService<IIocResolver>()                 )             }         );     }      private static void InitializeAbp(IApplicationBuilder app)     {         var abpBootstrapper = app.ApplicationServices.GetRequiredService<AbpBootstrapper>();         abpBootstrapper.Initialize();          var applicationLifetime = app.ApplicationServices.GetService<IApplicationLifetime>();         applicationLifetime.ApplicationStopping.Register(() => abpBootstrapper.Dispose());     }      public static void UseCastleLoggerFactory(this IApplicationBuilder app)     {         var castleLoggerFactory = app.ApplicationServices.GetService<Castle.Core.Logging.ILoggerFactory>();         if (castleLoggerFactory == null)         {             return;         }          app.ApplicationServices             .GetRequiredService<ILoggerFactory>()             .AddCastleLogger(castleLoggerFactory);     }      public static void UseAbpRequestLocalization(this IApplicationBuilder app, Action<RequestLocalizationOptions> optionsAction = null)     {         var iocResolver = app.ApplicationServices.GetRequiredService<IIocResolver>();         using (var languageManager = iocResolver.ResolveAsDisposable<ILanguageManager>())         {             var supportedCultures = languageManager.Object                 .GetLanguages()                 .Select(l => CultureInfo.GetCultureInfo(l.Name))                 .ToArray();              var options = new RequestLocalizationOptions             {                 SupportedCultures = supportedCultures,                 SupportedUICultures = supportedCultures             };              var userProvider = new AbpUserRequestCultureProvider();              //0: QueryStringRequestCultureProvider             options.RequestCultureProviders.Insert(1, userProvider);             options.RequestCultureProviders.Insert(2, new AbpLocalizationHeaderRequestCultureProvider());             //3: CookieRequestCultureProvider             options.RequestCultureProviders.Insert(4, new AbpDefaultRequestCultureProvider());             //5: AcceptLanguageHeaderRequestCultureProvider              optionsAction?.Invoke(options);              userProvider.CookieProvider = options.RequestCultureProviders.OfType<CookieRequestCultureProvider>().FirstOrDefault();             userProvider.HeaderProvider = options.RequestCultureProviders.OfType<AbpLocalizationHeaderRequestCultureProvider>().FirstOrDefault();              app.UseRequestLocalization(options);         }     }      public static void UseAbpSecurityHeaders(this IApplicationBuilder app)     {         app.UseMiddleware<AbpSecurityHeadersMiddleware>();     } }

核心InitializeAbp(app),使用上文之前提到AbpBootstrapper引导启动Abp系统.(我们知道Abp模块有个Shutdown()方法,Abp使用IApplicationLifetime接口捕获应用程序事件实现模块的Shoutdown)

之后按需启动几个中间件,如: RequestLocalization,SecurityHeaders等(这些小组件和之前的过滤器后面我会分别详细介绍,这里就不深入讲解)

Abp中文网:https://cn.abp.io/
Abp交流群:735901849(纯技术交流,无广告,不卖课)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!