Содержание
Как мы уже знаем, контроллер занимается в MVC центральную роль в приложении — этот тот компонент, который обрабатывает запрос пользователя и отвечает за какие-либо действия. Здесь и далее в этой части мы будем изучать работу с контроллерами в ASP.NET Core MVC.
Вернемся к нашему первому приложению ASP.NET Core MVC и более детально рассмотрим класс контроллера HomeController
.
Что является контроллером в ASP.NET Core MVC
Посмотрим на контроллер в нашем первом приложении ASP.NET Core MVC и разберемся, что отличает контроллер от любого другого класса C#. Вот его код
public class HomeController : Controller { private readonly ILogger<HomeController> _logger; public HomeController(ILogger<HomeController> logger) { _logger = logger; } public IActionResult Index() { return View(); } public IActionResult Privacy() { return View(); } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } }
Первое, на что необходимо обратить внимание — это на то, что класс, который в нашем приложении является контроллером наследуется от класса Controller
. По соглашению, контроллером считаются следующие классы
- имя класса контроллера содержит суффикс Controller,
- класс наследуется от класса
Controller
- для класса указан атрибут
[Controller]
В нашем случае, использован второй вариант определения контроллера в приложении — наследование от класса Controller
, так как такой подход имеет ряд преимуществ, в том числе, доступ к контексту запроса и возможность использования вспомогательных методов отправки ответов клиенту.
Следуя перечисленным выше требованиям, мы можем задать нашему классу контроллера, например, такое название:
public class Home : Controller
при этом, ничего не изменится, класс всё также будет считаться контроллером с именем Home
. Если же мы будем использовать атрибут, например, так:
[Controller] public class Home
то получим максимально легковесный класс контроллера, но, при этом, теряем в этом классе некоторую функциональность, например, тот же доступ к контексту запроса.
Следующий момент, на который обратим внимание — это конструктор класса:
public HomeController(ILogger<HomeController> logger) { _logger = logger; }
в конструкторе класса контроллера обычно передаются зависимости с использованием механизма внедрения зависимостей. То есть, в нашем случае, в контроллер передается сервис логирования, с помощью которого мы можем писать лог работы приложения. Третий момент — это методы класса.
Действия контроллера
Все публичные методы класса контроллера по умолчанию считаются его действиями. И, хотя, как и любой другой метод C# действие контроллера может возвращать любой тип данных, например, строки или числа, обычно результатом действия контроллера является какой-либо объект, реализующий интерфейс IActionResult
. Например, в нашем классе контроллера определено действие:
public IActionResult Index() { return View(); }
Это действие возвращает объект типа ViewResult
, который является наследником абстрактного класса ActionResult
, реализующего интерфейс IActionResult
.
Действия контроллера обычно сопоставляются с маршрутом запроса. Если же мы хотим сделать так, чтобы публичный метод не был действием контроллера, то для такого метода применяется атрибут [NoAction]
. Например, применим этот атрибут для метода Index()
и посмотрим на результат
[NonAction] public IActionResult Index() { return View(); }
Система маршрутизации не смогла в итоге сопоставить запрос пользователя с необходимым действием (мы его исключили) и нам вернулся код ошибки 404.
Обращение к действиям контроллера
Чтобы мы могли обращаться к действиям контроллера, в ASP.NET Core используется система маршрутизации. Конкретно для ASP.NET Core MVC общепринятым считается использование трехсегментной структуры запроса. Например, как в нашем приложении:
app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
о методе MapControllerRoute()
мы говорили в предыдущей части. Такую систему удобно использовать для однозначной понятной системы обращения пользователей к ресурсам приложения. Например:
localhost:7212/Home/Index
— вернуть нам главную страницу приложенияlocalhost:7212/Tasks/Add
— добавить новую задачу в списокlocalhost:7212/Tasks/Delete/5
— удалить задачу с Id = 5- и т.д.
хотя, при желании мы можем использовать и двух- и четырех- сегментные схемы, но предложенная изначально трехсегментная система, на мой скромный взгляд, является наиболее удобной в использовании и логичной, в принципе, для ASP.NET Core MVC. Что ж, со структурой и особенностями контроллера разобрались. Теперь попробуем написать свой контроллер.
Первый контроллер в ASP.NET Core MVC
Создадим новое приложение ASP.NET Core MVC, как мы это делали в предыдущей части. Добавим в папку Controllers новый контроллер. Для этого, мы можем выбрать в контекстном мен. пункт «Контроллер»
или же создать обычный класс и применить к нему одно из условий, указанных выше для того, чтобы класс распознавался как контроллер. Я воспользуюсь контекстным меню:
Для примера был выбран шаблон пустого контролера. Название контроллера — SimpleController
. В итоге мы должны увидеть следующий код:
using Microsoft.AspNetCore.Mvc; namespace FirstMvcSite.Controllers { public class SimpleController1 : Controller { public IActionResult Index() { return View(); } } }
здесь уже определено одно действие Index
, но нам оно сегодня не понадобится, поэтому можем его смело удалить и напишем следующий метод:
//действие контроллера public string Hello() { return "Hello Controller"; }
здесь, исключительно ради примера, наше действие возвращает строку. Уже сейчас мы можем воспользоваться этим контроллером. Система маршрутизации сопоставит этот контроллер и действие с шаблоном маршрута, который используется сейчас по умолчанию:
немного усложним задачу и задействуем в работе контроллера третий сегмент пути (id
):
public class SimpleController : Controller { //действие контроллера public string Hello(string? id) { if (string.IsNullOrWhiteSpace(id)) return "Hello Controller"; else return $"Hello {id}"; } }
снова вернемся к шаблону маршрута и разберемся с тем, что теперь будет происходить в действии контроллера. Шаблон маршрута:
{controller=Home}/{action=Index}/{id?}
с первыми двумя параметрами все должно быть понятно — это имя контроллера и его действие. Третий параметр — необязательный, на что указывает знак вопроса после имени параметра. Следовательно и в методе действия контроллера мы определяем тип параметра допускающего null
и имя параметра метода соответствует имени параметра в шаблоне маршрута. Если третий параметр не будет задан или вместо него будет пробел, то вернется строка «Hello Controller», иначе, после Hello будет подставлено значение параметра. Например:
Итого
Контроллер в ASP.NET Core — это, обычно, публичный класс, соответствующий хотя бы одному из трех условий: унаследован от класса Controller
, содержит в названии суффикс Controller, для класса определен атрибут [Controller]
. Публичные методы класса контроллера не помеченные атрибутом [NoAction]
являются действиями контроллера, которые могут сопоставляться системой маршрутизации с шаблонами маршрутов. Действие контроллера может возвращать любые типы данных, но предпочтительным вариантом является возврат одного из объектов, реализующих интерфейса IActionResult
.