ABP动态生成WebAPI
ABP框架可以动态生成WebApi,开发人员无需创建APIController,直接继承IApplicationService接口,即可对外发布webApi。
创建动态Web Api 控制器
例如,在Service层有一个ITestService接口,如下:
public interface ITestService : IApplicationService{List<int> GetTestMethod();string GetAll();string GetById(int id);}
该接口实现了“IApplicationService”接口,在该框架中,我们无需构建TestServiceApiController就可以对外发布webapi。用户可以直接通过访问“api/services/app/TestService/GetTestMethod”实现api 访问。
实现原理:
模块初始化阶段,注册动态API实现模块,在批量/单个注册方法中,执行“BatchApiControllerBuilder”的“Build”方法,遍历Application层程序集,查找所有已注册接口类型。然后根据类型信息获取服务名称,生成单个“ApiControllerBuilder”实例,依次执行“ApiControllerBuilder”中的方法。其中生成“action”是在“Builder”中实现的。
在“ApiControllerBuilder”的“Builder”方法中”,通过“Build”方法构建apiinfo信息并将“action”添加到controller中,最后在apicontroller管理类中注册controller信息。
以下对类和接口逐一分析
AbpApiController:集成了ApiController,框架中自定义的apicontroller都继承自该类;
IDynamicApiController:空接口,生成DynamicApiController标识;
DynamicApiController<T>:动态生成ApiController类,继承自“AbpApiController”,“IDynamicApiController”;
1 public class DynamicApiController<T>: AbpApiController, IDynamicApiController 2 { 3 public List<string> AppliedCrossCuttingConcerns { get; } 4 public DynamicApiController() 5 { 6 AppliedCrossCuttingConcerns = new List<string>(); 7 } 8 }
DynamicApiControllerInfo:封装ApiController基本信息,其中以字典的形式存储了“DynamicApiActionInfo”;
1 public DynamicApiControllerInfo( 2 string serviceName, 3 Type serviceInterfaceType, 4 Type apiControllerType, 5 Type interceptorType, 6 IFilter[] filters = null, 7 bool? isApiExplorerEnabled = null, 8 bool isProxyScriptingEnabled = true) 9 { 10 ServiceName = serviceName; 11 ServiceInterfaceType = serviceInterfaceType; 12 ApiControllerType = apiControllerType; 13 InterceptorType = interceptorType; 14 IsApiExplorerEnabled = isApiExplorerEnabled; 15 IsProxyScriptingEnabled = isProxyScriptingEnabled; 16 Filters = filters ?? new IFilter[] { }; //Assigning or initialzing the action filters. 17 Actions = new Dictionary<string, DynamicApiActionInfo>(StringComparer.InvariantCultureIgnoreCase); 18 }
IBatchApiControllerBuilder<T>/BatchApiControllerBuilder<T>:批量ApiController构建器,通过“Build”方法,根据程序集,批量生成“DynamicApiControllerInfo”;
internal class BatchApiControllerBuilder<T> : IBatchApiControllerBuilder<T>{#region 声明实例private readonly string _servicePrefix;private readonly Assembly _assembly;private IFilter[] _filters;private Func<Type, string> _serviceNameSelector;private Func<Type, bool> _typePredicate;private bool _conventionalVerbs;private Action<IApiControllerActionBuilder<T>> _forMethodsAction;private bool? _isApiExplorerEnabled;private readonly IIocResolver _iocResolver;private readonly IDynamicApiControllerBuilder _dynamicApiControllerBuilder;private bool? _isProxyScriptingEnabled;#endregion#region 构造函数public BatchApiControllerBuilder(IIocResolver iocResolver,IDynamicApiControllerBuilder dynamicApiControllerBuilder,Assembly assembly,string servicePrefix){_iocResolver = iocResolver;_dynamicApiControllerBuilder = dynamicApiControllerBuilder;_assembly = assembly;_servicePrefix = servicePrefix;}#endregion#region 方法public void Build(){var types =from type in _assembly.GetTypes()where (type.IsPublic || type.IsNestedPublic) &&type.IsInterface &&typeof(T).IsAssignableFrom(type) &&_iocResolver.IsRegistered(type) &&!RemoteServiceAttribute.IsExplicitlyDisabledFor(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(IDynamicApiControllerBuilder).GetMethod("For", BindingFlags.Public | BindingFlags.Instance).MakeGenericMethod(type).Invoke(_dynamicApiControllerBuilder, new object[] { serviceName });if (_filters != null){builder.GetType().GetMethod("WithFilters", BindingFlags.Public | BindingFlags.Instance).Invoke(builder, new object[] { _filters });}if (_isApiExplorerEnabled != null){builder.GetType().GetMethod("WithApiExplorer", BindingFlags.Public | BindingFlags.Instance).Invoke(builder, new object[] { _isApiExplorerEnabled });}if (_isProxyScriptingEnabled != null){builder.GetType().GetMethod("WithProxyScripts", BindingFlags.Public | BindingFlags.Instance).Invoke(builder, new object[] { _isProxyScriptingEnabled.Value });}if (_conventionalVerbs){builder.GetType().GetMethod("WithConventionalVerbs", BindingFlags.Public | BindingFlags.Instance).Invoke(builder, new object[0]);}if (_forMethodsAction != null){builder.GetType().GetMethod("ForMethods", BindingFlags.Public | BindingFlags.Instance).Invoke(builder, new object[] { _forMethodsAction });}builder.GetType().GetMethod("Build", BindingFlags.Public | BindingFlags.Instance).Invoke(builder, new object[0]);}}private string GetConventionalServiceName(Type type){var typeName = type.Name;typeName = typeName.RemovePostFix(ApplicationService.CommonPostfixes);if (typeName.Length > 1 && typeName.StartsWith("I") && char.IsUpper(typeName, 1)){typeName = typeName.Substring(1);}return typeName.ToCamelCase();}public IBatchApiControllerBuilder<T> ForMethods(Action<IApiControllerActionBuilder> action){_forMethodsAction = action;return this;}public IBatchApiControllerBuilder<T> Where(Func<Type, bool> predicate){_typePredicate = predicate;return this;}public IBatchApiControllerBuilder<T> WithApiExplorer(bool isEnabled){_isApiExplorerEnabled = isEnabled;return this;}public IBatchApiControllerBuilder<T> WithConventionalVerbs(){_conventionalVerbs = true;return this;}public IBatchApiControllerBuilder<T> WithFilters(params IFilter[] filters){_filters = filters;return this;}public IBatchApiControllerBuilder<T> WithProxyScripts(bool isEnabled){_isProxyScriptingEnabled = isEnabled;return this;}public IBatchApiControllerBuilder<T> WithServiceName(Func<Type, string> serviceNameSelector){_serviceNameSelector = serviceNameSelector;return this;}#endregion}
View Code
DynamicApiControllerBuilder/IDynamicApiControllerBuilder:动态ApiController构建器。“For”方法构建了“ApiControllerBuilder”实例;“ForAll”生成了“BatchApiControllerBuilder”,用于批量生成“DynamicApiControllerInfo”实例;
IApiControllerBuilder/ApiControllerBuilder:单个ApiController构建器,每个ABPApiCon以troller中存储了“Action”的基本信息。通过“Build”方法,生成“DynamicApiControllerInfo”实例,然后遍历“Action”,添加到“IDictionary<string, ApiControllerActionBuilder<T>>”字典中;
1 public void Build() 2 { 3 var controllerInfo = new DynamicApiControllerInfo( 4 ServiceName, 5 ServiceInterfaceType, 6 typeof(DynamicApiController<T>), 7 typeof(AbpDynamicApiControllerInterceptor<T>), 8 Filters, 9 IsApiExplorerEnabled, 10 IsProxyScriptingEnabled 11 ); 12 foreach (var actionBuilder in _actionBuilders.Values) 13 { 14 if (actionBuilder.DontCreate) 15 { 16 continue; 17 } 18 controllerInfo.Actions[actionBuilder.ActionName] = actionBuilder.BuildActionInfo(ConventionalVerbs); 19 20 } 21 _iocResolver.Resolve<DynamicApiControllerManager>().Register(controllerInfo); 22 }
DynamicApiActionInfo:封装了“Action”名称、请求方式等基本信息;
1 /// <summary> 2 /// 封装动态生成的ApiController的Action的信息 3 /// </summary> 4 public class DynamicApiActionInfo 5 { 6 /// <summary> 7 /// action 名称 8 /// </summary> 9 public string ActionName { get; private set; } 10 /// <summary> 11 /// 方法信息 12 /// </summary> 13 public MethodInfo Method { get; private set; } 14 public HttpVerb Verb { get; private set; } 15 /// <summary> 16 /// 过滤器 17 /// </summary> 18 public IFilter[] Filters { get; set; } 19 /// <summary> 20 /// Is API Explorer enabled. 21 /// </summary> 22 public bool? IsApiExplorerEnabled { get; set; } 23 /// <summary> 24 /// 构造函数 25 /// </summary> 26 /// <param name="actionName"></param> 27 /// <param name="verb"></param> 28 /// <param name="method"></param> 29 /// <param name="filters"></param> 30 /// <param name="isApiExplorerEnabled"></param> 31 public DynamicApiActionInfo( 32 string actionName, 33 HttpVerb verb, 34 MethodInfo method, 35 IFilter[] filters = null, 36 bool? isApiExplorerEnabled = null) 37 { 38 ActionName = actionName; 39 Verb = verb; 40 Method = method; 41 IsApiExplorerEnabled = isApiExplorerEnabled; 42 Filters = filters ?? new IFilter[] { }; //Assigning or initialzing the action filters. 43 } 44 }
IApiControllerActionBuilder/ApiControllerActionBuilder:“ApiActionController”构建器,生成“DynamicApiActionInfo”对象;
DynamicApiControllerManager:ApiController管理类,以字典的形式,管理控制器。当浏览器接受到“HttpRouteData”请求时,程序根据服务的名称从该类中查找相应的controller;
DynamicHttpControllerDescriptor:继承自“HttpControllerDescriptor”;
AbpHttpControllerSelector:继承自“DefaultHttpControllerSelector”,重写了“SelectController”方法,返回新的“HttpControllerDescriptor”。在该类中,根据路由信息中的服务类名称,查找制定的“DynamicApiControllerInfo”;
AbpApiControllerActionSelector:继承自ASP.Net WebAPI 的 ApiControllerActionSelector,AbpApiControllerActionSelector 通过调用DynamicApiServiceNameHelper的静态方法(传入routedata中的serviceNameWithAction)获取action实例;
AbpApiControllerActivator :实现了 IHttpControllerActivator接口,根据controller的类型生成指定的controller;
AbpDynamicApiControllerInterceptor<T> :方法拦截器,拦截“Action”请求,调用服务层中的方法。
try{ invocation.ReturnValue=invocation.Method.Invoke(_proxiedObject, invocation.Arguments);}catch (TargetInvocationException targetInvocation){if (targetInvocation.InnerException != null){targetInvocation.InnerException.ReThrow();}throw;}
拦截器在模块的初始化阶段注册:
1 public override void PostInitialize() 2 { 3 var httpConfiguration= IocManager.Resolve<IAbpWebApiConfiguration>().HttpConfiguration; 4 InitializeRoutes(httpConfiguration); 5 InitializeAspNetServices(httpConfiguration); 6 7 foreach (var controllerInfo in IocManager.Resolve<DynamicApiControllerManager>().GetAll()) 8 { 9 IocManager.IocContainer.Register( 10 Component.For(controllerInfo.InterceptorType).LifestyleTransient(), 11 Component.For(controllerInfo.ApiControllerType) 12 .Proxy.AdditionalInterfaces(controllerInfo.ServiceInterfaceType) 13 .Interceptors(controllerInfo.InterceptorType) 14 .LifestyleTransient() 15 ); 16 17 //LogHelper.Logger.DebugFormat("Dynamic web api controller is created for type '{0}' with service name '{1}'.", controllerInfo.ServiceInterfaceType.FullName, controllerInfo.ServiceName); 18 } 19 20 Configuration.Modules.AbpWebApi().HttpConfiguration.EnsureInitialized(); 21 //base.PostInitialize(); 22 }
转载于:https://www.cnblogs.com/SecondSun/p/9275184.html
ABP动态生成WebAPI相关推荐
- WebAPI(part10)--动态生成表格
学习笔记,仅供参考,有错必究 文章目录 动态生成表格 动态生成表格 从本地取到数据,动态生成表格,并添加删除操作. 代码: <!DOCTYPE html> <html>< ...
- ABP动态配置数据库连接字符串 Oracle11g数据库
ABP动态配置数据库连接 Oracle11g数据库 ABP的仓储关于数据库连接字符串的配置是从web.config(app.config)的connectionStrings读取的. 我想实现的功能是 ...
- 【转载】 Python动态生成变量
用Python循环创建多个变量, 如创建 a1= .a2= .a3= .a4= .a5= 或 self.a1= .self.a2= . self.a3= 一. 可以通 ...
- Asp.net动态生成html页面
作者:网际浪子专栏(曾用名littlehb) http://blog.csdn.net/littlehb/ 适用于:Microsoft ASP.NET 摘要:asp.net动态生成html页面,适用 ...
- awstats CGI模式下动态生成页面缓慢的改进
本文可以看做是 多server多站点情况下awstats日志分析 这篇文章的下篇,在使用过程中发现awstats在cgi模式下动态生成分析报告慢的问题 (尤其是有些站点每天两个多G的日志,查看起来简直 ...
- 使用Vue动态生成form表单的实例代码
具有数据收集.校验和提交功能的表单生成器,包含复选框.单选框.输入框.下拉选择框等元素以及,省市区三级联动,时间选择,日期选择,颜色选择,文件/图片上传功能,支持事件扩展. 欢迎大家star学习交流: ...
- jquery动态生成SKU表格
sku的概念 SKU=Stock Keeping Unit(库存量单位).即库存进出计量的基本单元,可以是以件,盒,托盘等为单位.SKU这是对于大型连锁超市DC(配送中心)物流管理的一个必要的方法.现 ...
- html指定表格行列书,js动态生成指定行数的表格
下面用js实现可以生成用户所需行数的表格. 1.首先在body中填入下列代码,获取用户填入的行数值 动态生成表格 行 效果如下图所示: 2.header中添加js代码 function table() ...
- 使用未编译的XAML动态生成WPF控件
我们所经常使用的WPF界面大部分都是使用XAML文件进行定义编写,然后经编译生成窗体和控件,还有的就是在后台代码中定义控件和元素-这些都是在程序编译后已经固化不变的了-如果想要在程序编译后再使用XAM ...
最新文章
- 离群点检测算法-基础概念
- 计算机组成原理 — ARM 体系结构
- Maven(八)Eclipse创建Web项目(复杂方式)
- 每日冲刺报告——Day4(Java-Team)
- .NET的可调信号量
- Rust跨界前端全攻略
- C语言餐馆点菜系统设计,order-system 使用c语言设计的餐厅点菜系统 - 下载 - 搜珍网...
- 2019年最好用的6款数据库监控工具
- python入门第二十五天--反射 通过字符串的形式操作对象中的成员
- 汇编语言集成开发环境 RadASM 中文版 (修复object file not found报错)
- 华北电力大学\华电计算机考研复试经验分享
- 知识分享 | 什么是CAN线波特率
- xp计算机无法关机,WindowsXP电脑无法关机?6招轻松解决故障
- MRT退休后的HEG(HDF-EOS To GeoTIFF Conversion Tool )工具安装
- python选题背景_论文的选题背景及意义-样例
- 《英语(二)》作文案例
- vue利用 vue-animate-number插件动态展示数字(从0动态滚动到指定数字)
- Linux网络相关命令:netstat,ss
- 各种食用油的正确烹饪方法
- Python 使用PIL.Image制作一个运动小人的动态图
热门文章
- call指令和ret指令(1001)
- Nodejs实现的一个静态服务器例子
- POJ 2455 Secret Milking Machine
- [转]vim 如何编辑 GB2312 编码的文件?
- ubuntu安装ssh无法连接解决日志(已解决,可连接)-转
- mysql复制部署_MYSQL-主从复制部署
- 蓝桥杯 AGLO-152 算法训练 8-2求完数
- CCCC-GPLT L3-015. 球队“食物链” 团体程序设计天梯赛
- iOS开发之touchesCancelled
- java如何解析图片里面文字_如何识别图片中的文字 讯飞输入法文字扫描快捷翻译教程...