Работа с формами. Tag-хелперы форм

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

Для создания форм можно использовать стандартные элементы html. Однако для упрощения работы с формами ASP.NET Core также предоставляет группу tag-хелперов, с помощью которых можно определять формы html и их элементы. Рассмотрим применение подобных хелперов. Допустим, у нас есть страница Razor Index.cshtml и код связанной модели IndexModel в файле Index.cshtml.cs:

OnGet и OnPost в Razor Page в ASP.NET Core и C#

FormTagHelper

Пусть в файле Index.cshtml.cs определен следующий код:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPagesApp.Pages
{
    public class IndexModel : PageModel
    {
        [BindProperty]
        public Product Product { get; set; } = new("", 0, "");
        public string Message { get; private set; } = "Добавление товара";

        public void OnPost()
        {
            Message = $"Добавлен новый товар: {Product.Name} ({Product.Company})";
        }
    }

    public record class Product(string Name, int Price, string Company);
}

Здесь ожидается, что в post-запросе модель IndexModel будет получать данные в виде объекта Product. Для автоматической привязки данных запроса к объекту Person к свойству применяется атрибут BindProperty.

После получения объекта в запросе POST переустанавливается значение свойства Message.

Далее в файле Index.cshtml с помощью tag-хелперов определим форму для отправки данных:

@page 
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@model RazorPagesApp.Pages.IndexModel

<h2>@Model.Message</h2>
<form method="post" asp-antiforgery="true">
    <p>
        <label asp-for="Product.Name">Название</label><br />
        <input type="text" asp-for="Product.Name" />
    </p>
    <p>
        <label asp-for="Product.Price">Цена</label><br />
        <input asp-for="Product.Price" />
    </p>
    <p>
        <label asp-for="Product.Company">Производитель</label><br />
        <input type="text" asp-for="Product.Company" />
    </p>
    <input type="submit" value="Отправить" />
</form>

Тег-хелперы, используемые для создания форм, аналогичны соответствующим элементам html за тем исключением, что они добавляют дополнительную функциональность. Так, для создания формы используется класс FormTagHelper, представленный тегом form. Кроме стандартного атрибута method тег form также применяет атрибут asp-antiforgery указывает, будет ли для формы генерироваться antiforgery-токен. Если он имеет значение true, то токен будет генерироваться. Благодаря этому для модели IndexModel не нужно применять атрибут [IgnoreAntiforgeryToken], поскольку по умолчанию для страниц Razor требуется наличие подобного токена

 //[IgnoreAntiforgeryToken] - атрибут не нужен
public class IndexModel : PageModel

Все поля ввода, которые использовались выше на форме, имеют один общий атрибут asp-for, который указывает, для какого свойства модели создается элемент. Например:

<input type="text" asp-for="Product.Name" />

Здесь атрибут asp-for указывает, что данный элемент будет применяться для ввода значения для свойства Product.Name. Таким образом, мы можем привязать поля ввода к определенным свойствам модели.

tag-хелперы форм на страницах Razor Pages в ASP.NET Core и C#

Класс FormTagHelper может принимать следующие атрибуты:

  • asp-controller: указывает на контроллер, которому предназначен запрос

  • asp-action: указывает на действие контроллера

  • asp-area: указывает на название области, в которой будет вызываться контроллер для обработки формы

  • asp-antiforgery: если имеет значение true, то для этой формы будет генерироваться antiforgery token

  • asp-route: указывает на название маршрута

  • asp-all-route-data: устанавливает набор значений для параметров

  • asp-route-[название параметра]: определяет значение для определенного параметра

  • asp-page: указывает на страницу RazorPage, которая будет обрабатывать запрос

  • asp-page-handler: указывает на обработчик страницы RazorPage, который применяется для обработки запроса

  • asp-fragment: указывает фрагмент, который добавляется к запрашиваемому адресу после символа #.

Например, если необходимо сделать запрос на другую страницу, то можно использовать атрибут asp-page:

<form method="post" asp-page="Create">

В данном случае запрос идет на возможную страницу Create.cshtml.

С помощью атрибута asp-page-handler можно указать обработчик страницы, который будет обрабатывать запрос:

<form method="post" asp-page="Create" asp-page-handler="Person">

В данном случае запрос идет на возможную страницу Create.cshtml и ее обработчику (по сути запрос будет обрабатываться методом OnPostPerson() при наличие такового).

Рассмотрим вкратце ряд основных хелперов, которые могут применяться для создания элементов форм.

LabelTagHelper

LabelTagHelper использует тег label для создания метки:

<label asp-for="Name"></label>

InputTagHelper

InputTagHelper создает поле ввода:

<input asp-for="Name" />

TextAreaTagHelper

TextAreaTagHelper используется для создания многострочного текстового поля textarea. Данный хелпер применяет только атрибут asp-for:

<textarea asp-for="Name"></textarea>

SelectTagHelper

SelectTagHelper создает элемент списка <select>. Он имеет специальный атрибут asp-items, который указывает на объект IEnumerable<SelectListItem> - набор элементов, используемых для создания списка.

