.NET8では、KeyedServiceが導入され、カスタムキーワードを使用してサービスを利用できるようになりました。これは、複数のインターフェースサブクラスを注入する際に、命名キーワードで区別し、使用時にキーワードを使用して呼び出すことを意味します。
次に例を見てみましょう。通知サービスインターフェースINotifyServiceには、SMSServiceとEMailServiceの二つのサブクラスがあり、これらのサブクラスは異なるRespositoryを呼び出します。
public interface INotifyService{
bool Notify(string message);
}
public class SMSService : INotifyService{
private readonly Dictionary<string, dynamic> _configs;
private readonly ILogger<EMailService> _logger;
public SMSService([FromKeyedServices("smsRep")] IConfigRepository configRepository, ILogger<EMailService> logger) {
_logger = logger;
_configs = configRepository.GetConfig();
}
public bool Notify(string message) {
_logger.LogInformation($"{_configs["name"]},SMSService,こちらで設定ファイルに基づいてSMS通知の送信が完了します,Message:{message}");
return true;
}
}
public class EMailService : INotifyService{
private readonly Dictionary<string, dynamic> _configs;
private readonly ILogger<EMailService> _logger;
public EMailService([FromKeyedServices("emailRep")] IConfigRepository configRepository, ILogger<EMailService> logger) {
_logger = logger;
_configs = configRepository.GetConfig();
}
public bool Notify(string message) {
_logger.LogInformation($"{_configs["name"]},EMailService,こちらで設定ファイルに基づいてメール通知の送信が完了します,Message:{message}");
return true;
}
}
public interface IConfigRepository{
Dictionary<string, dynamic> GetConfig();
}
public class IEMailConfigRepository : IConfigRepository{
public Dictionary<string, dynamic> GetConfig() {
// データベースから設定情報を取得する
return new Dictionary<string, dynamic>() { { "name", "メール設定" } };
}
}
public class ISMSConfigRepository : IConfigRepository{
public Dictionary<string, dynamic> GetConfig() {
// データベースから設定情報を取得する
return new Dictionary<string, dynamic>() { { "name", "SMS設定" } }; ;
}
}
最後に、KeyedServiceを使用する場合、特性[FromKeyedServices("命名")]が必要ですが、この特性はapp.Mapメソッドで直接使用することはできません。そこで、SMSとEMailという二つのクラスを定義し、AddScoped方式での注入を行います。
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using System.Collections;
using System.Collections.Generic;
var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.AddScoped<SMS>();
builder.Services.AddScoped<EMail>();
builder.Services.AddKeyedScoped<IConfigRepository, ISMSConfigRepository>("smsRep");
builder.Services.AddKeyedScoped<IConfigRepository, IEMailConfigRepository>("emailRep");
builder.Services.AddKeyedScoped<INotifyService, EMailService>("emailSev");
builder.Services.AddKeyedScoped<INotifyService, SMSService>("smsSev");
var app = builder.Build();
app.MapGet("/sms", ([FromServices]SMS sms, string message) => new { Result = sms.Notify(message), Messgae = message, Type = sms.GetType().Name });
app.MapGet("/email", ([FromServices]EMail email, string message) => new { Result = email.Notify(message), Messgae = message, Type = email.GetType().Name });
//誤った書き方
//app.MapGet("/sms", ([FromKeyedServices("smsSev")] INotifyService notifyService, string message) => new { Result = notifyService.Notify(message), Messgae = message, Type = notifyService.GetType().Name });
//app.MapGet("/email", ([FromKeyedServices("smsSev")] INotifyService notifyService, string message) => new { Result = notifyService.Notify(message), Messgae = message, Type = notifyService.GetType().Name });
app.Run();
public class SMS([FromKeyedServices("smsSev")] INotifyService notifyService){
public bool Notify(string message) {
return notifyService.Notify(message);
}
}
public class EMail([FromKeyedServices("emailSev")] INotifyService notifyService){
public bool Notify(string message) {
return notifyService.Notify(message);
}
}
// もう一つの書き方は、AddSingleton方式で注入し、app.Services.GetRequiredKeyedService方式で通知インタフェースを取得し、使用することです。
builder.Services.AddKeyedSingleton<IConfigRepository, IEMailConfigRepository>("emailRep");
builder.Services.AddKeyedSingleton<INotifyService, EMailService>("emailSev");
var app = builder.Build();
app.MapGet("/email", (string message) =>{
var email = app.Services.GetRequiredKeyedService<INotifyService>("emailSev");
return new { Result = email.Notify(message), Messgae = message, Type = email.GetType().Name };
});
私が使用した感想としては、KeyedServiceの使用に多くの制限があり、スムーズではないと感じます。これはPreview段階であるためかもしれませんが、正式版での改善を期待しています。
(Translated by GPT)