转载

ABP之动态WebAPI(一)

ABP的动态WebApi实现了直接对服务层的调用(其实病没有跨过ApiController,只是将ApiController公共化,对于这一点的处理类似于MVC,对服务端的 调用没有跨过HttpHandler一样),这样不仅减少了ApiController的开发,也更能体现驱动领域设计的层结构。

对WebApi服务的替换与路由配置

AbpWebApiModule是Abp.Web.Api的模块类,该类中定义InitializeAspNetServices,InitializeRoutes两个方法,并且在模块的Initialize方法中执行,这两个方法分别是对WebApi的服务的替换与路由的配置,。这两处对WebApi的变更才使得直接调用服务层成为可能。

ABP之动态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}"   );  } 
View Code

对服务的分析与缓存

再对服务信息的存储上,作者提供了 DynamicApiControllerInfo,DynamicApiActionInfo(源码中的DynamicApiMethodInfo.cs),其中DynamicApiControllerInfo包含了一DynamicApiActionInfo集合。

ABP之动态WebAPI(一)
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);  }     } 
View Code

在执行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);  } } 
正文到此结束
Loading...