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. fc-san

    在SAN网络中,所有的数据传输在高速.高带宽的网络中进行,SAN存储实现的是直接对物理硬件的块级存储访问,提高了存储的性能和升级能力. 早期的SAN采用的是光纤通道(FC,Fibre Channel) ...

  2. MVC validate.js下使用 ajaxSubmit

    首页定义验证实体 using System.ComponentModel.DataAnnotations; using System.Web.Mvc; namespace MvcApplication ...

  3. webBrowser 加载网页

    事件 webBrowser_DocumentCompleted private void webBrowser_DocumentCompleted(object sender, WebBrowserD ...

  4. .Net 转战 Android 4.4 日常笔记(7)--apk的打包与反编译

    apk(android package)就是我们安卓系统的安装文件,可以在模拟器和手机中直接打开安装,从项目中打包apk有几种方式可取 一.最简单的方法(类似我们的winfrom) 只要我们调试或者运 ...

  5. MySQL utf8mb4 字符集:支持 emoji 表情符号

    转载地址:http://www.linuxidc.com/Linux/2013-05/84360.htm 我用他的方法解决了问题,亲测可用,不要用Nnvicat for Mysql去查询编码,在服务器 ...

  6. 应用程序框架实战三十七:Util最新代码更新说明

    离上一篇又过去了一个月,时间比较紧,后续估计会更紧,所以这次将放出更多公共操作类及配套的CodeSmith模板,本篇将简要介绍新放出的重要功能,供有兴趣的同学参考. 重要更新 这一次对两个VS解决方案 ...

  7. 从零开始编写自己的C#框架(2)——开发前准备工作

    没想到写了个前言就受到很多朋友的支持,大家的推荐就是我最大的动力(推荐得我热血沸腾,大家就用推荐来猛砸我吧O^-^O),谢谢大家支持. 其实框架开发大家都知道,不过要想写得通俗点,我个人觉得还是挺吃力 ...

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

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

  9. 遇到 HTTP 错误 403.14 - Forbidden?

    打开 http://localhost:1609 报错: HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容 解决方案一:设置默认首页 在 Web.conf ...

  10. geotrellis使用(二十)geotrellis1.0版本新功能及变化介绍

    目录 前言 变化情况介绍 总结 一.前言        之前版本是0.9或者0.10.1.0.10.2,最近发现更新成为1.0.0-2077839.1.0应该也能称之为正式版了吧.发现其中有很多变化, ...