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(一)的更多相关文章

  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. 我心中的核心组件(可插拔的AOP)~大话开篇及目录

    回到占占推荐博客索引 核心组件 我心中的核心组件,核心组件就是我认为在项目中比较常用的功能,如日志,异常处理,消息,邮件,队列服务,调度,缓存,持久化,分布式文件存储,NoSQL存储,IoC容器,方法 ...

  2. Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析

    Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析     Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析1 存 ...

  3. C++ 回调函数 实现 的测试代码

    最近项目里使用了异步Socket,使用的是完成端口做的e; Accept,receive,send 等完全的异步实现(多线程) 然后 又要多个端口使用, 后来想到包装下完成端口Socket,然后当有事 ...

  4. 搜狗输入法wp风格皮肤

    换了个nexus 发现输入法真的没有wp的好用 没办法,刚好搜狗输入法有定制皮肤的选项,所以自己做了个wp风格的输入法皮肤. 一点微小的工作 http://pan.baidu.com/s/1kVsHd ...

  5. 实战Hybird app:内存溢出与优化

    pheongap项目:http://www.nduoa.com/apk/detail/646816 主要的问题: heap过大,内存低性能差的机子上引起奔溃,直接退出 关于web app的优化,不仅仅 ...

  6. ActionScript 3.0入门:Hello World、文件读写、数据存储(SharedObject)、与JS互调

    近期项目中可能要用到Flash存取数据,并与JS互调,所以就看了一下ActionScript 3.0,现把学习结果分享一下,希望对新手有帮助. 目录 ActionScript 3.0简介 Hello ...

  7. MVC5 网站开发实践 概述

    目录 MVC5 网站开发实践  概述 MVC5 网站开发实践  1.建立项目 MVC5 网站开发实践  2.后台管理 MVC5 网站开发实践  2.1.管理员登陆 MVC5 网站开发实践 2.2.管理 ...

  8. MongoDB学习系列(1)--入门介绍

    MongoDB是一款为Web应用程序设计的面向文档结构的数据库系统. MongoDB贡献者是10gen公司.地址:http://www.10gen.com 1.MongoDB主要特性: 1.1文档数据 ...

  9. Objective-C中的Block回调模式

    在前面的博客中提到了Block的概念和使用方法,个人感觉Block最爽的用法莫过于在回调时用block.感觉比委托回调和目标方法回调用着要顺手,好不好用还得读者亲自用一下才知道.如果 读者之前用过SS ...

  10. 如何搭建Percona XtraDB Cluster集群

    一.环境准备 主机IP                     主机名               操作系统版本     PXC 192.168.244.146     node1           ...