相關模塊 1. AbpAspNetCoreModule 2. AbpAspNetCoreMvcModule 3. AbpAspNetCoreMvcContractsModule abp通過這三個模塊載入並配置了 asp.net core。,最主要的就是AbpAspNetCoreMvcModule模塊 ...
相關模塊
- AbpAspNetCoreModule
- AbpAspNetCoreMvcModule
- AbpAspNetCoreMvcContractsModule
abp通過這三個模塊載入並配置了 asp.net core。,最主要的就是AbpAspNetCoreMvcModule模塊類,abp如何基於aspnet core構建自己的控制器和AppServices,就是在這個類中。
AbpAspNetCoreMvcModule
將AbpAspNetCoreMvcConventionalRegister類添加到ConventionalRegistrarList列表中,該類主要是用來註入依賴及獲取服務生命周期的。public override void PreConfigureServices(ServiceConfigurationContext context) { context.Services.AddConventionalRegistrar(new AbpAspNetCoreMvcConventionalRegistrar()); }
接下來就是重點,在ConfigureServices方法中配置視圖和控制器,當然是基於 asp.net core mvc。首先配置Razor:
context.Services.Insert(0, ServiceDescriptor.Singleton<IConfigureOptions<RazorViewEngineOptions>>( new ConfigureOptions<RazorViewEngineOptions>(options => { options.FileProviders.Add( new RazorViewEngineVirtualFileProvider( context.Services.GetSingletonInstance<IObjectAccessor<IServiceProvider>>() ) ); } ) ) );
配置Api描述符:
Configure<ApiDescriptionModelOptions>(options => { options.IgnoredInterfaces.AddIfNotContains(typeof(IAsyncActionFilter)); options.IgnoredInterfaces.AddIfNotContains(typeof(IFilterMetadata)); options.IgnoredInterfaces.AddIfNotContains(typeof(IActionFilter)); });
可以看到 aspnetcore mvc中的過濾器介面,我們將其添加到了Api描述模型選項類中。下麵就是註入MVC:
var mvcCoreBuilder = context.Services.AddMvcCore(); var mvcBuilder = context.Services.AddMvc() .AddDataAnnotationsLocalization(options => { options.DataAnnotationLocalizerProvider = (type, factory) => { var resourceType = abpMvcDataAnnotationsLocalizationOptions.AssemblyResources.GetOrDefault(type.Assembly); return factory.Create(resourceType ?? type); }; }) .AddViewLocalization();
使用DI創建控制器,使用的是aspnet core預設的控制器激活器ServiceBasedControllerActivator類:
//Use DI to create controllers context.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
abp提供了一個基於約定的控制器特性提供器類,這個類是基於 aspnetcore mvc的ControllerFeatureProvider構建自己的控制器,並檢索判斷控制器。
//Add feature providers var partManager = context.Services.GetSingletonInstance<ApplicationPartManager>(); var application = context.Services.GetSingletonInstance<IAbpApplication>(); partManager.FeatureProviders.Add(new AbpConventionalControllerFeatureProvider(application));
該類源碼:
public class AbpConventionalControllerFeatureProvider : ControllerFeatureProvider { private readonly IAbpApplication _application; public AbpConventionalControllerFeatureProvider(IAbpApplication application) { _application = application; } protected override bool IsController(TypeInfo typeInfo) { //TODO: Move this to a lazy loaded field for efficiency. if (_application.ServiceProvider == null) { return false; } var configuration = _application.ServiceProvider .GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>().Value .ConventionalControllers .ConventionalControllerSettings .GetSettingOrNull(typeInfo.AsType()); return configuration != null; } }
由上,abp會基於aspnetcore mvc配置abp的mvc模塊,特別是Controller的創建。從代碼裡面可以看出獲取到AbpAspNetCoreMvcOptions的服務再去檢索規約的控制器。由此返回是否是控制器。AbpAspNetCoreMvcOptions類是Abp對aspnet core mvc的一個封裝,源碼如下:
public class AbpAspNetCoreMvcOptions { public ConventionalControllerOptions ConventionalControllers { get; } public AbpAspNetCoreMvcOptions() { ConventionalControllers = new ConventionalControllerOptions(); } } //規約控制器集合 public class ConventionalControllerOptions { public ConventionalControllerSettingList ConventionalControllerSettings { get; } public List<Type> FormBodyBindingIgnoredTypes { get; } public ConventionalControllerOptions() { ConventionalControllerSettings = new ConventionalControllerSettingList(); FormBodyBindingIgnoredTypes = new List<Type> { typeof(IFormFile) }; } public ConventionalControllerOptions Create(Assembly assembly, [CanBeNull] Action<ConventionalControllerSetting> optionsAction = null) { var setting = new ConventionalControllerSetting(assembly, ModuleApiDescriptionModel.DefaultRootPath); // DefaultRootPath = app,abp路由就是以這個app開頭的。 optionsAction?.Invoke(setting); setting.Initialize(); ConventionalControllerSettings.Add(setting); return this; } }
AbpAspNetCoreMvcOptions實際上是通過ConventionalControllerOptions來完成規約的配置,來實現自定義的路由以及動態API。
AspNetCoreDescriptionModelProvider
abp是如何aspnet core創建自己的API的呢?有這麼一個類AspNetCoreDescriptionModelProvider,這個類就是提供了aspnet core的描述模型,源碼如下:
public class AspNetCoreApiDescriptionModelProvider : IApiDescriptionModelProvider, ITransientDependency { public ILogger<AspNetCoreApiDescriptionModelProvider> Logger { get; set; } private readonly IApiDescriptionGroupCollectionProvider _descriptionProvider; private readonly AbpAspNetCoreMvcOptions _options; private readonly ApiDescriptionModelOptions _modelOptions; public AspNetCoreApiDescriptionModelProvider( IApiDescriptionGroupCollectionProvider descriptionProvider, IOptions<AbpAspNetCoreMvcOptions> options, IOptions<ApiDescriptionModelOptions> modelOptions) { _descriptionProvider = descriptionProvider; _options = options.Value; _modelOptions = modelOptions.Value; Logger = NullLogger<AspNetCoreApiDescriptionModelProvider>.Instance; } public ApplicationApiDescriptionModel CreateApiModel() { //TODO: Can cache the model? var model = ApplicationApiDescriptionModel.Create(); foreach (var descriptionGroupItem in _descriptionProvider.ApiDescriptionGroups.Items) { foreach (var apiDescription in descriptionGroupItem.Items) { if (!apiDescription.ActionDescriptor.IsControllerAction()) { continue; } AddApiDescriptionToModel(apiDescription, model); } } return model; } private void AddApiDescriptionToModel(ApiDescription apiDescription, ApplicationApiDescriptionModel model) { var controllerType = apiDescription.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(); var setting = FindSetting(controllerType); var moduleModel = model.GetOrAddModule(GetRootPath(controllerType, setting)); var controllerModel = moduleModel.GetOrAddController(controllerType.FullName, CalculateControllerName(controllerType, setting), controllerType, _modelOptions.IgnoredInterfaces); var method = apiDescription.ActionDescriptor.GetMethodInfo(); var uniqueMethodName = GetUniqueActionName(method); if (controllerModel.Actions.ContainsKey(uniqueMethodName)) { Logger.LogWarning($"Controller '{controllerModel.ControllerName}' contains more than one action with name '{uniqueMethodName}' for module '{moduleModel.RootPath}'. Ignored: " + method); return; } Logger.LogDebug($"ActionApiDescriptionModel.Create: {controllerModel.ControllerName}.{uniqueMethodName}"); var actionModel = controllerModel.AddAction(uniqueMethodName, ActionApiDescriptionModel.Create( uniqueMethodName, method, apiDescription.RelativePath, apiDescription.HttpMethod, GetSupportedVersions(controllerType, method, setting) )); AddParameterDescriptionsToModel(actionModel, method, apiDescription); } private static string CalculateControllerName(Type controllerType, ConventionalControllerSetting setting) { var controllerName = controllerType.Name.RemovePostFix("Controller").RemovePostFix(ApplicationService.CommonPostfixes); if (setting?.UrlControllerNameNormalizer != null) { controllerName = setting.UrlControllerNameNormalizer(new UrlControllerNameNormalizerContext(setting.RootPath, controllerName)); } return controllerName; } }
這個類為我們提供了從Action到Controller的描述,構建了abp自己的api。它的調用有兩個地方,一個是AbpApiDefinitionController,一個是ProxyScriptManager,前者是定義Abp的api控制器定義的地方,後者則是生成代理腳本的地方,abp的示例項目BookStore中會調用介面Abp/ServiceProxyScript生成一個js文件,這個js文件裡面就是api的url地址,前端通過訪問這個api地址來訪問appservice等後端方法。源碼如下:
[Area("Abp")] [Route("Abp/ServiceProxyScript")] [DisableAuditing] public class AbpServiceProxyScriptController : AbpController { private readonly IProxyScriptManager _proxyScriptManager; public AbpServiceProxyScriptController(IProxyScriptManager proxyScriptManager) { _proxyScriptManager = proxyScriptManager; } [HttpGet] [Produces("text/javascript", "text/plain")] public string GetAll(ServiceProxyGenerationModel model) { model.Normalize(); return _proxyScriptManager.GetScript(model.CreateOptions()); } }
AbpHttpModule模塊
Abp創建jquery代理腳本生成器,主要用來生產api提供給前端訪問public override void ConfigureServices(ServiceConfigurationContext context) { Configure<AbpApiProxyScriptingOptions>(options => { options.Generators[JQueryProxyScriptGenerator.Name] = typeof(JQueryProxyScriptGenerator); }); }