<深入理解Abp> 程式啟動 - 一切的開始
我們知道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
已經把框架的相關元件整合到了MVC
中.接下來程式啟動.請求被各種中介軟體處理(MVC中介軟體會呼叫過濾器).
Abp中文網:https://cn.abp.io/
Abp交流群:735901849(純技術交流,無廣告,不賣課)