• ASP.NET CORE 重写IControllerActivator实现默认IOC属性与方法注入


    1.创建控制器的过程依赖众多不同的提供者和工厂类,但最终是由实现IControllerActivator接口的实例来决定的。实现类只需要实现两个方法:
     public interface IControllerActivator
        {
            //
            // 摘要:
            //     Creates a controller.
            //
            // 参数:
            //   context:
            //     The Microsoft.AspNetCore.Mvc.ControllerContext for the executing action.
            object Create(ControllerContext context);
            //
            // 摘要:
            //     Releases a controller.
            //
            // 参数:
            //   context:
            //     The Microsoft.AspNetCore.Mvc.ControllerContext for the executing action.
            //
            //   controller:
            //     The controller to release.
            void Release(ControllerContext context, object controller);
        }
    

      

    如你所见,该Create方法传递了用于创建控制器的ControllerContext实例。控制器的创建方式取决于具体的实现。
     
    2.在各大第三方IOC容器中,实现方法注入与属性注入都是先要标记特性所以我们第一步,先新建两个特性
     
    代表属性注入的特性
     
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace GreenUnity.Common.Attributes
    {
        /// <summary>
        /// 限制特性只能标记在属性上(该特性什么都不做,只用来标记属性注入)
        /// </summary>
        [AttributeUsage(AttributeTargets.Property)]
        public class PropertyInjectionAttribute:Attribute
        {
    
        }
    }
    

      

    代表方法注入的特性
     
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace GreenUnity.Common.Attributes
    {
        /// <summary>
        /// 限制特性只能标记在方法上(该特性什么都不做,只用来标记方法注入)
        /// </summary>
        [AttributeUsage(AttributeTargets.Method)]
        public class MethodInjectionAttribute:Attribute
        {
    
        }
    }
    

      

    3.前面我们讲过,控制器的实例化是来自于IControllerActivator接口实列的Create方法,我们新建一个类,继承IControllerActivator接口,实现Create方法,在Create方法里做属性注入与方法注入的实现。注意此扩展方法未解决循环依赖问题
     
    using GreenUnity.Common.Attributes;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Controllers;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    
    namespace GreenUnity.Common.Extend
    {
        public class CustomControllerActivator : IControllerActivator
        {
            /// <summary>
            /// 该方法扩展框架IOC属性与方法注入但是未解决循环依赖问题.使用时切勿循环依赖会死循环内存溢出
            /// </summary>
            /// <param name="context"></param>
            /// <returns></returns>
            public object Create(ControllerContext context)
            {
    
    
                //获得框架得服务提供对象,用于实列化控制器
                IServiceProvider serviceProvider = context.HttpContext.RequestServices;
                //获取控制器类型
                Type type = context.ActionDescriptor.ControllerTypeInfo.AsType();
                //实列化控制器
                object Context = serviceProvider.GetService(type);
                //属性注入
                PropertyInjection(type, serviceProvider, Context);
                //方法注入
                MethodInjection(type, serviceProvider, Context);
    
                return Context;//把实列化的控制器返回
    
            }
    
            /// <summary>
            /// 属性注入
            /// </summary>
            /// <param name="type"></param>
            /// <param name="serviceProvider"></param>
            public void PropertyInjection(Type type, IServiceProvider serviceProvider, object Context)
            {
                try
                {
                    //根据自定义特性确定要属性注入的属性。
                    //利用反射获取控制器中应用了PropertyInjectionAttribute的属性。
                    foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance).Where(m => m.IsDefined(typeof(PropertyInjectionAttribute), true)))
                    {
                        Type PropertyType = propertyInfo.PropertyType;//获取当前属性的类型。注:GetType()获取的是当前对象的类型
                        object property = serviceProvider.GetService(PropertyType);//利用框架的服务提供对象 创建对象
    
                        PropertyInjection(PropertyType, serviceProvider, property);//如果有多层注入需要递归创建对象,把当前对象传入。
                        MethodInjection(PropertyType, serviceProvider, property);//如果有多层注入需要递归创建对象,把当前对象传入。
    
                        propertyInfo.SetValue(Context, property);//给属性赋值
                    }
                }
                catch (Exception ex)
                {
    
                }
            }
    
            /// <summary>
            /// 方法注入
            /// </summary>
            /// <param name="type"></param>
            /// <param name="serviceProvider"></param>
            /// <param name="Context"></param>
            public void MethodInjection(Type type, IServiceProvider serviceProvider, object Context)
            {
                try
                {
                    //根据自定义特性确定要方法注入的方法。
                    //利用反射获取控制器中应用了MethodInjectionAttribute特性的方法。
                    foreach (MethodInfo memberInfo in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(m => m.IsDefined(typeof(MethodInjectionAttribute))))
                    {
                        ParameterInfo[] parameterInfos = memberInfo.GetParameters();//获取方法参数列表
                        object[] Parameters = new object[parameterInfos.Length];
                        //循环实列化方法参数
                        for (int i = 0; i < parameterInfos.Length; i++)
                        {
                            Type ParameterType = parameterInfos[i].ParameterType;//获取当前方法参数的类型
                            object Parameter = serviceProvider.GetService(ParameterType);//利用框架的服务提供对象 创建对象
    
    
                            MethodInjection(ParameterType, serviceProvider, Parameter);//如果有多层注入需要递归创建对象,把当前对象传入。
                            PropertyInjection(ParameterType, serviceProvider, Parameter);//如果有多层注入需要递归创建对象,把当前对象传入。
    
                            Parameters[i] = Parameter;//添加到参数实列数组中去
                        }
                        memberInfo.Invoke(Context, Parameters);//执行方法
                    }
                }
                catch (Exception ex)
                {
    
                }
            }
    
    
    
    
            public void Release(ControllerContext context, object controller)
            {
            }
        }
    }
    

      

    4.在Startup的ConfigureServices中替换掉原有的ControllerActivator实现
     #region 替换掉框架自己实现的ControllerActivator
    //1.把控制器当做服务注册到容器中
    services.AddControllersWithViews().AddControllersAsServices();
    //2.找出默认的Activator
    var DefaultActivator = services.FirstOrDefault(m => m.ServiceType == typeof(IControllerActivator));
    //3.移除默认Activator
    services.Remove(DefaultActivator);
    //4.把自己自定义的Activator添加进去
    services.AddTransient<IControllerActivator, CustomControllerActivator>();
    
    #endregion
    

      

    5.到此已经配置扩展完成,在需要属性注入和方法注入的地方加上特性就行。扩展的方法可以自动注入
     
    /// <summary>
    /// 属性注入
    /// </summary>
    [PropertyInjection]
    private UnitOfWork unitOfWork { get; set; }
    
    /// <summary>
    /// 方法注入
    /// </summary>
    private ILogger<UserController> Logger = null;
    [MethodInjection]
     private void MethodInjection(ILogger<UserController> _logger)
    {
      Logger = _logger;
    }
    

      

  • 相关阅读:
    State Management
    排序效率小PK
    ES,ZK,Mysql相关参数优化
    ES翻译之Function Score Query
    打算坚持学习技术的习惯
    面试——并发基础知识1
    码云的GIT操作
    CountDownLatch模拟高并发测试代码
    Bloom Filter的应用
    面试题1—选取同一个字符第一不重复的字符
  • 原文地址:https://www.cnblogs.com/objectnull/p/14134482.html
Copyright © 2020-2023  润新知