Рассмотрим одну из ситуаций, где может потребоваться подобный хелпер. Пусть в файле Index.cshtml.cs определен следующий код:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace RazorPagesApp.Pages
{
    public class IndexModel : PageModel
    {
        // условные данные
        static List<Company> companies { get; } = new()
        {
            new Company(1, "Apple"),
            new Company(2, "Samsung"),
            new Company(3, "Google")
        };
        public SelectList Companies { get; } = new SelectList(companies, "Id", "Name");
        [BindProperty]
        public Product Product { get; set; } = new("", 1000, 0);
        public string Message { get; private set; } = "Добавление товара";

        public void OnPost()
        {
            // получаем производителя товара
            Company? company = companies.FirstOrDefault(c => c.Id == Product.CompanyId);
            Message = $"Добавлен новый товар: {Product.Name} ({company?.Name})";
        }
    }
    public record class Product(string Name, int Price, int CompanyId);
    public record class Company(int Id, string Name);
}

Здесь определены две сущности - Product и Company. Причем у класса Product определено свойство CompanyId, через которое объект Product будет связан с определенным объектом Company.

В классе модели IndexModel определены условные данные - статический список объектов Company, из которого будет выбираться производитель для добавления товара.

Но для отображения списка объектов в tag-хелпере SelectTagHelper нам нужен объект IEnumerable<SelectListItem>. В качестве такового обычно выступает объект класса SelectList.

Класс SelectList имеет ряд конструкторов:

public SelectList (IEnumerable items);
public SelectList (IEnumerable items, object selectedValue);
public SelectList (IEnumerable items, string dataValueField, string dataTextField);
public SelectList (IEnumerable items, string dataValueField, string dataTextField, object selectedValue);

Параметры конструктора:

  • items задает набор элементов для списка

  • selectedValue устанавливливает выделенное по умолчанию значение

  • dataValueField устанавливливает свойство объекта, значение которого будет отправляться на сервер

  • dataTextField устанавливливает свойство объекта, значение которого будет отображаться для данного элемента в списке

То есть в данном случае свойство

public SelectList Companies { get; } = new SelectList(companies, "Id", "Name");

Что будет создаваться список из набора companies. В качестве значений, которые будет выбирать пользователь, будут использоваться значения свойства Id. А в качестве текста, который будет отображаться для элемента, будет применяться текст свойства Name.

На странице Index.cshtml определим форму для ввода данных:

@page 
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@model RazorPagesApp.Pages.IndexModel

<h2>@Model.Message</h2>
<form method="post" asp-antiforgery="true">
    <p>
        <label asp-for="Product.Name">Название</label><br />
        <input type="text" asp-for="Product.Name" />
    </p>
    <p>
        <label asp-for="Product.Price">Цена</label><br />
        <input asp-for="Product.Price" />
    </p>
    <p>
        <label asp-for="Product.CompanyId">Производитель</label><br />
        <select asp-for="Product.CompanyId" asp-items="Model.Companies"></select>
    </p>
    <input type="submit" value="Отправить" />
</form>

Для создания выпадающего списка здесь применяется следующий tag-хелпер

<select asp-for="Product.CompanyId" asp-items="Model.Companies"></select>

Атрибуту asp-items передается объект SelectList, из которого будет создаваться список

asp-items и SelectList на страницах Razor Pages и C#

При необходимости мы можем указать элемент, который будет отображаться по умолчанию:

<select asp-for="Product.CompanyId" asp-items="Model.Companies">
	<option selected="selected" disabled="disabled">Выберите компанию</option>
</select>

Обработка форм и обработчики страниц razor

Razor Pages также позволяет отправлять форму различным обработчикам одной и той же страницы. Для этого у тега формы можно указать нужный обработчик с помощью параметра asp-page-handler. Более того можно указать у отдельных кнопок, на какой обработчик они отправятся данные формы. Например, изменим код IndexModel:

using Microsoft.AspNetCore.Mvc.RazorPages;

namespace RazorPagesApp.Pages
{
    public class IndexModel : PageModel
    {
        // условные данные
        IEnumerable<Person> people = new List<Person>
       {
            new ("Tom", 37),
            new ("Sam", 28),
            new ("Bob", 41),
            new ("Tim", 25)
        };
        public IEnumerable<Person> DisplayedPeople { get; private set; } = new List<Person>();
        public void OnGet()
        {
            DisplayedPeople = people;
        }
        public void OnPostGreaterThan(int age)
        {
            DisplayedPeople = people.Where(p => p.Age > age);
        }
        public void OnPostLessThan(int age)
        {
            DisplayedPeople = people.Where(p => p.Age < age);
        }
    }
    public record class Person(string Name, int Age);
}

Обработчик OnPostGreaterThan находит пользователей, у которых возраст больше определенного, а обработчик OnPostLessThan, наоборот, находит пользователей, у которых возраст меньше, чем определенный.

Изменим код страницы Index.cshtml:

@page "{handler?}"

@model PersonModel
@using RazorPagesApp.Models

<h2>Список пользователей</h2>
<form method="POST">
    <input type="number" name="age" />
    <input type="submit" asp-page-handler="GreaterThan" value="Старше" />
    <input type="submit" asp-page-handler="LessThan" value="Младше" />
</form>
<table class="table">
    <tr><th>Name</th><th>Age</th></tr>
    @foreach(Person person in Model.DisplayedPeople)
    {
        <tr>
            <td>@person.Name</td>
            <td>@person.Age</td>
        </tr>
    }
</table>

На странице определена форма, но в зависимости от того, на какую кнопку мы нажмем, введенное значение будет улетать тому или иному обработчику.

POST handlers in Razor Pages in ASP.NET Core и C#
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850