Внедрение зависимостей в ASP.NET Core MVC

  • Михаил
  • 12 мин. на прочтение
  • 150
  • 30 Nov 2022
  • 30 Nov 2022

В этой статье мы собираемся обсудить важную концепцию ASP.NET Core MVC — внедрение зависимостей .

Если вы пропустили некоторые из предыдущих статей серии, рекомендуем посетить страницу серии: серия  ASP.NET Core MVC.

Чтобы загрузить исходный код этой статьи, посетите:  Внедрение зависимостей в ASP.NET Core MVC.

Итак, давайте приступим к делу.

Инверсия зависимостей и внедрение зависимостей

Dependency Inversion— это один из основных принципов разработки программного обеспечения, который мы используем для создания слабо связанных модулей. При создании приложений мы можем добиться этого с помощью техники, называемой Dependency Injection. Dependency Injection (DI)это метод внедрения зависимых модулей в наши классы.

Мы подробно обсуждали это в одной из наших других статей Принцип инверсии зависимостей . Мы также обсудили концепцию внедрения зависимостей и способы ее реализации.

Итак, в этом разделе мы рассмотрим поддержку внедрения зависимостей в приложении ASP.NET Core MVC.

Внедрение зависимостей в контроллеры

ASP.NET Core поддерживает внедрение зависимостей (DI) между классами и их зависимостями. Контроллеры MVC явно запрашивают зависимости через конструкторы. Кроме того, ASP.NET Core имеет встроенную поддержку внедрения зависимостей, что упрощает тестирование и обслуживание приложения.

Мы добавляем службы в качестве параметра конструктора, и среда выполнения разрешает службу из контейнера службы. Обычно мы определяем службы с помощью интерфейсов.

Когда мы реализуем шаблон репозитория в приложении ASP.NET Core MVC, мы используем внедрение зависимостей в наших контроллерах. Мы объяснили, как реализовать простой репозиторий данных, в разделе статьи Реализация простого репозитория данных .

Давайте создадим приложение ASP.NET Core MVC и реализуем простой репозиторий данных, как описано в статье.

Прежде всего, давайте создадим интерфейс IDataRepository:

public interface IDataRepository
{
    IEnumerable GetAll();
    void Add(Employee employee);
}

Затем создадим класс, EmployeeManagerреализующий IDataRepositoryинтерфейс:

public class EmployeeManager : IDataRepository
{
    public void Add(Employee employee)
    {
        throw new NotImplementedException();
    }
    IEnumerable IDataRepository.GetAll()
    {
        return new List() {
            new Employee(){ }
        };
    }
}

Следующим шагом является добавление службы в контейнер службы. Нам нужно сделать это в ConfigureServices()методе Startup.csкласса:

services.AddScoped<IDataRepository<Employee>, EmployeeManager>();

Таким образом, мы настроили репозиторий с помощью внедрения зависимостей.

Далее создадим метод действия EmployeeControllerwith Index(), чтобы получить список всех сотрудников:

public class EmployeeController : Controller
{
    private readonly IDataRepository _dataRepository;
    public EmployeeController(IDataRepository dataRepository)
    {
        _dataRepository = dataRepository;
    }
    public IActionResult Index()
    {
        IEnumerable employees = _dataRepository.GetAll();
        return View(employees);
    }
}

Здесь мы сначала объявляем _dataRepositoryпеременную типа IDataRepository. Позже мы внедряем его через конструктор.

Мы также можем внедрить службу непосредственно в метод действия без использования внедрения конструктора. Для этого мы можем использовать [FromServices]атрибут:

public IActionResult Index([FromServices]  IDataRepository _dataRepository)
{
    IEnumerable employees = _dataRepository.GetAll();
    return View(employees);
}

Атрибут FromServicesуказывает, что параметр действия должен быть привязан с помощью служб запроса.

Большой. Мы узнали, как использовать внедрение зависимостей для предоставления зависимостей в контроллер.

