.NET Core 支援相依性注入 (Depedency Injection) 的設計模式,以往的 .NET Framework 在不支援 DI 的時候,我們會利用一些套件幫助我們完成這件事,例如 Autofac。假設現在我們有多個服務要註冊,使用 Autofac 來做 DI,可以使用以下的方法實現:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class ServiceDI : Autofac.Module { protected override void Load(ContainerBuilder builder) { builder.RegisterType<ServiceA>().As<IServiceA>().WithAttributeFiltering(); builder.RegisterType<ServiceB>().As<IServiceB>().WithAttributeFiltering(); builder.RegisterType<ServiceC>().As<IServiceC>().WithAttributeFiltering();
var serviceTypes = Assembly.Load("Where.My.Services.At"); builder.RegisterAssemblyTypes(serviceTypes) .AsImplementedInterfaces() .WithAttributeFilter(); } }
|
現在我們想用微軟的 DI 工具來達到一樣的事情,若參考微軟官方的教學文件,也是教大家一個一個註冊,後來翻了一下文件,發現其實也有跟上面 Autofac 一樣,可以用參數型別為 Type 的方法來進行註冊:AddScoped(IServiceCollection, Type, Type)
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| using System.Linq; using System.Reflection; using Microsoft.Extensions.DependencyInjection;
public static class ServiceMicrosoftDI { public static void RegisterService(this IServiceCollection services) { var serviceTypes = Assembly.Load("Where.My.Services.At"); var implementationTypes = serviceTypes.GetTypes().Where(i => i.Name.StartsWith("Service") && i.IsClass);
foreach(var implementationType in implementationTypes) { var serviceName = string.Format("I{0}", implementationType.Name);
var serviceType = implementationType.GetInterface(serviceName);
services.AddScoped(serviceType, implementationType); } } }
|
最後在 Startup.cs
中註冊
1 2 3 4 5
| public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.RegisterService(); }
|
上面的寫法有個前提是 Interface 和實作的 Class,命名有一個 Pattern 存在 (即開頭差一個 I
),如果有其他更好的寫法歡迎提供。
參考
・How to register a service with multiple interfaces in ASP.NET Core DI
・微軟官方文件 - .NET 中的相依性插入
・微軟官方文件 - ServiceCollectionServiceExtensions.AddScoped 方法