Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7
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:
За установку сервисов в приложении отвечает метод ConfigureServices, определенный в классе Startup. В проекте Empty этот метод фактически пустой:
public void ConfigureServices(IServiceCollection services) { }
Через параметр IServiceCollection сервисы и добавляются в проект. Несмотря на то, что метод пустой, IServiceCollection уже содержит ряд сервисов по умолчанию
Как видно на скриншоте, в коллекции IServiceCollection 78 сервиса, который мы можем использовать в приложении. Это такие сервисы, как ILogger<T>, ILoggerFactory, IWebHostEnvironment и ряд других. Они добавляются по умолчанию инфраструктурой 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 имеет еще ряд встроенных сервисов, которые мы можем подключать в приложение при необходимости.
Все сервисы и компоненты 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()); }); } } }