ABP的动态WebApi实现了直接对服务层的调用(其实病没有跨过ApiController,只是将ApiController公共化,对于这一点的处理类似于MVC,对服务端的 调用没有跨过HttpHandler一样),这样不仅减少了ApiController的开发,也更能体现驱动领域设计的层结构。

对WebApi服务的替换与路由配置

AbpWebApiModule是Abp.Web.Api的模块类,该类中定义InitializeAspNetServices,InitializeRoutes两个方法,并且在模块的Initialize方法中执行,这两个方法分别是对WebApi的服务的替换与路由的配置,。这两处对WebApi的变更才使得直接调用服务层成为可能。

  1. private static void InitializeAspNetServices()
  2. {
  3. GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new AbpHttpControllerSelector(GlobalConfiguration.Configuration));
  4. GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionSelector), new AbpApiControllerActionSelector());
  5. GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new AbpControllerActivator());
  6. }
  7.  
  8. private static void InitializeRoutes()
  9. {
  10. DynamicApiRouteConfig.Register();
  11. }
  12.  
  13. public static void Register()
  14. {
  15. //Dynamic Web APIs (with area name)
  16. GlobalConfiguration.Configuration.Routes.MapHttpRoute(
  17. name: "AbpDynamicWebApi",
  18. routeTemplate: "api/services/{*serviceNameWithAction}"
  19. );
  20. }

对服务的分析与缓存

再对服务信息的存储上,作者提供了DynamicApiControllerInfo,DynamicApiActionInfo(源码中的DynamicApiMethodInfo.cs),其中DynamicApiControllerInfo包含了一DynamicApiActionInfo集合。

  1. internal class DynamicApiControllerInfo
  2. {
  3. /// <summary>
  4. /// Name of the service.
  5. /// </summary>
  6. public string ServiceName { get; private set; }
  7.  
  8. /// <summary>
  9. /// Controller type.
  10. /// </summary>
  11. public Type Type { get; private set; }
  12.  
  13. /// <summary>
  14. /// Dynamic Action Filters for this controller.
  15. /// </summary>
  16. public IFilter[] Filters { get; set; }
  17.  
  18. /// <summary>
  19. /// All actions of the controller.
  20. /// </summary>
  21. public IDictionary<string, DynamicApiActionInfo> Actions { get; private set; }
  22.  
  23. /// <summary>
  24. /// Creates a new <see cref="DynamicApiControllerInfo"/> instance.
  25. /// </summary>
  26. /// <param name="serviceName">Name of the service</param>
  27. /// <param name="type">Controller type</param>
  28. /// <param name="filters">Filters</param>
  29. public DynamicApiControllerInfo(string serviceName, Type type, IFilter[] filters = null)
  30. {
  31. ServiceName = serviceName;
  32. Type = type;
  33. Filters = filters ?? new IFilter[] { }; //Assigning or initialzing the action filters.
  34.  
  35. Actions = new Dictionary<string, DynamicApiActionInfo>(StringComparer.InvariantCultureIgnoreCase);
  36. }
  37. }

在执行AbpHttpControllerSelector, AbpApiControllerActionSelector, AbpControllerActivator的时候,系统已经在初始化的时候对服务层进行了分析与缓存。

在作者给的Demo SimpleTaskSystem下有一模块类SimpleTaskSystemWebApiModule

  1. [DependsOn(typeof(AbpWebApiModule))] //We declare depended modules explicitly
  2. public class SimpleTaskSystemWebApiModule : AbpModule
  3. {
  4. public override void Initialize()
  5. {
  6. //This code is used to register classes to dependency injection system for this assembly using conventions.
  7. IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
  8.  
  9. //Creating dynamic Web Api Controllers for application services.
  10. //Thus, 'web api layer' is created automatically by ABP.
  11.  
  12. DynamicApiControllerBuilder
  13. .ForAll<IApplicationService>(Assembly.GetAssembly(typeof (SimpleTaskSystemApplicationModule)), "tasksystem")
  14. .Build();
  15. }
  16. }

  

