zoukankan      html  css  js  c++  java
  • 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         }
  • 相关阅读:
    Mac MySql突然不好用了,说权限不够
    关闭Nginx的进程
    Mac 设置域名解析
    Docker的Yml文件
    Docker遇到的异常和注意点
    MySQL 查询时间段内的数据
    golang martini 源码阅读笔记之martini核心
    golang martini 源码阅读笔记之inject
    使用erlang实现简单的二进制通信协议
    使用 erlang OTP 模式编写非阻塞的 tcp 服务器(来自erlang wiki)
  • 原文地址:https://www.cnblogs.com/SecondSun/p/9275184.html
Copyright © 2011-2022 走看看