Как обрабатывать несколько кнопок отправки в одной форме ASP.NET MVC?
Решение с использованием атрибута name и привязки к действиям контроллера
Самый распространённый и простой способ — дать кнопкам одинаковый атрибут name, но разные value. Затем в контроллере можно проверить, какое значение пришло, и вызвать соответствующий метод. Однако в ASP.NET MVC есть более элегантное решение — использовать атрибут value как имя действия.
Вот как это работает:
- Дайте кнопкам атрибут
name="submitButton"(или любое другое имя). - Установите разные значения
value, которые будут соответствовать именам методов контроллера. - Создайте один метод
[HttpPost], который принимает модель и строку с именем кнопки. - Внутри метода используйте
switchилиifдля вызова нужной логики.
Пример кода представления:
@using (Html.BeginForm("HandleForm", "Article"))
{
@Html.HiddenFor(m => m.Id)
@Html.EditorFor(m => m.Title)
@Html.EditorFor(m => m.Content)
<input type="submit" name="action" value="SaveDraft" />
<input type="submit" name="action" value="Publish" />
}
Контроллер:
[HttpPost]
public ActionResult HandleForm(ArticleViewModel model, string action)
{
if (!ModelState.IsValid)
{
return View(model);
}
switch (action)
{
case "SaveDraft":
// Логика сохранения черновика
TempData["Message"] = "Черновик сохранён";
break;
case "Publish":
// Логика публикации
TempData["Message"] = "Статья опубликована";
break;
default:
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
return RedirectToAction("Index");
}
Более продвинутый подход: кастомный ActionMethodSelectorAttribute
Если вы хотите сохранить отдельные методы для каждой кнопки (как вы изначально пытались), можно создать свой атрибут, который проверяет значение кнопки в запросе. Это потребует больше кода, но даст более чистую архитектуру.
Создайте класс атрибута:
public class SubmitButtonAttribute : ActionMethodSelectorAttribute
{
public string ButtonName { get; set; }
public string ButtonValue { get; set; }
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
var value = controllerContext.HttpContext.Request[ButtonName];
return value != null && value == ButtonValue;
}
}
Теперь используйте его в контроллере:
[HttpPost]
[SubmitButton(ButtonName = "action", ButtonValue = "SaveDraft")]
public ActionResult SaveDraft(ArticleViewModel model)
{
// Сохранить черновик
return RedirectToAction("Index");
}
[HttpPost]
[SubmitButton(ButtonName = "action", ButtonValue = "Publish")]
public ActionResult Publish(ArticleViewModel model)
{
// Опубликовать
return RedirectToAction("Index");
}
Таким образом, ASP.NET MVC сам выберет правильный метод на основе нажатой кнопки. Этот подход более масштабируемый, если у вас много кнопок или сложная логика.
Важно: Не забывайте про валидацию модели и редирект после POST, чтобы избежать повторной отправки формы при обновлении страницы (принцип Post/Redirect/Get).
<<Альтернативный подход: использование JavaScript для изменения action формы
Если вы предпочитаете не смешивать логику в одном методе контроллера, можно решить задачу на стороне клиента с помощью JavaScript. Этот подход особенно удобен, когда кнопки должны отправлять форму на разные URL или когда у вас много кнопок с разной логикой.
Пример с jQuery:
@using (Html.BeginForm("SaveDraft", "Article"))
{
@Html.HiddenFor(m => m.Id)
@Html.EditorFor(m => m.Title)
@Html.EditorFor(m => m.Content)
<input type="submit" value="Сохранить черновик" class="btn-action" data-action="SaveDraft" />
<input type="submit" value="Опубликовать" class="btn-action" data-action="Publish" />
}
<script>
$(document).ready(function() {
$('.btn-action').on('click', function(e) {
e.preventDefault();
var action = $(this).data('action');
var form = $(this).closest('form');
form.attr('action', '/Article/' + action);
form.submit();
});
});
</script>
В контроллере у вас будут два отдельных метода:
[HttpPost]
public ActionResult SaveDraft(ArticleViewModel model)
{
// Логика
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Publish(ArticleViewModel model)
{
// Логика
return RedirectToAction("Index");
}
Плюсы: чистая архитектура контроллера, легко тестировать, не нужно парсить имена кнопок.
Минусы: зависимость от JavaScript (если JS отключён, форма не сработает корректно). Для критически важных форм лучше использовать серверный подход из первого ответа.