在这里是使用到了DynamicApiControllerBuilder,这个类主要是对服务接口进行一个注册,再由IBatchApiControllerBuilder按照注册的服务接口对提供的程序集进行分析。

DynamicApiControllerBuilder提供的ForAll只是返回的一个IBatchApiControllerBuilder实现对象

  1. public static IBatchApiControllerBuilder<T> ForAll<T>(Assembly assembly, string servicePrefix)
  2. {
  3. return new BatchApiControllerBuilder<T>(assembly, servicePrefix);
  4. }

  

这个方法为BatchApiControllerBuilder提供了服务接口与服务接口与需要分析的程序集,以及服务地址前缀。

BatchApiControllerBuilder从程序集中获取实现服务接口的非抽象类。BatchApiControllerBuilder再通过DynamicApiControllerBuilder将这些类与服务名信息传递给IApiControllerBuilder。

  1. public void Build()
  2. {
  3. var types =
  4. from
  5. type in _assembly.GetTypes()
  6. where
  7. type.IsPublic && type.IsInterface && typeof(T).IsAssignableFrom(type) && IocManager.Instance.IsRegistered(type)
  8. select
  9. type;
  10.  
  11. if (_typePredicate != null)
  12. {
  13. types = types.Where(t => _typePredicate(t));
  14. }
  15.  
  16. foreach (var type in types)
  17. {
  18. var serviceName = _serviceNameSelector != null
  19. ? _serviceNameSelector(type)
  20. : GetConventionalServiceName(type);
  21.  
  22. if (!string.IsNullOrWhiteSpace(_servicePrefix))
  23. {
  24. serviceName = _servicePrefix + "/" + serviceName;
  25. }
  26.  
  27. var builder = typeof(DynamicApiControllerBuilder)
  28. .GetMethod("For", BindingFlags.Public | BindingFlags.Static)
  29. .MakeGenericMethod(type)
  30. .Invoke(null, new object[] { serviceName });
  31.  
  32. if (_filters != null)
  33. {
  34. builder.GetType()
  35. .GetMethod("WithFilters", BindingFlags.Public | BindingFlags.Instance)
  36. .Invoke(builder, new object[] { _filters });
  37. }
  38.  
  39. builder.GetType()
  40. .GetMethod("Build", BindingFlags.Public | BindingFlags.Instance)
  41. .Invoke(builder, new object[0]);
  42. }
  43. }

  

