相关模块
  1. AbpAspNetCoreModule
  2. AbpAspNetCoreMvcModule
  3. 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);
    });
    }

4. abp中的asp.net core模块剖析的更多相关文章

  1. 中小研发团队架构实践之生产环境诊断工具WinDbg 三分钟学会.NET微服务之Polly 使用.Net Core+IView+Vue集成上传图片功能 Fiddler原理~知多少? ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一) C#程序中设置全局代理(Global Proxy) WCF 4.0 使用说明 如何在IIS上发布,并能正常访问

    中小研发团队架构实践之生产环境诊断工具WinDbg 生产环境偶尔会出现一些异常问题,WinDbg或GDB是解决此类问题的利器.调试工具WinDbg如同医生的听诊器,是系统生病时做问题诊断的逆向分析工具 ...

  2. ASP.NET Core模块概述

    原文地址:ASP.NET Core Module overview By Tom Dykstra, Rick Strahl, and Chris Ross ASP.NET Core模块(ANCM)让你 ...

  3. 丙申年把真假美猴王囚禁在容器中跑 ASP.NET Core 1.0

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  4. 在Visual Studio 2017中使用Asp.Net Core构建Angular4应用程序

    前言 Visual Studio 2017已经发布了很久了.做为集成了Asp.Net Core 1.1的地表最强IDE工具,越来越受.NET系的开发人员追捧. 随着Google Angular4的发布 ...

  5. [Asp.Net Core] 1. IIS中的 Asp.Net Core 和 dotnet watch

    在基于传统的.NET Framework的Asp.Net Mvc的时候,本地开发环境中可以在IIS中建立一个站点,可以直接把站点的目录指向asp.net mvc的项目的根目录.然后build一下就可以 ...

  6. 【Asp.Net Core】在Visual Studio 2017中使用Asp.Net Core构建Angular4应用程序

    前言 Visual Studio 2017已经发布了很久了.做为集成了Asp.Net Core 1.1的地表最强IDE工具,越来越受.NET系的开发人员追捧. 随着Google Angular4的发布 ...

  7. ASP.NET Core 2.2 基础知识(十一) ASP.NET Core 模块

    ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ...

  8. IIS中的 Asp.Net Core 和 dotnet watch

    在基于传统的.NET Framework的Asp.Net Mvc的时候,本地开发环境中可以在IIS中建立一个站点,可以直接把站点的目录指向asp.net mvc的项目的根目录.然后build一下就可以 ...

  9. .NET 7 预览版2 中的 ASP.NET Core 更新

    .NET 7 预览版2 现已推出,其中包括对ASP.NET Core 的许多重大改进. 以下是此预览版中新增内容的摘要: 推断来自服务的API 控制器操作参数 SignalR 集线器方法的依赖注入 为 ...

随机推荐

  1. 阿里P7整理“硬核”面试文档:Java基础+数据库+算法+框架技术等

    现在的程序员越来越多,大部分的程序员都想着自己能够进入大厂工作,但每个人的能力都是有差距的,所以并不是人人都能跨进BATJ.即使如此,但身在职场的我们一刻也不能懈怠,既然对BATJ好奇,那么就要朝这个 ...

  2. FileReader.result

    FileReader.result 该属性返回文件的内容.此属性仅在读取操作完成后才有效,并且数据的格式取决于用于启动读取操作的方法.FileReader]**result** 句法 var file ...

  3. Nginx动静分离(Nginx+Tomcat)

    第一步:nginx构建 第二步:Tomcat构建 1.Tomcat基础点 (1)Tomcat 是基于java开发的web容器,用来发布java代码和jsp网页. (2)开发人员开发java web网站 ...

  4. css练习——两列左窄右kuan型

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  5. pycharm中启动Django方法

    1.找到Edit Configurations 2.Parameters处添加  runserver 0.0.0.0:8080 3.运行成功

  6. VLAN应用实例

    VLAN 此次内容主要介绍VLAN的Access接口.Trunk接口.Hybird接口的配置实例,以及实际应用. 一.介绍三种接口 1.Access接口 (1)Access接口是交换机上用来连接用户主 ...

  7. ios instancetype与id区别

    我们都知道未知类型的的对象可以用id关键字表示,那为什么还会再有一个instancetype呢? instancetype能返回相关联的类型(使那些非关联返回类型的方法返回所在类的类型):而id 返回 ...

  8. 商品类目和商品大广告的Redis缓存

    (dubbo)主要的实现类: 商品类目的Redis缓存 com.bjsxt.ego.portal.service.impl.PortalItemCatServiceImpl package com.b ...

  9. 无向图的桥+搜索优化--UESTC1956-北极的猴子

    北极的猴子 Time Limit: 1000 MS     Memory Limit: 256 MB Submit Status 也许你不知道,在北极也有猴子,我们叫它们北极猴.北极猴们在北极一共有n ...

  10. Java并发编程系列-(3) 原子操作与CAS

    3. 原子操作与CAS 3.1 原子操作 所谓原子操作是指不会被线程调度机制打断的操作:这种操作一旦开始,就一直运行到结束,中间不会有任何context switch,也就是切换到另一个线程. 为了实 ...