说说KeyedService

在.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,这里根据配置文件完成短信的通知发送,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", "email配置" } };    }}public class ISMSConfigRepository : IConfigRepository{    public Dictionary<string, dynamic> GetConfig()    {        //从数据库中获取配置信息        return new Dictionary<string, dynamic>() { { "name", "sms配置" } }; ;    }}

最后,再定义两个使用类SMS和EMail,在使上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阶段,希望正式版本有所改善。