我們知道 應用程式的核心配置在項目中的 " " 文件. 方法主要用於將服務添加到 容器中並做一些配置. 配置請求管道. 框架使用自己的DI容器\(主要為了相容之前的NET Framework版本和使用一些高級特性,如攔截器\),所以我們在 方法的底部會看到 這時候 的方法返回值也變成了 \(關於這點 ...
我們知道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(純技術交流,無廣告,不賣課)