Получение зависимостей

Последнее обновление: 15.11.2022

Для получения зависимостей в консольном приложении .NET можно использовать различные способы:

  • Напрямую из коллекции сервисов ServiceCollection

  • Через методы GetService()/GetRequiredService() объекта IServiceProvider (так называемый паттерн "service locator")

  • Через конструктор класса

Для работы определим интерфейс ITimeService и класс ShortTimeService, который реализует данный интерфейс:

interface ITimeService
{
	string GetTime();
}
class ShortTimeService : ITimeService
{
	public string GetTime() => DateTime.Now.ToShortTimeString();
}

Методы GetService/GetRequiredService объекта IServiceProvider

Объект IServiceProvider предоставляет ряд методов для получения сервисов:

  • GetService<service>(): использует провайдер сервисов для создания объекта, который представляет тип service. В случае если в провайдере сервисов для данного сервиса не установлена зависимость, то возвращает значение null

  • GetRequiredService<service>(): использует провайдер сервисов для создания объекта, который представляет тип service. В случае если в провайдере сервисов для данного сервиса не установлена зависимость, то генерирует исключение

Данный паттерн получения сервиса еще называется service locator. Например, определим следующий код приложения:

using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection()
    .AddTransient<ITimeService, ShortTimeService>();

using var serviceProvider = services.BuildServiceProvider();
// получаем сервис
var timeService = serviceProvider.GetService<ITimeService>();
Console.WriteLine($"Time: {timeService?.GetTime()}");

interface ITimeService
{
    string GetTime();
}
class ShortTimeService : ITimeService
{
    public string GetTime() => DateTime.Now.ToShortTimeString();
}

В данном случае с помощью строки кода

var timeService = serviceProvider.GetService<ITimeService>();

Получаем из коллекции сервисов объект сервиса ITimeService - в данном случае он будет представлять объект ShortTimeService

Возможна ситуация, когда сервис не будет добавлен в коллекцию сервисов, однако в какой-то части приложения мы может попытаться его получить:

using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();
using var serviceProvider = services.BuildServiceProvider();
// здесь timeService равен null
var timeService = serviceProvider.GetService<ITimeService>();

В этом случае переменная timeService будет иметь значение null.

Аналогичный образом можно использовать метод GetRequiredService() за тем исключением, что если сервис не добавлен, то метод генерирует исключение:

using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection()
    .AddTransient<ITimeService, ShortTimeService>();

using var serviceProvider = services.BuildServiceProvider();
var timeService = serviceProvider.GetRequiredService<ITimeService>();
Console.WriteLine($"Time: {timeService?.GetTime()}");

Конструкторы

Встроенная в .NET система внедрения зависимостей использует конструкторы классов для передачи всех зависимостей. Передача сервисов через конструкторы является предпочтительным способом внедрения зависимостей.

Например, пусть в проекте определен следующий класс TimeMessage:

class TimeMessage
{
	ITimeService timeService;
	public TimeMessage(ITimeService timeService) =>this.timeService = timeService;
	public string GetTime() => $"Time: {timeService.GetTime()}";
}

Здесь через конструктор класса передается зависимость от ITimeService. Причем здесь неизвестно, что это будет за реализация интерфейса ITimeService. В методе GetTime() формируем сообщение, в котором из сервиса получаем текущее время.

Для использования класса TimeMessage определим следующую программу:

using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection()
    .AddTransient<ITimeService, ShortTimeService>()
    .AddTransient<TimeMessage>();

using var serviceProvider = services.BuildServiceProvider();
var timeMessage = serviceProvider.GetService<TimeMessage>();
Console.WriteLine(timeMessage?.GetTime());

class TimeMessage
{
    ITimeService timeService;
    public TimeMessage(ITimeService timeService) =>this.timeService = timeService;
    public string GetTime() => $"Time: {timeService.GetTime()}";
}

interface ITimeService
{
    string GetTime();
}
class ShortTimeService : ITimeService
{
    public string GetTime() => DateTime.Now.ToShortTimeString();
}

Для использования в приложении в качестве сервиса класс TimeMessage также добавляется в коллекцию сервисов. Поскольку это самодостаточная зависимость, которая представляет конкретный класс, то метод services.AddTransient типизируется одним этим типом TimeMessage. То есть классы, которые используют сервисы, сами могут выступать в качестве сервисов.

Но так как класс TimeMessage использует зависимость ITimeService, которая передается через конструктор, то нам надо также установить и эту зависимость:

services.AddTransient<ITimeService, ShortTimeService>();

И когда при обработке запроса будет использоваться класс TimeMessage, для создания объекта этого класса будет вызываться провайдер сервисов. Провайдер сервисов проверят конструктор класса TimeMessage на наличие зависимостей. Затем создает объекты для всех используемых зависимостей и передает их в конструктор.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850