在.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);}}
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阶段,希望正式版本有所改善。