Dependency Injection

Dependency injection (DI) или внедрение зависимостей представляет механизм, который позволяет сделать взаимодействующие в приложении объекты слабосвязанными. Такие объекты связаны между собой через абстракции, например, через интерфейсы, что делает всю систему более гибкой, более адаптируемой и расширяемой.

Нередко для установки зависимостей в подобных системах используются специальные контейнеры — IoC-контейнеры (Inversion of Control). Такие контейнеры служат своего рода фабриками, которые устанавливают зависимости между абстракциями и конкретными объектами и, как правило, управляют созданием этих объектов.

И если раньше в ASP.NET 4 и других предыдщих версиях надо было использовать различные внешние IoC-контейнеры для установки зависимостей, такие как Ninject, Autofac, Unity, Windsor Castle, StructureMap, то ASP.NET Core уже имеет встроенный контейнер внедрения зависимостей, который представлен интерфейсом IServiceProvider. А сами зависимости еще называются сервисами, собственно поэтому контейнер можно назвать провайдером сервисов. Этот контейнер отвечает за сопоставление зависимостей с конкретными типами и за внедрение зависимостей в различные объекты.

Установка встроенных сервисов фреймворка

Для рассмотрения работы механизма Dependency Injection создадим новый проект ASP.NET Core 3.0 по типу Empty:

Новый проект ASP.NET Core для Dependency Injection

За установку сервисов в приложении отвечает метод ConfigureServices, определенный в классе Startup. В проекте Empty этот метод фактически пустой:

public void ConfigureServices(IServiceCollection services)
{
}

Через параметр IServiceCollection сервисы и добавляются в проект. Несмотря на то, что метод пустой, IServiceCollection уже содержит ряд сервисов по умолчанию

Сервисы в ASP.NET Core

Как видно на скриншоте, в коллекции IServiceCollection 78 сервиса, который мы можем использовать в приложении. Это такие сервисы, как ILogger<T>ILoggerFactoryIWebHostEnvironment и ряд других. Они добавляются по умолчанию инфраструктурой ASP.NET Core. И мы их можем использовать в любой части приложения. Например, в том же пустом проекте следующее определение метода Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
 
    app.UseRouting();
 
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    });
}

Через параметры метода Configure можно получить добавленные в приложении сервисы и, в частности, через параметр передается сервис IWebHostEnvironment, который используется для определения окружения.

Регистрация встроенных сервисов ASP.NET Core

Кроме ряда подключаемых по умолчанию сервисов ASP.NET Core имеет еще ряд встроенных сервисов, которые мы можем подключать в приложение при необходимости. Все сервисы и компоненты middleware, которые предоставляются ASP.NET по умолчанию, регистрируются в приложение с помощью методов расширений IServiceCollection, имеющих общую форму Add[название_сервиса].

Например:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
}

Для объекта IServiceCollection определено ряд методов расширений, которые начинаются на Add, как, например, AddMvc(). Эти методы добавляют в объект IServiceCollection соответствующие сервисы. Например, AddMvc() добавляет в приложение сервисы MVC, благодаря чему мы сможем их использовать в методе Configure().

Информация о сервисах

Каждый сервис в коллекции IServiceCollection представляет объект ServiceDescriptor, который несет некоторую информацию. В частности, наиболее важные свойства этого объекта:

  • ServiceType: тип сервиса
  • ImplementationType: тип реализации сервиса
  • Lifetime: жизненный цикл сервиса

Например, получим все сервисы, которые добавлены в приложение:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System.Text;
 
namespace DIApp
{
    public class Startup
    {
        private IServiceCollection _services;
        public void ConfigureServices(IServiceCollection services)
        {
            _services = services;
        }
        public void Configure(IApplicationBuilder app)
        {
            app.Run(async context =>
            {
                var sb = new StringBuilder();
                sb.Append("<h1>Все сервисы</h1>");
                sb.Append("<table>");
                sb.Append("<tr><th>Тип</th><th>Lifetime</th><th>Реализация</th></tr>");
                foreach (var svc in _services)
                {
                    sb.Append("<tr>");
                    sb.Append($"<td>{svc.ServiceType.FullName}</td>");
                    sb.Append($"<td>{svc.Lifetime}</td>");
                    sb.Append($"<td>{svc.ImplementationType?.FullName}</td>");
                    sb.Append("</tr>");
                }
                sb.Append("</table>");
                context.Response.ContentType = "text/html;charset=utf-8";
                await context.Response.WriteAsync(sb.ToString());
            });
        }
    }
}
Получение всех сервисов их IServiceCollection ASP.NET Core

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *