Контроллеры

Контроллеры и их действия

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7

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

Центральным звеном в архитектуре ASP.NET Core MVC является контроллер. При получении запроса система маршрутизации выбирает для обработки запроса нужный контроллер и передает ему данные запроса. Контроллер обрабатывает эти данные и посылает обратно результат обработки.

В ASP.NET Core MVC контроллер представляет обычный класс на языке C#, который наследуется от абстрактного базового класса Microsoft.AspNetCore.Mvc.Controller. По умолчанию проект ASP.NET Core MVC содержит как минимум один контроллер - HomeController:

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 });
	}
}

В данном случае мы видим, что констроллер имеет конструктор, через который посредством механизма dependency injection передается сервис ILogger, используемый для логгирования. Также контроллер определяет три метода - Index, Privacy и Error.

При использовании контроллеров существуют некоторые условности. Во-первых, в проекте контроллеры помещаются в каталог Controllers. И во-вторых, по соглашениям об именовании названия контроллеров обычно оканчиваются на суффикс "Controller", остальная же часть до этого суффикса считается именем контроллера, например, HomeController. Но в принципе эти условности необязательны.

Но есть также и обязательные условности, которые предъявляются к контроллерам. В частности, класс контроллера должен удовлетворять как минимум одному из следующих условий:

  • Класс контроллера имеет суффикс "Controller"

    public class HomeController
    {  
    	//............  
    }
    
  • Класс контроллера наследуется от класса, который имеет суффикс "Controller"

    public class Home : Controller
    {
    	//.............
    }
    
  • К классу контроллера применяется атрибут [Controller]

    [Controller]
    public class Home
    {
    	//..................
    }
    

Если нам нужен еще один контроллер, то мы можем добавить в папку Controllers новый класс, который будет наследоваться от класса Controller. Либо мы можем использовать готовый шаблон Controller Class:

Добавление контроллера в ASP.NET Core

Контроллер, как и любой класс на языке C#, может иметь поля, свойства, методы. По умолчанию HomeController имеет четыре метода, которые можно назвать действиями. Действия контроллера - это публичные методы, которые могут сопоставляться с запросами. Например, стандартный контроллер содержит метод Index - он имеет модификатор public и поэтому может использоваться для обработки запроса.

Чтобы обратиться контроллеру из веб-браузера, нам надо в адресной строке набрать адрес_сайта/Имя_контроллера/Действие_контроллера. Так, по запросу адрес_сайта/Home/Index система маршрутизации по умолчанию вызовет метод Index контроллера HomeController для обработки входящего запроса. Например:

Обращение к методу контроллера ASP.NET MVC Core

Однако такое сопоставление строки url с названием контроллера и его метода происходит благодаря системе маршрутизации. Если мы обратимся к классу Startup и его методу Configure(), то мы можем найти там определение единственного для приложения маршрута:

app.UseEndpoints(endpoints =>
{
	endpoints.MapControllerRoute(
			name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
});

Метод endpoints.MapControllerRoute добавляет один маршрут с именем default и шаблоном "{controller=Home}/{action=Index}/{id?}". Данный шаблон устанавливает трехсегментную структуру строки запроса: controller/action/id. То есть в начале идет название контроллера, затем название действия, и далее может идти необязательный параметр id.

Собственно поэтому система может соотнести запрос типа localhost:xxxx/Home/Index с контроллером и его действием.

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

protected internal string Hello()
{
    return "Hello ASP.NET";
}

Поскольку его модификатор отличается от public, то мы не сможем обратиться к этому методу с запросом localhost:xxxx/Home/Hello. Хотя такие не публичные методы также могут быть полезными - в них можно определять какие-нибудь промежуточные вычисления и затем использовать в действиях контроллера. При этом если мы изменим модификатор метода на public, то метод Hello станет полноценным действием:

Действия контроллера

Атрибуты NonController, ActionName и NonAction

Возможно, сопоставление по умолчанию бывает не всегда удобно. Например, у нас есть класс в папке Controllers, но мы не хотим, чтобы он мог обрабатывать запрос и использоваться как контроллер. Чтобы указать, что этот класс не является контроллером, нам надо использовать над ним атрибут [NonController]:

[NonController]
public class HomeController : Controller
{
	//...........
}

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

[NonAction]
public string Hello()
{
    return "Hello ASP.NET";
}

Атрибут [ActionName] позволяет для метода задать другое имя действия. Например:

[ActionName("Welcome")]
public string Hello()
{
    return "Hello ASP.NET";
}

В этом случае чтобы обратиться к этому методу, надо отправить запрос localhost:xxxx/Home/Welcome. А запрос localhost:xxxx/Home/Hello работать не будет.

Типы запросов

В прошлой главе для обработки запросов использовалась следующая пара методов:

[HttpGet]
public IActionResult Buy(int? id)
{
    if (id == null) return RedirectToAction("Index");
    ViewBag.PhoneId = id;
    return View();
}
[HttpPost]
public string Buy(Order order)
{
    db.Orders.Add(order);
    // сохраняем в бд все изменения
    db.SaveChanges();
    return "Спасибо, " + order.User + ", за покупку!";
}

Несмотря на то, что здесь два разных метода, но они в соответствии с именем образуют одно действие Buy. Допустимо определять в контроллере методы с одним и тем же именем, только в этом случае они должны различаться по параметрам, как в данном случае.

Кроме того, методы в рамках одного действия могут обслуживать разные запросы. Для указания типа запроса HTTP нам надо применить к методу один из атрибутов: [HttpGet], [HttpPost], [HttpPut], [HttpDelete] и [HttpHead]. Если атрибут явным образом не указан, то метод может обрабатывать все типы запросов: GET, POST, PUT, DELETE.

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