ABP之动态WebAPI(一)
ABP的动态WebApi实现了直接对服务层的调用(其实病没有跨过ApiController,只是将ApiController公共化,对于这一点的处理类似于MVC,对服务端的 调用没有跨过HttpHandler一样),这样不仅减少了ApiController的开发,也更能体现驱动领域设计的层结构。
对WebApi服务的替换与路由配置
AbpWebApiModule是Abp.Web.Api的模块类,该类中定义InitializeAspNetServices,InitializeRoutes两个方法,并且在模块的Initialize方法中执行,这两个方法分别是对WebApi的服务的替换与路由的配置,。这两处对WebApi的变更才使得直接调用服务层成为可能。
- private static void InitializeAspNetServices()
- {
- GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new AbpHttpControllerSelector(GlobalConfiguration.Configuration));
- GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionSelector), new AbpApiControllerActionSelector());
- GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new AbpControllerActivator());
- }
- private static void InitializeRoutes()
- {
- DynamicApiRouteConfig.Register();
- }
- public static void Register()
- {
- //Dynamic Web APIs (with area name)
- GlobalConfiguration.Configuration.Routes.MapHttpRoute(
- name: "AbpDynamicWebApi",
- routeTemplate: "api/services/{*serviceNameWithAction}"
- );
- }
对服务的分析与缓存
再对服务信息的存储上,作者提供了DynamicApiControllerInfo,DynamicApiActionInfo(源码中的DynamicApiMethodInfo.cs),其中DynamicApiControllerInfo包含了一DynamicApiActionInfo集合。
- internal class DynamicApiControllerInfo
- {
- /// <summary>
- /// Name of the service.
- /// </summary>
- public string ServiceName { get; private set; }
- /// <summary>
- /// Controller type.
- /// </summary>
- public Type Type { get; private set; }
- /// <summary>
- /// Dynamic Action Filters for this controller.
- /// </summary>
- public IFilter[] Filters { get; set; }
- /// <summary>
- /// All actions of the controller.
- /// </summary>
- public IDictionary<string, DynamicApiActionInfo> Actions { get; private set; }
- /// <summary>
- /// Creates a new <see cref="DynamicApiControllerInfo"/> instance.
- /// </summary>
- /// <param name="serviceName">Name of the service</param>
- /// <param name="type">Controller type</param>
- /// <param name="filters">Filters</param>
- public DynamicApiControllerInfo(string serviceName, Type type, IFilter[] filters = null)
- {
- ServiceName = serviceName;
- Type = type;
- Filters = filters ?? new IFilter[] { }; //Assigning or initialzing the action filters.
- Actions = new Dictionary<string, DynamicApiActionInfo>(StringComparer.InvariantCultureIgnoreCase);
- }
- }
在执行AbpHttpControllerSelector, AbpApiControllerActionSelector, AbpControllerActivator的时候,系统已经在初始化的时候对服务层进行了分析与缓存。
在作者给的Demo SimpleTaskSystem下有一模块类SimpleTaskSystemWebApiModule
- [DependsOn(typeof(AbpWebApiModule))] //We declare depended modules explicitly
- public class SimpleTaskSystemWebApiModule : AbpModule
- {
- public override void Initialize()
- {
- //This code is used to register classes to dependency injection system for this assembly using conventions.
- IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
- //Creating dynamic Web Api Controllers for application services.
- //Thus, 'web api layer' is created automatically by ABP.
- DynamicApiControllerBuilder
- .ForAll<IApplicationService>(Assembly.GetAssembly(typeof (SimpleTaskSystemApplicationModule)), "tasksystem")
- .Build();
- }
- }
在这里是使用到了DynamicApiControllerBuilder,这个类主要是对服务接口进行一个注册,再由IBatchApiControllerBuilder按照注册的服务接口对提供的程序集进行分析。
DynamicApiControllerBuilder提供的ForAll只是返回的一个IBatchApiControllerBuilder实现对象
- public static IBatchApiControllerBuilder<T> ForAll<T>(Assembly assembly, string servicePrefix)
- {
- return new BatchApiControllerBuilder<T>(assembly, servicePrefix);
- }
这个方法为BatchApiControllerBuilder提供了服务接口与服务接口与需要分析的程序集,以及服务地址前缀。
BatchApiControllerBuilder从程序集中获取实现服务接口的非抽象类。BatchApiControllerBuilder再通过DynamicApiControllerBuilder将这些类与服务名信息传递给IApiControllerBuilder。
- public void Build()
- {
- var types =
- from
- type in _assembly.GetTypes()
- where
- type.IsPublic && type.IsInterface && typeof(T).IsAssignableFrom(type) && IocManager.Instance.IsRegistered(type)
- select
- type;
- if (_typePredicate != null)
- {
- types = types.Where(t => _typePredicate(t));
- }
- foreach (var type in types)
- {
- var serviceName = _serviceNameSelector != null
- ? _serviceNameSelector(type)
- : GetConventionalServiceName(type);
- if (!string.IsNullOrWhiteSpace(_servicePrefix))
- {
- serviceName = _servicePrefix + "/" + serviceName;
- }
- var builder = typeof(DynamicApiControllerBuilder)
- .GetMethod("For", BindingFlags.Public | BindingFlags.Static)
- .MakeGenericMethod(type)
- .Invoke(null, new object[] { serviceName });
- if (_filters != null)
- {
- builder.GetType()
- .GetMethod("WithFilters", BindingFlags.Public | BindingFlags.Instance)
- .Invoke(builder, new object[] { _filters });
- }
- builder.GetType()
- .GetMethod("Build", BindingFlags.Public | BindingFlags.Instance)
- .Invoke(builder, new object[0]);
- }
- }
IApiControllerBuilder将通过服务类生成DynamicApiControllerInfo,再将IApiControllerBuilder存储于DynamicApiControllerManager中,同时分析服务类,将公开非静态方法作为action,存储到DynamicApiControllerManager.Actions
- internal class ApiControllerBuilder<T> : IApiControllerBuilder<T>
- {
- /// <summary>
- /// Name of the controller.
- /// </summary>
- private readonly string _serviceName;
- /// <summary>
- /// List of all action builders for this controller.
- /// </summary>
- private readonly IDictionary<string, ApiControllerActionBuilder<T>> _actionBuilders;
- /// <summary>
- /// Action Filters to apply to the whole Dynamic Controller.
- /// </summary>
- private IFilter[] _filters;
- /// <summary>
- /// Creates a new instance of ApiControllerInfoBuilder.
- /// </summary>
- /// <param name="serviceName">Name of the controller</param>
- public ApiControllerBuilder(string serviceName)
- {
- if (string.IsNullOrWhiteSpace(serviceName))
- {
- throw new ArgumentException("serviceName null or empty!", "serviceName");
- }
- if (!DynamicApiServiceNameHelper.IsValidServiceName(serviceName))
- {
- throw new ArgumentException("serviceName is not properly formatted! It must contain a single-depth namespace at least! For example: 'myapplication/myservice'.", "serviceName");
- }
- _serviceName = serviceName;
- _actionBuilders = new Dictionary<string, ApiControllerActionBuilder<T>>();
- foreach (var methodInfo in DynamicApiControllerActionHelper.GetMethodsOfType(typeof(T)))
- {
- _actionBuilders[methodInfo.Name] = new ApiControllerActionBuilder<T>(this, methodInfo);
- }
- }
- /// <summary>
- /// The adds Action filters for the whole Dynamic Controller
- /// </summary>
- /// <param name="filters"> The filters. </param>
- /// <returns>The current Controller Builder </returns>
- public IApiControllerBuilder<T> WithFilters(params IFilter[] filters)
- {
- _filters = filters;
- return this;
- }
- /// <summary>
- /// Used to specify a method definition.
- /// </summary>
- /// <param name="methodName">Name of the method in proxied type</param>
- /// <returns>Action builder</returns>
- public IApiControllerActionBuilder<T> ForMethod(string methodName)
- {
- if (!_actionBuilders.ContainsKey(methodName))
- {
- throw new AbpException("There is no method with name " + methodName + " in type " + typeof(T).Name);
- }
- return _actionBuilders[methodName];
- }
- /// <summary>
- /// Builds the controller.
- /// This method must be called at last of the build operation.
- /// </summary>
- public void Build()
- {
- var controllerInfo = new DynamicApiControllerInfo(_serviceName, typeof(DynamicApiController<T>), _filters);
- foreach (var actionBuilder in _actionBuilders.Values)
- {
- if (actionBuilder.DontCreate)
- {
- continue;
- }
- controllerInfo.Actions[actionBuilder.ActionName] = actionBuilder.BuildActionInfo();
- }
- IocManager.Instance.IocContainer.Register(
- Component.For<AbpDynamicApiControllerInterceptor<T>>().LifestyleTransient(),
- Component.For<DynamicApiController<T>>().Proxy.AdditionalInterfaces(new[] { typeof(T) }).Interceptors<AbpDynamicApiControllerInterceptor<T>>().LifestyleTransient()
- );
- DynamicApiControllerManager.Register(controllerInfo);
- LogHelper.Logger.DebugFormat("Dynamic web api controller is created for type '{0}' with service name '{1}'.", typeof(T).FullName, controllerInfo.ServiceName);
- }
- }
ABP之动态WebAPI(一)的更多相关文章
- ABP源码分析三十五:ABP中动态WebAPI原理解析
动态WebAPI应该算是ABP中最Magic的功能之一了吧.开发人员无须定义继承自ApiController的类,只须重用Application Service中的类就可以对外提供WebAPI的功能, ...
- ABP中动态WebAPI原理解析
ABP中动态WebAPI原理解析 动态WebAPI应该算是ABP中最Magic的功能之一了吧.开发人员无须定义继承自ApiController的类,只须重用Application Service中的类 ...
- ABP之动态WebAPI
ABP之动态WebAPI ABP的动态WebApi实现了直接对服务层的调用(其实病没有跨过ApiController,只是将ApiController公共化,对于这一点的处理类似于MVC,对服务端的 ...
- ABP之动态WebAPI(二)
HttpControllerDescriptor与HttpActionDescriptor HttpControllerDescriptor封装了某个HttpController类型的元数据,我们可以 ...
- 动态WebApi
动态WebApi实现了直接对Service的调用,其实没有跨过ApiController,只是我们自己创建出ApiController 实现主要分以下几步 一 对默认WebApi服务的替换 ApiGl ...
- ABP项目中使用Swagger生成动态WebAPI
本文是根据角落的白板报的<使用ABP实现SwaggerUI,生成动态webapi>一文的学习总结,感谢原文作者角落的白板报. 1 安装Swashbuckle.core 1.1 选择WebA ...
- 最新版ABP 动态WebAPI 日期转json带T的解决方案| ABP DateTIme Json format
ABP动态webapi返回的json数据中,日期时间带T还有毫秒数的问题,在以往的版本中可以使用下面方法解决: 在XXXAbpWebApiModule中加上下面的代码: 很老的很老的版本有效: pub ...
- [ABP框架]动态web Api的拦截用法。
先进行配置 首先这种需求,一般发生在APP端,我们给APP,不会给所有项目系统的接口给他们用.我们系统有200个接口,但是APP的需求只会用20个.那么这个需求也就应运而生了. 以上为API文件夹中为 ...
- ASP.NET Core 奇淫技巧之动态WebApi
一.前言 接触到动态WebApi(Dynamic Web API)这个词的已有几年,是从ABP框架里面接触到的,当时便对ABP的这个技术很好奇,后面分析了一波,也尝试过从ABP剥离一个出来作为独立组件 ...
随机推荐
- PHP钩子机制
什么是钩子 大家想必听过插件,wordpress插件特别多,这个就是用钩子机制实现的. 当代码在运行的过程中,我们预先在运行的几个特殊点里执行一些特殊方法:例如在运行方法(例如Blog::add的ad ...
- 我所理解的Cocos2d-x
我所理解的Cocos2d-x(完全基于Cocos2d-x3.0,深度剖析计算机图形学,OpenGL ES及游戏引擎架构,全面提升游戏开发相关知识) 秦春林 著 ISBN 978-7-121-246 ...
- MacOS中使用QT开发iOS应用
因为项目合同中规定一部分业务内容要在手机端实现,包括安卓机和苹果机,因此选择了QT作为开发工具.程序在Win10和安卓系统上已经完美运行,这几天开始搭建iOS的编译和发布环境,因为以前没有使用过mac ...
- 使用Event Message 对 Package 进行Troubleshoot
在SSIS Server上,发现一个Package Job运行异常,该Package处于僵死状态.从 Job Activity Monitor中看到该Job一直处于运行状态,但是,DW中没有执行任何Q ...
- JavaScript JsTree实例
var RightTree= function () { }; RightTree.prototype = { //初始化权限树 InitRightTree: function () { $.ajax ...
- NFS Volume Provider(Part I) - 每天5分钟玩转 OpenStack(62)
cinder-volume 支持多种 volume provider,前面我们一直使用的是默认的 LVM,本节我们将增加 NFS volume provider. 虽然 NFS 更多地应用在实验或小规 ...
- MySQL学习笔记五:数据类型
MySQL支持多种数据类型,大致可以分为数值,日期/时间和字符类型. 数值类型 MySQL支持所有标准SQL数值数据类型,包括严格数值数据类型(INTEGER.SMALLINT.DECIMAL和NUM ...
- 包含块( Containing block ) 转自W3CHelp
包含块简介 在 CSS2.1 中,很多框的定位和尺寸的计算,都取决于一个矩形的边界,这个矩形,被称作是包含块( containing block ). 一般来说,(元素)生成的框会扮演它子孙元素包含块 ...
- ZOJ Problem Set - 1241 Geometry Made Simple
水题不解释 #include <stdio.h> #include <math.h> int main() { ,flag=; double a,b,c; while(scan ...
- hibernate笔记--单(双)向的多对多映射关系
在讲单向的多对多的映射关系的案例时,我们假设我们有两张表,一张角色表Role,一张权限表Function,我们知道一个角色或者说一个用户,可能有多个操作权限,而一种操作权限同时被多个用户所拥有,假如我 ...