.NET Core 中 提供了一套依賴注入容器,但需要手工注入。隨着業務增長,需要注入的實現增多,會出現忘記注入的情況。
Autofac 自動注入
1.添加Autofac 引用
Install-Package Autofac -Version 5.2.0
2.添加Autofac.Extensions.DependencyInjection 引用
Install-Package Autofac.Extensions.DependencyInjection-Version 6.0.0
3.定義生命周期相關接口
/// <summary> /// 請求單例 /// </summary> public interface IScope { } /// <summary> /// 單例 /// </summary> public interface ISingleton { } /// <summary> /// 瞬態 /// </summary> public interface ITransient { } /// <summary> /// 注入接口忽略 /// </summary> public interface IDependencyInterfaceIgnore { }
4.注入相關類型
using Autofac; using Autofac.Builder; using Autofac.Core; using Autofac.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; using EasyFx.Core.Utils; namespace EasyFx.Core.DependencyInjection { public class AutofacConfigure : IDisposable { public static IContainer ApplicationContainer { get; private set; } private static void RegisterTypes(ContainerBuilder builder, List<Type> types, ServiceLifetime lifetime, bool asSelf, bool isGeneric) { if (!types.Any()) { return; } if (isGeneric) { foreach (var item in types) { IRegistrationBuilder<object, ReflectionActivatorData, DynamicRegistrationStyle> typeBuilder; var interfaceType = item.GetInterfaces().FirstOrDefault(p => p.IsGenericType); if (interfaceType != null) { typeBuilder = builder.RegisterGeneric(item).As(interfaceType).PropertiesAutowired(); } else { typeBuilder = builder.RegisterGeneric(item).PropertiesAutowired(); } SetLifetime(typeBuilder, lifetime); } } else { var typeBuilder = builder.RegisterTypes(types.ToArray()).PropertiesAutowired(); if (asSelf) { typeBuilder.AsSelf(); } else { typeBuilder.AsImplementedInterfaces(); } SetLifetime(typeBuilder, lifetime); } } private static void SetLifetime<TReflectionActivatorData>(IRegistrationBuilder<object, TReflectionActivatorData, DynamicRegistrationStyle> typeBuilder, ServiceLifetime lifetime) where TReflectionActivatorData : ReflectionActivatorData { switch (lifetime) { case ServiceLifetime.Scoped: typeBuilder.InstancePerDependency(); break; case ServiceLifetime.Singleton: typeBuilder.SingleInstance(); break; case ServiceLifetime.Transient: typeBuilder.InstancePerLifetimeScope(); break; } } private static void RegisterTypes(ContainerBuilder builder, List<Type> types, ServiceLifetime lifetime) { if (!types.Any()) { return; } var group = types.Select(it => new { AsSelf = it.GetInterfaces().Contains(typeof(IDependencyInterfaceIgnore)), IsGeneric = it.IsGenericType, Type = it }) .GroupBy(it => new { it.AsSelf, it.IsGeneric }); foreach (var item in group) { RegisterTypes(builder, item.Select(it => it.Type).ToList(), lifetime, item.Key.AsSelf, item.Key.IsGeneric); RegisterTypes(builder, item.Select(it => it.Type).ToList(), lifetime, item.Key.AsSelf, item.Key.IsGeneric); } } public static IServiceProvider BuildServiceProvider(IServiceCollection services, params IModule[] modules) { var builder = new ContainerBuilder(); if (modules != null && modules.Any()) { foreach (var module in modules) { builder.RegisterModule(module); } } var types = ReflectionHelper.GetApplicationTypes(); //singleton var singletonTypes = types.FindAll(t => t.GetInterfaces().Contains(typeof(ISingleton)) && !t.IsInterface); RegisterTypes(builder, singletonTypes, ServiceLifetime.Singleton); //scope var scopeTypes = types.FindAll(t => t.GetInterfaces().Contains(typeof(IScope)) && !t.IsInterface); RegisterTypes(builder, scopeTypes, ServiceLifetime.Scoped); //transient var transientTypes = types.FindAll(t => t.GetInterfaces().Contains(typeof(ITransient)) && !t.IsInterface); RegisterTypes(builder, transientTypes, ServiceLifetime.Transient); builder.Populate(services); ApplicationContainer = builder.Build(); return new AutofacServiceProvider(ApplicationContainer); } /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary> public void Dispose() { ApplicationContainer?.Dispose(); } } }
5.替換ServiceProviderFactory
using Autofac.Extensions.DependencyInjection; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; namespace EasyFx.Sample.Web { public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseServiceProviderFactory(context=>new AutofacServiceProviderFactory()) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); } }
相關依賴代碼
1.ReflectionHelper 提供了只包括項目框架的類型
using Microsoft.Extensions.DependencyModel; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.Loader; namespace EasyFx.Core.Utils { public class ReflectionHelper { public static List<Type> GetApplicationTypes() { var context = DependencyContext.Default; return context.CompileLibraries .Where(lib => !lib.Serviceable && lib.Type != "package") .SelectMany(lib => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name)).GetTypes()) .ToList(); } public static List<Assembly> GetApplicationAssemblies() { var context = DependencyContext.Default; return context.CompileLibraries .Where(lib => !lib.Serviceable && lib.Type != "package") .Select(lib => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name))) .ToList(); } } }