• ABP之动态WebAPI(一)


    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}"
                    );
            }
    View Code

     

    对服务的分析与缓存

    再对服务信息的存储上,作者提供了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);
            }
        }
    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);
            }
        }
    

      

  • 相关阅读:
    MYSQL查询和插入数据的流程是怎样的
    Nacos服务心跳和健康检查源码介绍
    Nacos使用和注册部分源码介绍
    实用程序包utils
    SOLID原则
    前端实用程序包utils
    实现 strStr()
    记一次华为机试
    十分钟入门 Python 教程
    字符串转换整数 (atoi)
  • 原文地址:https://www.cnblogs.com/gangtianci/p/4691150.html
Copyright © 2020-2023  润新知