IApiControllerBuilder将通过服务类生成DynamicApiControllerInfo,再将IApiControllerBuilder存储于DynamicApiControllerManager中,同时分析服务类,将公开非静态方法作为action,存储到DynamicApiControllerManager.Actions

  1. internal class ApiControllerBuilder<T> : IApiControllerBuilder<T>
  2. {
  3. /// <summary>
  4. /// Name of the controller.
  5. /// </summary>
  6. private readonly string _serviceName;
  7.  
  8. /// <summary>
  9. /// List of all action builders for this controller.
  10. /// </summary>
  11. private readonly IDictionary<string, ApiControllerActionBuilder<T>> _actionBuilders;
  12.  
  13. /// <summary>
  14. /// Action Filters to apply to the whole Dynamic Controller.
  15. /// </summary>
  16. private IFilter[] _filters;
  17.  
  18. /// <summary>
  19. /// Creates a new instance of ApiControllerInfoBuilder.
  20. /// </summary>
  21. /// <param name="serviceName">Name of the controller</param>
  22. public ApiControllerBuilder(string serviceName)
  23. {
  24. if (string.IsNullOrWhiteSpace(serviceName))
  25. {
  26. throw new ArgumentException("serviceName null or empty!", "serviceName");
  27. }
  28.  
  29. if (!DynamicApiServiceNameHelper.IsValidServiceName(serviceName))
  30. {
  31. throw new ArgumentException("serviceName is not properly formatted! It must contain a single-depth namespace at least! For example: 'myapplication/myservice'.", "serviceName");
  32. }
  33.  
  34. _serviceName = serviceName;
  35.  
  36. _actionBuilders = new Dictionary<string, ApiControllerActionBuilder<T>>();
  37. foreach (var methodInfo in DynamicApiControllerActionHelper.GetMethodsOfType(typeof(T)))
  38. {
  39. _actionBuilders[methodInfo.Name] = new ApiControllerActionBuilder<T>(this, methodInfo);
  40. }
  41. }
  42.  
  43. /// <summary>
  44. /// The adds Action filters for the whole Dynamic Controller
  45. /// </summary>
  46. /// <param name="filters"> The filters. </param>
  47. /// <returns>The current Controller Builder </returns>
  48. public IApiControllerBuilder<T> WithFilters(params IFilter[] filters)
  49. {
  50. _filters = filters;
  51. return this;
  52. }
  53.  
  54. /// <summary>
  55. /// Used to specify a method definition.
  56. /// </summary>
  57. /// <param name="methodName">Name of the method in proxied type</param>
  58. /// <returns>Action builder</returns>
  59. public IApiControllerActionBuilder<T> ForMethod(string methodName)
  60. {
  61. if (!_actionBuilders.ContainsKey(methodName))
  62. {
  63. throw new AbpException("There is no method with name " + methodName + " in type " + typeof(T).Name);
  64. }
  65.  
  66. return _actionBuilders[methodName];
  67. }
  68.  
  69. /// <summary>
  70. /// Builds the controller.
  71. /// This method must be called at last of the build operation.
  72. /// </summary>
  73. public void Build()
  74. {
  75. var controllerInfo = new DynamicApiControllerInfo(_serviceName, typeof(DynamicApiController<T>), _filters);
  76.  
  77. foreach (var actionBuilder in _actionBuilders.Values)
  78. {
  79. if (actionBuilder.DontCreate)
  80. {
  81. continue;
  82. }
  83.  
  84. controllerInfo.Actions[actionBuilder.ActionName] = actionBuilder.BuildActionInfo();
  85. }
  86.  
  87. IocManager.Instance.IocContainer.Register(
  88. Component.For<AbpDynamicApiControllerInterceptor<T>>().LifestyleTransient(),
  89. Component.For<DynamicApiController<T>>().Proxy.AdditionalInterfaces(new[] { typeof(T) }).Interceptors<AbpDynamicApiControllerInterceptor<T>>().LifestyleTransient()
  90. );
  91.  
  92. DynamicApiControllerManager.Register(controllerInfo);
  93.  
  94. LogHelper.Logger.DebugFormat("Dynamic web api controller is created for type '{0}' with service name '{1}'.", typeof(T).FullName, controllerInfo.ServiceName);
  95. }
  96. }

  

