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相关推荐

  1. WebAPI(part10)--动态生成表格

    学习笔记,仅供参考,有错必究 文章目录 动态生成表格 动态生成表格 从本地取到数据,动态生成表格,并添加删除操作. 代码: <!DOCTYPE html> <html>< ...

  2. ABP动态配置数据库连接字符串 Oracle11g数据库

    ABP动态配置数据库连接 Oracle11g数据库 ABP的仓储关于数据库连接字符串的配置是从web.config(app.config)的connectionStrings读取的. 我想实现的功能是 ...

  3. 【转载】 Python动态生成变量

    用Python循环创建多个变量, 如创建 a1=   .a2=   .a3=   .a4=   .a5=    或  self.a1=    .self.a2=   . self.a3= 一. 可以通 ...

  4. Asp.net动态生成html页面

    作者:网际浪子专栏(曾用名littlehb)  http://blog.csdn.net/littlehb/ 适用于:Microsoft ASP.NET 摘要:asp.net动态生成html页面,适用 ...

  5. awstats CGI模式下动态生成页面缓慢的改进

    本文可以看做是 多server多站点情况下awstats日志分析 这篇文章的下篇,在使用过程中发现awstats在cgi模式下动态生成分析报告慢的问题 (尤其是有些站点每天两个多G的日志,查看起来简直 ...

  6. 使用Vue动态生成form表单的实例代码

    具有数据收集.校验和提交功能的表单生成器,包含复选框.单选框.输入框.下拉选择框等元素以及,省市区三级联动,时间选择,日期选择,颜色选择,文件/图片上传功能,支持事件扩展. 欢迎大家star学习交流: ...

  7. jquery动态生成SKU表格

    sku的概念 SKU=Stock Keeping Unit(库存量单位).即库存进出计量的基本单元,可以是以件,盒,托盘等为单位.SKU这是对于大型连锁超市DC(配送中心)物流管理的一个必要的方法.现 ...

  8. html指定表格行列书,js动态生成指定行数的表格

    下面用js实现可以生成用户所需行数的表格. 1.首先在body中填入下列代码,获取用户填入的行数值 动态生成表格 行 效果如下图所示: 2.header中添加js代码 function table() ...

  9. 使用未编译的XAML动态生成WPF控件

    我们所经常使用的WPF界面大部分都是使用XAML文件进行定义编写,然后经编译生成窗体和控件,还有的就是在后台代码中定义控件和元素-这些都是在程序编译后已经固化不变的了-如果想要在程序编译后再使用XAM ...

最新文章

  1. 离群点检测算法-基础概念
  2. 计算机组成原理 — ARM 体系结构
  3. Maven(八)Eclipse创建Web项目(复杂方式)
  4. 每日冲刺报告——Day4(Java-Team)
  5. .NET的可调信号量
  6. Rust跨界前端全攻略
  7. C语言餐馆点菜系统设计,order-system 使用c语言设计的餐厅点菜系统 - 下载 - 搜珍网...
  8. 2019年最好用的6款数据库监控工具
  9. python入门第二十五天--反射 通过字符串的形式操作对象中的成员
  10. 汇编语言集成开发环境 RadASM 中文版 (修复object file not found报错)
  11. 华北电力大学\华电计算机考研复试经验分享
  12. 知识分享 | 什么是CAN线波特率
  13. xp计算机无法关机,WindowsXP电脑无法关机?6招轻松解决故障
  14. MRT退休后的HEG(HDF-EOS To GeoTIFF Conversion Tool )工具安装
  15. python选题背景_论文的选题背景及意义-样例
  16. 《英语(二)》作文案例
  17. vue利用 vue-animate-number插件动态展示数字(从0动态滚动到指定数字)
  18. Linux网络相关命令:netstat,ss
  19. 各种食用油的正确烹饪方法
  20. Python 使用PIL.Image制作一个运动小人的动态图

热门文章

  1. call指令和ret指令(1001)
  2. Nodejs实现的一个静态服务器例子
  3. POJ 2455 Secret Milking Machine
  4. [转]vim 如何编辑 GB2312 编码的文件?
  5. ubuntu安装ssh无法连接解决日志(已解决,可连接)-转
  6. mysql复制部署_MYSQL-主从复制部署
  7. 蓝桥杯 AGLO-152 算法训练 8-2求完数
  8. CCCC-GPLT L3-015. 球队“食物链” 团体程序设计天梯赛
  9. iOS开发之touchesCancelled
  10. java如何解析图片里面文字_如何识别图片中的文字 讯飞输入法文字扫描快捷翻译教程...