1. 程式人生 > 其它 >關於.NetCore依賴注入 .Net Core5.0中Autofac依賴注入整合多層,專案中可直接用

關於.NetCore依賴注入 .Net Core5.0中Autofac依賴注入整合多層,專案中可直接用

.Net Core5.0中Autofac依賴注入整合多層,專案中可直接用

目錄

 


回到頂部

一、配置Autofac替換內建DI

1.安裝Nuget包:Autofac,Autofac.Extensions.DependencyInjection

 

 

 

2.Program.cs中CreateHostBuilder方法後加上.UseServiceProviderFactory(new AutofacServiceProviderFactory()) ; 告訴程式要使用Autofac。

 

 

 3.Startup.cs中增加方法ConfigureContainer(ContainerBuilder containerBuilder),例項注入的地方,配置完成。

 /// <summary>
        /// Autofac註冊服務的地方,Autofac會自動呼叫
        /// </summary>
        /// <param name="containerBuilder"></param>
        public void ConfigureContainer(ContainerBuilder containerBuilder)
        {

        }
回到頂部

二、建構函式注入

新建IUserService,類UserService,控制器UserController

 public interface IUserService
    {
        public string GetUserName();
    }
 public class UserService
    {
        public string GetUserName()
        {
            return "張三";
        }
    }
 public class UserController : Controller
    {
        private readonly IUserService _userService;
        public UserController(IUserService userService)
        {
            _userService = userService;
        }
        public IActionResult Index()
        {
            string name = _userService.GetUserName();
            return Content(name);
        }
    }

在上面的ConfigureContainer方法把UserService注入進來,預設是瞬時注入

瞬時注入:containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerDependency();;

單例注入:containerBuilder.RegisterType<UserService>().As<IUserService>().SingleInstance();

生命週期注入: containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerLifetimeScope();

 /// <summary>
        /// Autofac註冊服務的地方,Autofac會自動呼叫
        /// </summary>
        /// <param name="containerBuilder"></param>
        public void ConfigureContainer(ContainerBuilder containerBuilder)
        {
            //註冊服務
            containerBuilder.RegisterType<UserService>().As<IUserService>();
        }

訪問/User/Index,_userService成功注入,正確獲取結果。

 

回到頂部

三、屬性注入

1.把UserController改成屬性注入形式,屬性注入有一個問題,就是那些屬性需要注入?全部注入沒必要,父類也有很多屬性,要按需注入,給屬性增加一個自定義特性標識說明需要注入。

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

2.新增自定義特性類AutowiredPropertyAttribute.cs

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

3.增加識別特性類AutowiredPropertySelector.cs

 /// <summary>
    /// IPropertySelector:檢視屬性上是否標記某一個特性
    /// </summary>
   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容器中,在Startup.cs的ConfigureServices中增加

 //讓控制器例項由容器建立
 services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());

 

 5.把容器註冊到IOC容器,在Startup.cs的ConfigureContainer()增加

 //獲取所有控制器型別並使用屬性注入
            Type[] controllersTypeAssembly = typeof(Startup).Assembly.GetExportedTypes()
                .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
            containerBuilder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());

 

 6.驗證結果,新增一個介面IOrderService.cs和一個實現類OrderService.cs做對比

 public interface IOrderService
    {
        public string CreateOrder();
    }

public class OrderService : IOrderService
    {
        public string CreateOrder()
        {
            return "下單成功";
        }
    }

把UserController改成

  public class UserController : Controller
    {
        [AutowiredProperty]
        private IUserService userService { get; set; }

        private IOrderService orderService { get; set; }//不加屬性注入標識
        public IActionResult Index()
        {
            string name = userService.GetUserName();
            return Content(name);
        }
    }

注入方法ConfigureContainer()增加

containerBuilder.RegisterType<OrderService>().As<IOrderService>();

 

執行程式,能看到增加了注入標識的userService注入成功,沒加標識的orderService沒有注入。

 

回到頂部

四、批量注入

實際專案中那麼多需要注入的類,一個個寫註冊就不太現實了,需要一個可以批量注入的方法。

1.新建三個空介面IScopeDenpendency.cs,ISingletonDenpendency.cs,ITransitDenpendency.cs

  /// <summary>
    /// 瞬時注入
    /// </summary>
    public interface ITransitDenpendency
    {
    }
  /// <summary>
    /// 單例注入標識
    /// </summary>
    public interface ISingletonDenpendency
    {
    }
   /// <summary>
    /// 生命週期注入標識
    /// </summary>
    public interface IScopeDenpendency
    {
    }

2.把上面要注入的類實現上面的介面

 

 

