相关模块
  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. 【Luogu P3387】缩点模板(强连通分量Tarjan&拓扑排序)

    Luogu P3387 强连通分量的定义如下: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶 ...

  2. day 49

    今日内容 标签操作 样式操作 样式类操作 addClass(); // 添加指定的CSS类名. removeClass(); // 移除指定的CSS类名. hasClass(); // 判断样式存不存 ...

  3. T1110-计算线段长度

    原题链接: https://nanti.jisuanke.com/t/T1010 题目简述: 已知线段的两个端点的坐标A(Xa,Ya),B(Xb,Yb)A(X_a,Y_a),B(X_b,Y_b)A(X ...

  4. Java核心技术第八章-泛型

    摘要 本文根据<Java核心技术 卷一>一书的第八章总结而成,部分文章摘抄书内,作为个人笔记. 文章不会过于深入,望读者参考便好. 为什么要使用泛型程序设计 泛型程序设计(Generic ...

  5. 【数据结构】之链表(Java语言描述)

    以前写过一篇帖子,记录了链表在C语言中的描述代码.C语言中没有链表的直接实现,因此,我们需要自己编写代码实现.请参考[我的这篇文章]. Java中默认为我们提供了链表的API—— LinkedList ...

  6. RocketMQ 多副本前置篇:初探raft协议

    目录 1.Leader选举 1.1 一轮投票中,只有一个节点发起投票的情况 1.2 一轮投票中,超过一个节点发起投票的情况 1.3 思考如何实现Raft选主 2.日志复制 Raft协议是分布式领域解决 ...

  7. Python高级数据结构-Collections模块

    在Python数据类型方法精心整理,不必死记硬背,看看源码一切都有了之中,认识了python基本的数据类型和数据结构,现在认识一个高级的:Collections 这个模块对上面的数据结构做了封装,增加 ...

  8. centOS7 可以ping通主机不能访问外网

    前言: 突然打开自己前不久在虚拟机安装的centOS7系统,发现以前可以来联网突然不能访问外网,在网上看了很多方法,终于解决 问题描述: 连上网,但是ping 不同外网,如ping www.baodu ...

  9. 修改PHP上传文件大小限制

    1. 在php.ini中,做如下修改: file_uploads = on upload_tmp_dir = /home/upload upload_max_filesize = 4000M post ...

  10. lerna式升级

    有段时间没更新博客了,是时候更新一波了. 之前不是vue-next出了吗,然后就去学习了一下,发现整个目录不是那么熟悉了,变成这样了: 于是就这个线索去研究了一下,发下这是用的 lerna + yar ...