ABP之动态WebAPI(一)的更多相关文章

  1. ABP源码分析三十五:ABP中动态WebAPI原理解析

    动态WebAPI应该算是ABP中最Magic的功能之一了吧.开发人员无须定义继承自ApiController的类,只须重用Application Service中的类就可以对外提供WebAPI的功能, ...

  2. ABP中动态WebAPI原理解析

    ABP中动态WebAPI原理解析 动态WebAPI应该算是ABP中最Magic的功能之一了吧.开发人员无须定义继承自ApiController的类,只须重用Application Service中的类 ...

  3. ABP之动态WebAPI

    ABP之动态WebAPI ABP的动态WebApi实现了直接对服务层的调用(其实病没有跨过ApiController,只是将ApiController公共化,对于这一点的处理类似于MVC,对服务端的 ...

  4. ABP之动态WebAPI(二)

    HttpControllerDescriptor与HttpActionDescriptor HttpControllerDescriptor封装了某个HttpController类型的元数据,我们可以 ...

  5. 动态WebApi

    动态WebApi实现了直接对Service的调用,其实没有跨过ApiController,只是我们自己创建出ApiController 实现主要分以下几步 一 对默认WebApi服务的替换 ApiGl ...

  6. ABP项目中使用Swagger生成动态WebAPI

    本文是根据角落的白板报的<使用ABP实现SwaggerUI,生成动态webapi>一文的学习总结,感谢原文作者角落的白板报. 1 安装Swashbuckle.core 1.1 选择WebA ...

  7. 最新版ABP 动态WebAPI 日期转json带T的解决方案| ABP DateTIme Json format

    ABP动态webapi返回的json数据中,日期时间带T还有毫秒数的问题,在以往的版本中可以使用下面方法解决: 在XXXAbpWebApiModule中加上下面的代码: 很老的很老的版本有效: pub ...

  8. [ABP框架]动态web Api的拦截用法。

    先进行配置 首先这种需求,一般发生在APP端,我们给APP,不会给所有项目系统的接口给他们用.我们系统有200个接口,但是APP的需求只会用20个.那么这个需求也就应运而生了. 以上为API文件夹中为 ...

  9. ASP.NET Core 奇淫技巧之动态WebApi

    一.前言 接触到动态WebApi(Dynamic Web API)这个词的已有几年,是从ABP框架里面接触到的,当时便对ABP的这个技术很好奇,后面分析了一波,也尝试过从ABP剥离一个出来作为独立组件 ...

随机推荐

  1. PHP钩子机制

    什么是钩子 大家想必听过插件,wordpress插件特别多,这个就是用钩子机制实现的. 当代码在运行的过程中,我们预先在运行的几个特殊点里执行一些特殊方法:例如在运行方法(例如Blog::add的ad ...

  2. 我所理解的Cocos2d-x

    我所理解的Cocos2d-x(完全基于Cocos2d-x3.0,深度剖析计算机图形学,OpenGL ES及游戏引擎架构,全面提升游戏开发相关知识) 秦春林 著   ISBN 978-7-121-246 ...

  3. MacOS中使用QT开发iOS应用

    因为项目合同中规定一部分业务内容要在手机端实现,包括安卓机和苹果机,因此选择了QT作为开发工具.程序在Win10和安卓系统上已经完美运行,这几天开始搭建iOS的编译和发布环境,因为以前没有使用过mac ...

  4. 使用Event Message 对 Package 进行Troubleshoot

    在SSIS Server上,发现一个Package Job运行异常,该Package处于僵死状态.从 Job Activity Monitor中看到该Job一直处于运行状态,但是,DW中没有执行任何Q ...

  5. JavaScript JsTree实例

    var RightTree= function () { }; RightTree.prototype = { //初始化权限树 InitRightTree: function () { $.ajax ...

  6. NFS Volume Provider(Part I) - 每天5分钟玩转 OpenStack(62)

    cinder-volume 支持多种 volume provider,前面我们一直使用的是默认的 LVM,本节我们将增加 NFS volume provider. 虽然 NFS 更多地应用在实验或小规 ...

  7. MySQL学习笔记五:数据类型

    MySQL支持多种数据类型,大致可以分为数值,日期/时间和字符类型. 数值类型 MySQL支持所有标准SQL数值数据类型,包括严格数值数据类型(INTEGER.SMALLINT.DECIMAL和NUM ...

  8. 包含块( Containing block ) 转自W3CHelp

    包含块简介 在 CSS2.1 中,很多框的定位和尺寸的计算,都取决于一个矩形的边界,这个矩形,被称作是包含块( containing block ). 一般来说,(元素)生成的框会扮演它子孙元素包含块 ...

  9. ZOJ Problem Set - 1241 Geometry Made Simple

    水题不解释 #include <stdio.h> #include <math.h> int main() { ,flag=; double a,b,c; while(scan ...

  10. hibernate笔记--单(双)向的多对多映射关系

    在讲单向的多对多的映射关系的案例时,我们假设我们有两张表,一张角色表Role,一张权限表Function,我们知道一个角色或者说一个用户,可能有多个操作权限,而一种操作权限同时被多个用户所拥有,假如我 ...