Теперь давайте посмотрим, как внедрить зависимости в представления.

Внедрение зависимостей в представления

ASP.NET Core поддерживает внедрение зависимостей в представления. 

Когда внедрять зависимости в представления

Внедрение сервисов в представления является отклонением от концепции MVC. Но в некоторых случаях у нас могут быть сервисы для конкретных представлений, которые возвращают данные, которые мы используем только для заполнения элементов представления. Примером может служить служба, которая предоставляет набор значений, которые нам нужно отобразить в элементе управления списком. В таких сценариях мы можем внедрять сервисы непосредственно в представления. Внедрение представления может быть полезно для заполнения параметров в элементах пользовательского интерфейса, таких как раскрывающиеся списки.

Рассмотрим форму для создания книги, которая включает параметры для указания жанра. Для рендеринга данных с использованием стандартного подхода MVC контроллер должен запросить службы доступа к данным для этого набора параметров, а затем заполнить Model или ViewBag набором параметров, которые необходимо привязать.

Альтернативный подход заключается в внедрении сервисов непосредственно в представление. Этот подход сводит к минимуму количество кода, необходимого контроллеру, поскольку мы перемещаем логику построения элемента представления в само представление.

Как внедрять сервисы в представления

Мы можем внедрить службу в представление с помощью @injectдирективы. @injectдобавляет свойство в наше представление и инициализирует его с помощью DI:

@inject  

Давайте создадим метод действия контроллера для отображения формы создания книги:

public class BooksController : Controller
{
    public IActionResult Create()
    {
        return View();
    }
}

Затем давайте создадим Bookкласс модели:

public class Book
{
    public int Id { get; set; }
    [Display(Name = "Book Title")]
    public string Title { get; set; }
    public string Genre { get; set; }
    [DataType(DataType.Currency)]
    [Range(1, 100)]
    public decimal Price { get; set; }
    [Display(Name = "Publish Date")]
    [DataType(DataType.Date)]
    public DateTime PublishDate { get; set; }
}

Для следующего шага давайте определим a BooksLookupServiceдля предоставления данных списка для жанров:

public class BooksLookupService
{
    public List GetGenres()
    {
        return new List()
        {
            "Fiction",
            "Thriller",
            "Comedy",
            "Autobiography"
        };
    }
}

Затем давайте создадим представление и внедрим в него экземпляр BooksLookupService:

@model WorkingWithDI.Models.Book
@inject WorkingWithDI.Models.Services.BooksLookupService BooksLookupService
@{
    ViewData["Title"] = "Create";
    var genres = BooksLookupService.GetGenres();
}
<h1>Create</h1>
<h4>Book</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>
            <div>
                <label asp-for="Genre" class="control-label"></label>
                <select asp-items="@(new SelectList(genres))" class="form-control" ></select>
            </div>
            <div class="form-group">
                <label asp-for="Price" class="control-label"></label>
                <input asp-for="Price" class="form-control" />
                <span asp-validation-for="Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="PublishDate" class="control-label"></label>
                <input asp-for="PublishDate" class="form-control" />
                <span asp-validation-for="PublishDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-action="Index">Back to List</a>
</div>

Это предоставит значения списка в представление.

В качестве последнего шага нам нужно зарегистрировать типы, которые мы запрашиваем через внедрение зависимостей, в Startup.ConfigureServices(). Если тип не зарегистрирован, он генерирует исключение времени выполнения.

services.AddTransient<BooksLookupService>();

Вот и все. Теперь давайте запустим приложение и перейдем к Create Booksформе:

Мы видим, что список жанров заполняется путем получения значений из файла BooksLookupService.

Отлично, мы научились внедрять зависимость прямо в представление.

Вывод

В этой статье мы изучили следующие темы:

В следующей части этой серии мы узнаем о модульном тестировании в ASP.NET Core MVC .