Кроме GET-запросов также широко применяются POST-запросы. Как правило, такие запросы отправляются с помощью форм на веб-странице. Но основные принципы передачи данных будут теми же, что и в GET-запросах.
Для передачи POST-запросов определим в следующий контроллер с двумя методами:
using Microsoft.AspNetCore.Mvc; namespace MvcApp.Controllers { public class HomeController : Controller { [HttpGet] public async Task Index() { string content = @"<form method='post'> <label>Name:</label><br /> <input name='name' /><br /> <label>Age:</label><br /> <input type='number' name='age' /><br /> <input type='submit' value='Send' /> </form>"; Response.ContentType = "text/html;charset=utf-8"; await Response.WriteAsync(content); } [HttpPost] public string Index(string name, int age) => $"{name}: {age}"; } }
Первый метод Index имеет атрибут [HttpGet], поэтому данный метод будет обрабатывать только запросы GET. Для упрощения примера в ответ метод будет возвращать html-код с формой ввода (хотя естественно, для формы html можно было бы определить отдельную html-страницу или представление)
Эта форма содержит два поля ввода. Что важно, первое поле имеет имя "name", которое задается с помощью атрибута "name":
<input name='name' />
Второе поле имеет имя "age":
<input type='number' name='age' />
Таким образом, при обращении к методу пользователь увидит в браузере форму ввода. При нажатии на кнопку Send введенные данные будут отправляться на сервер.
Поскольку у элемента <form>
не задан атрибут action
, который устанавливает адрес, то введенные данные отправляются на тот же адрес (то есть по сути
методу с тем же именем - методу Index).
Но поскольку у формы установлен атрибут method='post'
, то данные будут отправлять в запросе типа POST. А запросы данного типа обрабатывает второй метод Index:
[HttpPost] public string Index(string name, int age) => $"{name}: {age}";
Чтобы система могла связать параметры метода и данные формы, необходимо, чтобы атрибуты name
у полей формы соответствовали названиям параметров. То есть в данном случае
параметры метода Index называются так же, как и поля формы - name и age.
При получении данных форм действуют те же правила привязки, что и при получении параметров строки запроса. Поэтому с той же формы можно получить значения в виде сложных объектов, в которых названия свойств соответствуют названиям полей формы:
using Microsoft.AspNetCore.Mvc; namespace MvcApp.Controllers { public class HomeController : Controller { public async Task Index() { string content = @"<form method='post'> <label>Name:</label><br /> <input name='name' /><br /> <label>Age:</label><br /> <input type='number' name='age' /><br /> <input type='submit' value='Send' /> </form>"; Response.ContentType = "text/html;charset=utf-8"; await Response.WriteAsync(content); } [HttpPost] public string Index(Person person) => $"{person.Name}: {person.Age}"; } public record class Person(string Name, int Age); }
В данном случае поля формы name и age соответствуют по названию свойствам класса Person, поэтому вместо одиночных разрозненных значений мы можем получить отправленную форму в виде объекта Person.
Для передачи массивов с помощью формы надо создать набор одноименных полей, которые называются по имени массива:
using Microsoft.AspNetCore.Mvc; namespace MvcApp.Controllers { public class HomeController : Controller { public async Task Index() { string form = @"<form method='post'> <p><input name='names' /></p> <p><input name='names' /></p> <p><input name='names' /></p> <input type='submit' value='Send' /> </form>"; Response.ContentType = "text/html;charset=utf-8"; await Response.WriteAsync(form); } [HttpPost] public string Index(string[] names) { string result = ""; foreach(string name in names) { result = $"{result} {name}"; } return result; } } }
В данном случае на форме, отправляемой пользователю, расположены три поля с именем "names". В итоге при отправке формы будет сформирован массив names из трех элементов, который можно получить во втором методе Index:
И также у элементов формы можно было бы явным образом указать индексы:
<form method='post'> <p><input name='names[0]' /></p> <p><input name='names[2]' /></p> <p><input name='names[1]' /></p> <input type='submit' value='Send' /> </form>
Также можно было бы вовсе ограничиться одними индексами
<form method='post'> <p><input name='[0]' /></p> <p><input name='[2]' /></p> <p><input name='[1]' /></p> <input type='submit' value='Send' /> </form>
Передача словарей в метод контроллера аналогична передаче элементов массивов за тем исключением, что для каждого элемента устанавливается ключ:
using Microsoft.AspNetCore.Mvc; namespace MvcApp.Controllers { public class HomeController : Controller { [HttpGet] public async Task Index() { string content = @"<form method='post'> <p> Германия: <input type='text' name='items[germany]' /> </p> <p> Франция: <input type='text' name='items[france]' /> </p> <p> Испания: <input type='text' name='items[spain]' /> </p> <p> <input type='submit' value='Отправить' /> </p> </form>"; Response.ContentType = "text/html;charset=utf-8"; await Response.WriteAsync(content); } [HttpPost] public string Index(Dictionary<string, string> items) { string result = ""; foreach (var item in items) { result = $"{result} {item.Key} - {item.Value}; "; } return result; } } }
При отправке массивов сложных объектов на форме также определяется набор полей, где каждое поле привязано к определенному свойству объекта:
using Microsoft.AspNetCore.Mvc; namespace MvcApp.Controllers { public class HomeController : Controller { public async Task Index() { string form = @"<form method='post'> <p> Person1 Name:<br/> <input name='people[0].name' /><br/> Person1 Age:<br/> <input name='people[0].age' /> </p> <p> Person2 Name:<br/> <input name='people[1].name' /><br/> Person2 Age:<br/> <input name='people[1].age' /> </p> <input type='submit' value='Send' /> </form>"; Response.ContentType = "text/html;charset=utf-8"; await Response.WriteAsync(form); } [HttpPost] public string Index(Person[] people) { string result = ""; foreach(Person person in people) { result = $"{result} \n{person}"; } return result; } } public record class Person(string Name, int Age); }
В данном случае на форму вводятся значения для свойств Name и Age двух объектов Person. После отправке эти объекты уйдут в виде массива people второму методу Index.
Для получения данных отправленных форм можно использовать свойство Request.Form. Это свойство представляет коллекцию IFormsCollection
,
где каждый элемент имеет ключ и значение. В качестве ключа элемента выступает название поля формы, а в качестве значения - введенные в это поле данные:
using Microsoft.AspNetCore.Mvc; namespace MvcApp.Controllers { public class HomeController : Controller { public async Task Index() { string content = @"<form method='post' action='/Home/PersonData'> <label>Name:</label><br /> <input name='name' /><br /> <label>Age:</label><br /> <input type='number' name='age' /><br /> <input type='submit' value='Send' /> </form>"; Response.ContentType = "text/html;charset=utf-8"; await Response.WriteAsync(content); } [HttpPost] public string PersonData() { string name = Request.Form["name"]; string age = Request.Form["age"]; return $"{name}: {age}"; } } }