首先創建2個用於反射的標記 ServiceName是用來做多租戶標記的
public class InjectAttribute : Attribute { public string ServiceName { get; set; } public InjectAttribute(string serviceName) { ServiceName = serviceName; } public InjectAttribute() { ServiceName = ""; } } public class DenpendencyAttribute : Attribute { }
創建Autofac裝配初始化的類
public static class AutofacAutoRegisterInit { public static void Init(ContainerBuilder builder, params Assembly[] assembliesWithServices) { Dictionary<Type, List<Type>> diDic = new Dictionary<Type, List<Type>>(); foreach (Assembly assembly in assembliesWithServices) { foreach (Type type in assembly.GetTypes()) { if (type.GetCustomAttribute<DenpendencyAttribute>() != null) { if (!diDic.ContainsKey(type)) { diDic.Add(type, new List<Type>()); } } if (type.GetCustomAttribute<InjectAttribute>() != null) { foreach (Type ImplementedInterface in type.GetTypeInfo().ImplementedInterfaces) { if (diDic.ContainsKey(ImplementedInterface)) { diDic[ImplementedInterface].Add(type); } else { diDic.Add(ImplementedInterface, new List<Type>() { type }); } } } } } foreach (Type denpendencyType in diDic.Keys) { foreach (Type injectType in diDic[denpendencyType]) { string serviceName = injectType.GetCustomAttribute<InjectAttribute>()!.ServiceName; builder.RegisterType(injectType).Keyed(serviceName, denpendencyType).As(denpendencyType); } builder.Register<Func<string, object>>(c => { var ic = c.Resolve<IComponentContext>(); return named => ic.ResolveKeyed(named, denpendencyType); }); } } }
修改啟動文件內容 必須使用DependencyContext.Default來獲取程序集,不能通過運行項目路徑加載,否則會導致程序集不匹配。
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory(autofacBuilder => { var libs = DependencyContext.Default.CompileLibraries.Where(u => u.Name.Contains("APITemplate")); List<Assembly> loadAssembly = new List<Assembly>(); foreach (var lib in libs) { loadAssembly.Add(AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name))); } AutofacAutoRegisterInit.Init(autofacBuilder, loadAssembly.ToArray()); }));
如何使用?
單一實現和正常的構造函數注入方式一樣
多租戶使用以下方式Test參數就是Inject中的Servicename
private readonly Func<string,IApolloApplicationService> apolloApplicationService; public ApolloController(Func<string, IApolloApplicationService> apolloApplicationService) { this.apolloApplicationService = apolloApplicationService; } [HttpGet] public ActionResult Get([FromRoute] string key) { var value = apolloApplicationService("Test").GetValue(key); return Ok(value); }