.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

一、配置Autofac替换内置DI
1、安装Nuget包:Autofac.Extensions.DependencyInjection.
.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

2、Program.cs中加上

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
    //在这里写注入代码
});
.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

二、构造函数注入

新建IUserService,类UserService

public interface IUserService
{
    public string GetUserName();
}
public class UserService:IUserService
{
    public string GetUserName()
    {
        return "张三";
    }
}

在上面的ConfigureContainer方法把UserService注入进来,默认是瞬时注入

瞬时注入

containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerDependency();

单例注入

containerBuilder.RegisterType< UserService >().As< IUserService>().SingleInstance();

生命周期注入

containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerLifetimeScope();
.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

注入试下是否注入成功

.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

调用成功,证明注入成功

三、属性注入

1、把HomeController改成属性注入形式,属性注入有一个问题,就是那些属性需要注入?

全部注入没必要,父类也有很多属性,要按需注入,给属性增加一个自定义特性标识说明需要注入。

public class HomeController : Controller
{
    [AutowiredProperty]
    private IUserService userService { get; set; }
    public IActionResult Index()
    {
        string name = userService.GetUserName();
          return View();
    }
}

2、新增自定义特性类AutowiredPropertyAttribute.cs

[AttributeUsage(AttributeTargets.Property)]
//为了支持属性注入,只能打到属性上
public class AutowiredPropertyAttribute: Attribute
{
}

3、增加识别特性类AutowiredPropertySelector.cs

public class AutowiredPropertySelector : IPropertySelector
{
    public bool InjectProperty(PropertyInfo propertyInfo, object instance)
    {
        //判断属性的特性是否包含自定义的属性,标记有返回true
        return propertyInfo.CustomAttributes.Any(s => s.AttributeType == typeof(AutowiredPropertyAttribute));
    }
}

4、因为Controller 默认是由 Mvc 模块管理的,需要把控制器放到IOC容器中,在Program.cs中增加

//让控制器实例由容器创建
builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());

5、把容器注册到IOC容器,在Program.cs的ConfigureContainer()增加

//获取所有控制器类型并使用属性注入
Type[] controllersTypeAssembly = typeof(Program).Assembly.GetExportedTypes()
    .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
containerBuilder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());
.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

验证:

.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

成功。

四、批量注入

实际项目中那么多需要注入的类,一个个写注册就不太现实了,需要一个可以批量注入的方法。

1、新建三个空接口IScopeDenpendency.cs,ISingletonDenpendency.cs,ITransitDenpendency.cs

/// <summary>
/// 瞬时注入
/// </summary>
public interface ITransitDenpendency
{
}
/// <summary>
/// 单例注入标识
/// </summary>
public interface ISingletonDenpendency
{
}
/// <summary>
/// 生命周期注入标识
/// </summary>
public interface IScopeDenpendency
{
}

2、把上面要注入的类实现上面的接口

.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

3、新增一个IocManager类

/// <summary>
/// Ioc管理
/// </summary>
public static class IocManager
{
     /// <summary>
     /// 批量注入扩展
     /// </summary>
     /// <param name="builder"></param>
     /// <param name="assembly"></param>
     public static void BatchAutowired(this ContainerBuilder builder, Assembly assembly)
     {

         var transientType = typeof(ITransitDenpendency); //瞬时注入
         var singletonType = typeof(ISingletonDenpendency); //单例注入
         var scopeType = typeof(IScopeDenpendency); //单例注入
         //瞬时注入
         builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(transientType))
             .AsSelf()
             .AsImplementedInterfaces()
             .InstancePerDependency()
             .PropertiesAutowired(new AutowiredPropertySelector());
         //单例注入
         builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(singletonType))
            .AsSelf()
            .AsImplementedInterfaces()
            .SingleInstance()
            .PropertiesAutowired(new AutowiredPropertySelector());
         //生命周期注入
         builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(scopeType))
            .AsSelf()
            .AsImplementedInterfaces()
            .InstancePerLifetimeScope()
            .PropertiesAutowired(new AutowiredPropertySelector());
     }
}

4、把注入类ConfigureContainer改成

 
.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

5、防止Program.cs代码过多,建一个Module把注入代码搬走,新建AutofacRegisterModule.cs类把ConfigureContainer的代码移过去

public class AutofacRegisterModule : Autofac.Module
{
    protected override void Load(ContainerBuilder builder)
    {
        //获取所有控制器类型并使用属性注入
        Type[] controllersTypeAssembly = typeof(Program).Assembly.GetExportedTypes()
            .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
        builder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());
        //批量自动注入,把需要注入层的程序集传参数,注入Service层的类
        builder.BatchAutowired(typeof(UserService).Assembly);
        //注入其它层的containerBuilder.BatchAutowired(typeof(其它层的任务一个类).Assembly);
    }
}

ConfigureContainer的代码变成

.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

五、手动获取实例

手动获取实例的场景有静态帮助类中获取实例,例如redisHelper中获取注入的配置文件中的连接字符串

1、在上面的IocManager类中增加

private static object obj = new object();
private static ILifetimeScope _container { get; set; }

public static void InitContainer(ILifetimeScope container)
{
    //防止过程中方法被调用_container发生改变
    if (_container == null)
    {
        lock (obj)
        {
            if (_container == null)
            {
                _container = container;
            }
        }
    }
}
/// <summary>
/// 手动获取实例
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T Resolve<T>()
{
    return _container.Resolve<T>();
}

2、在Program.cs中增加

.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

3、验证,新建一个DataHelper.cs类

public class DataHelper
{
    //手动注入UserService
    private static IUserService userService = IocManager.Resolve<IUserService>();
    public static string GetData()
    {
        return userService.GetUserName();
    }
}
.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

成功获取到值,证明从容器中获取成功。

六、其它用法

1、不用接口,直接注入实例

public class UserService :ITransitDenpendency  
{ 
   public string GetUserName()  
   { 
     return "张三";  
   }  
}
.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用

2、一接口多实现

public class UserService :IUserService
{
    public string GetUserName()
    {
        return "张三";
    }
}

public class UserService2 : IUserService
{
    public string GetUserName()
    {
        return "张三2号";
    }
}
.NET 7 中 Autofac 依赖注入整合多层,项目中可直接用