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

1.创建控制器的过程依赖众多不同的提供者和工厂类,但最终是由实现IControllerActivator接口的实例来决定的。实现类只需要实现两个方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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容器中,实现方法注入与属性注入都是先要标记特性所以我们第一步,先新建两个特性
 
代表属性注入的特性
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System;
using System.Collections.Generic;
using System.Text;
 
namespace GreenUnity.Common.Attributes
{
    /// <summary>
    /// 限制特性只能标记在属性上(该特性什么都不做,只用来标记属性注入)
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class PropertyInjectionAttribute:Attribute
    {
 
    }
}

  

代表方法注入的特性
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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方法里做属性注入与方法注入的实现。注意此扩展方法未解决循环依赖问题
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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实现
1
2
3
4
5
6
7
8
9
10
11
#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.到此已经配置扩展完成,在需要属性注入和方法注入的地方加上特性就行。扩展的方法可以自动注入
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// <summary>
/// 属性注入
/// </summary>
[PropertyInjection]
private UnitOfWork unitOfWork { get; set; }
 
/// <summary>
/// 方法注入
/// </summary>
private ILogger<UserController> Logger = null;
[MethodInjection]
 private void MethodInjection(ILogger<UserController> _logger)
{
  Logger = _logger;
}

  

posted @   存在丶  阅读(655)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示