3.新增一個IocManger類

  /// <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改成

 /// <summary>
        /// Autofac註冊服務的地方,Autofac會自動呼叫
        /// </summary>
        /// <param name="containerBuilder"></param>
        public void ConfigureContainer(ContainerBuilder containerBuilder)
        {
            //獲取所有控制器型別並使用屬性注入
           Type[] controllersTypeAssembly = typeof(Startup).Assembly.GetExportedTypes()
               .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
            containerBuilder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());

            //批量自動注入,把需要注入層的程式集傳引數
            containerBuilder.BatchAutowired(typeof(UserService).Assembly);
            containerBuilder.BatchAutowired(typeof(UserRepository).Assembly);
        }

5.防止startup.cs程式碼過多,建一個Module把注入程式碼搬走,新建AutofacRegisterModule.cs類把ConfigureContainer的程式碼移過去

 public class AutofacRegisterModule:Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            //獲取所有控制器型別並使用屬性注入
            Type[] controllersTypeAssembly = typeof(Startup).Assembly.GetExportedTypes()
                .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
            builder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());

            //批量自動注入,把需要注入層的程式集傳引數
            builder.BatchAutowired(typeof(UserService).Assembly);
            builder.BatchAutowired(typeof(UserRepository).Assembly);
        }
    }

ConfigureContainer的程式碼變成

/// <summary>
        /// Autofac註冊服務的地方,Autofac會自動呼叫
        /// </summary>
        /// <param name="containerBuilder"></param>
        public void ConfigureContainer(ContainerBuilder containerBuilder)
        {
            containerBuilder.RegisterModule<AutofacRegisterModule>();
        }

 

回到頂部

五、手動獲取例項

手動獲取例項的場景有靜態幫助類中獲取例項,例如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.在Startup.cs的Configure()中增加

//獲取Autofac容器上下文資訊
IocManager.InitContainer(app.ApplicationServices.GetAutofacRoot());

3.驗證,新建一個DataHelper.cs類

 public class DataHelper
    {
        //手動注入UserService
        private static IUserService userService = IocManager.Resolve<IUserService>();
        public static string GetData()
        {
            return userService.GetUserName();
        }
    }

修改UserController用DataHelper的方法成功獲取資料

 

回到頂部

六、其它用法

1.不用介面,直接注入例項

 public class UserService :ITransitDenpendency
    {
        public string GetUserName()
        {
            return "張三";
        }
    }

 

 2.一介面多實現

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

 public class User2Service : IUserService
    {
        public string GetUserName()
        {
            return "張三2號";
        }
    }

 

 

 

最後:原始碼地址:https://github.com/weixiaolong325/.NetCore5.0AutofacDemo

演示專案結構:

 

原文連結:https://www.cnblogs.com/wei325/archive/2021/08/11/15121451.html

目錄

 


回到頂部

一、配置Autofac替換內建DI

1.安裝Nuget包:Autofac,Autofac.Extensions.DependencyInjection

 

 

 

2.Program.cs中CreateHostBuilder方法後加上.UseServiceProviderFactory(new AutofacServiceProviderFactory()) ; 告訴程式要使用Autofac。

 

 

 3.Startup.cs中增加方法ConfigureContainer(ContainerBuilder containerBuilder),例項注入的地方,配置完成。

 /// <summary>
        /// Autofac註冊服務的地方,Autofac會自動呼叫
        /// </summary>
        /// <param name="containerBuilder"></param>
        public void ConfigureContainer(ContainerBuilder containerBuilder)
        {

        }
回到頂部

二、建構函式注入

新建IUserService,類UserService,控制器UserController

 public interface IUserService
    {
        public string GetUserName();
    }
 public class UserService
    {
        public string GetUserName()
        {
            return "張三";
        }
    }
 public class UserController : Controller
    {
        private readonly IUserService _userService;
        public UserController(IUserService userService)
        {
            _userService = userService;
        }
        public IActionResult Index()
        {
            string name = _userService.GetUserName();
            return Content(name);
        }
    }

在上面的ConfigureContainer方法把UserService注入進來,預設是瞬時注入

瞬時注入:containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerDependency();;

單例注入:containerBuilder.RegisterType<UserService>().As<IUserService>().SingleInstance();

生命週期注入: containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerLifetimeScope();

 /// <summary>
        /// Autofac註冊服務的地方,Autofac會自動呼叫
        /// </summary>
        /// <param name="containerBuilder"></param>
        public void ConfigureContainer(ContainerBuilder containerBuilder)
        {
            //註冊服務
            containerBuilder.RegisterType<UserService>().As<IUserService>();
        }

訪問/User/Index,_userService成功注入,正確獲取結果。

 

回到頂部

三、屬性注入

1.把UserController改成屬性注入形式,屬性注入有一個問題,就是那些屬性需要注入?全部注入沒必要,父類也有很多屬性,要按需注入,給屬性增加一個自定義特性標識說明需要注入。

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

2.新增自定義特性類AutowiredPropertyAttribute.cs

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

