Предположим, у вас другой провайдер SMS, и вы хотите выбрать одного из этих провайдеров на основании некоторых критериев.
Есть два способа выбрать, какая реализация интерфейса будет инстанциирована с использованием выбранного вами IOC.
Первый подход, который я не рекомендую, - это зарегистрировать свои службы и выбрать тот, который вам нужен во время выполнения.
services.AddSingleton<ISmsProvider, SmsProviderA>();
services.AddSingleton<ISmsProvider, SmsProviderB>();
services.AddSingleton<ISmsProvider, SmsProviderC>();
Затем во время выполнения вы можете разрешить правильный объект, выполнив
var services = serviceProvider.GetServices<ISmsProvider>();
var smsProviderC= services.First(o => o.GetType()== typeof(SmsProviderC));
Проблема с этим подходом в том, что когда мы вызываем serviceProvider.GetServices<ISmsProvider>();
будут созданы экземпляры всех служб, а не только той, которую вы хотите, поэтому будут созданы экземпляры SmsProviderA , SmsProviderB and SmsProviderC
, и если эти службы также имеют много внутренних зависимостей, все эти зависимости также будут созданы.
Итак, рассмотрите этот подход, если ваши службы легковесны или у них нет внутренних зависимостей.
Второй подход, который я рекомендую, заключается в следующем: сначала определите свой интерфейс.
public interface ISmsProvider
{
Task<SendResult> SendSmsAsync(string to, string message);
}
Затем реализуйте свои услуги
public classSmsProviderA
:ISmsProvider
{ private readonly HttpClient _httpClient; publicSmsProviderA
(HttpClient httpClient) { _httpClient = httpClient; } public async Task<SmsResultDto> SendSmsAsync(SmsDto dto) { ///do something here } } public classSmsProviderB
:ISmsProvider
{ private readonly HttpClient _httpClient; publicSmsProviderB
(HttpClient httpClient) { _httpClient = httpClient; } public async Task<SmsResultDto> SendSmsAsync(SmsDto dto) { ///do something here } } public classSmsProviderC
:ISmsProvider
{ public async Task<SmsResultDto> SendSmsAsync(SmsDto dto) { ///do something here } }
Затем зарегистрируйте услугу в выбранном вами МОК
services.AddHttpClient<SmsProviderA
>(); services.AddHttpClient<SmsProviderB
>(); services.AddTransient<SmsProviderC
>();
А затем зарегистрируйте Func вашего Сервиса, чтобы вы могли звонить с помощью своего di
services.AddTransient<Func<string, ISms>>(serviceProvider => key => { switch (key) { case "SmsProviderA
": return serviceProvider.GetService<SmsProviderA
>(); case "SmsProviderB
": return serviceProvider.GetService<SmsProviderB
>(); case "SmsProviderC
": return serviceProvider.GetService<SmsProviderC
>(); default: return serviceProvider.GetService<SmsProviderA
>(); } });
Итак, в вашем контроллере или других службах вы можете использовать свою службу и решить, какой из служб будет создан.
Помните, что сначала вы должны создать экземпляр своего преобразователя, который в данном случае является делегатом Func.
public class SendSmsController : ControllerBase { private readonly Func<string,ISmsProvider
> _smsServie; public SendSmsController(Func<string, ISms> smsServie) { _smsServie = smsServie; } public async Task<ActionResult> SendSms() { var serviceToBeInstantiated = "SmsProviderA
"; var sendResult= await _smsServie(serviceToBeInstantiated).SendSmsAsync(number,"hi"); } }
Преимущество этого подхода заключается в том, что вы создаете экземпляр нужной службы только с правильным сроком действия.