3.增加識別特性類AutowiredPropertySelector.cs

 /// <summary>
    /// IPropertySelector:檢視屬性上是否標記某一個特性
    /// </summary>
   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容器中,在Startup.cs的ConfigureServices中增加

 //讓控制器例項由容器建立
 services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());

 

 5.把容器註冊到IOC容器,在Startup.cs的ConfigureContainer()增加

 //獲取所有控制器型別並使用屬性注入
            Type[] controllersTypeAssembly = typeof(Startup).Assembly.GetExportedTypes()
                .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
            containerBuilder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());

 

 6.驗證結果,新增一個介面IOrderService.cs和一個實現類OrderService.cs做對比

 public interface IOrderService
    {
        public string CreateOrder();
    }

public class OrderService : IOrderService
    {
        public string CreateOrder()
        {
            return "下單成功";
        }
    }

把UserController改成

  public class UserController : Controller
    {
        [AutowiredProperty]
        private IUserService userService { get; set; }

        private IOrderService orderService { get; set; }//不加屬性注入標識
        public IActionResult Index()
        {
            string name = userService.GetUserName();
            return Content(name);
        }
    }

注入方法ConfigureContainer()增加

containerBuilder.RegisterType<OrderService>().As<IOrderService>();

 

執行程式,能看到增加了注入標識的userService注入成功,沒加標識的orderService沒有注入。

 

回到頂部

四、批量注入

實際專案中那麼多需要注入的類,一個個寫註冊就不太現實了,需要一個可以批量注入的方法。

1.新建三個空介面IScopeDenpendency.cs,ISingletonDenpendency.cs,ITransitDenpendency.cs

  /// <summary>
    /// 瞬時注入
    /// </summary>
    public interface ITransitDenpendency
    {
    }
  /// <summary>
    /// 單例注入標識
    /// </summary>
    public interface ISingletonDenpendency
    {
    }
   /// <summary>
    /// 生命週期注入標識
    /// </summary>
    public interface IScopeDenpendency
    {
    }

2.把上面要注入的類實現上面的介面

 

 

3.新增一個IocManger類

  /// <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改成

 /// <summary>
        /// Autofac註冊服務的地方,Autofac會自動呼叫
        /// </summary>
        /// <param name="containerBuilder"></param>
        public void ConfigureContainer(ContainerBuilder containerBuilder)
        {
            //獲取所有控制器型別並使用屬性注入
           Type[] controllersTypeAssembly = typeof(Startup).Assembly.GetExportedTypes()
               .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
            containerBuilder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());

            //批量自動注入,把需要注入層的程式集傳引數
            containerBuilder.BatchAutowired(typeof(UserService).Assembly);
            containerBuilder.BatchAutowired(typeof(UserRepository).Assembly);
        }

5.防止startup.cs程式碼過多,建一個Module把注入程式碼搬走,新建AutofacRegisterModule.cs類把ConfigureContainer的程式碼移過去

 public class AutofacRegisterModule:Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            //獲取所有控制器型別並使用屬性注入
            Type[] controllersTypeAssembly = typeof(Startup).Assembly.GetExportedTypes()
                .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
            builder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());

            //批量自動注入,把需要注入層的程式集傳引數
            builder.BatchAutowired(typeof(UserService).Assembly);
            builder.BatchAutowired(typeof(UserRepository).Assembly);
        }
    }

ConfigureContainer的程式碼變成

/// <summary>
        /// Autofac註冊服務的地方,Autofac會自動呼叫
        /// </summary>
        /// <param name="containerBuilder"></param>
        public void ConfigureContainer(ContainerBuilder containerBuilder)
        {
            containerBuilder.RegisterModule<AutofacRegisterModule>();
        }

 

回到頂部

五、手動獲取例項

手動獲取例項的場景有靜態幫助類中獲取例項,例如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.在Startup.cs的Configure()中增加

//獲取Autofac容器上下文資訊
IocManager.InitContainer(app.ApplicationServices.GetAutofacRoot());

3.驗證,新建一個DataHelper.cs類

 public class DataHelper
    {
        //手動注入UserService
        private static IUserService userService = IocManager.Resolve<IUserService>();
        public static string GetData()
        {
            return userService.GetUserName();
        }
    }

修改UserController用DataHelper的方法成功獲取資料

 

回到頂部

六、其它用法

1.不用介面,直接注入例項

 public class UserService :ITransitDenpendency
    {
        public string GetUserName()
        {
            return "張三";
        }
    }

 

 2.一介面多實現

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

 public class User2Service : IUserService
    {
        public string GetUserName()
        {
            return "張三2號";
        }
    }

 

 

 

最後:原始碼地址:https://github.com/weixiaolong325/.NetCore5.0AutofacDemo

演示專案結構:

 

原文連結:https://www.cnblogs.com/wei325/archive/2021/08/11/15121451.html