Лучшая практика проверки модели MVC3 перенаправление после изменения сообщения / состояния

#asp.net-mvc-3 #redirect

#asp.net-mvc-3 #перенаправление

Вопрос:

Учитывая, что веб-приложения всегда должны перенаправляться после POST (или любого неповторяемого запроса на изменение состояния на стороне сервера) …

… как люди используют проверку модели MVC3 и выполняют обязательное перенаправление?

Ответ №1:

Обычно вы перенаправляете только после успешного сообщения (без ошибок проверки модели), в противном случае вы отправляете страницу обратно с сообщением об ошибке проверки.

Перенаправление в шаблоне PRG предотвращает двойную публикацию, поэтому нет никакого вреда в отправке той же страницы ( сообщение об ошибке), потому что сообщение не было успешным и не будет, если что-то не изменится для прохождения проверки.

Редактировать:

Похоже, вы ищете переход ModelState к следующему (перенаправленному) запросу. Это можно сделать, используя TempData для сохранения ModelState до следующего запроса. К вашему сведению, TempData использует сеанс.

Это может быть реализовано с ActionFilters помощью . Примеры можно найти в коде проекта MvcContrib: ModelStateToTempDataAttribute

Это также упоминалось вместе с другими советами в статье «Лучшие практики» по weblogs.asp.net (кажется, автор переместил блог, но я не смог найти статью в новом блоге). Из статьи:

Одна из проблем с этим шаблоном заключается в том, что при сбое проверки или возникновении какого-либо исключения вам необходимо скопировать ModelState в TempData. Если вы делаете это вручную, пожалуйста, остановите это, вы можете сделать это автоматически с помощью фильтров действий, например, следующим образом:

Контроллер

 [AcceptVerbs(HttpVerbs.Get), OutputCache(CacheProfile = "Dashboard"), StoryListFilter, ImportModelStateFromTempData]
public ActionResult Dashboard(string userName, StoryListTab tab, OrderBy orderBy, int? page)
{
    //Other Codes
    return View();
}

[AcceptVerbs(HttpVerbs.Post), ExportModelStateToTempData]
public ActionResult Submit(string userName, string url)
{
    if (ValidateSubmit(url))
    {
        try
        {
            _storyService.Submit(userName, url);
        }
        catch (Exception e)
        {
            ModelState.AddModelError(ModelStateException, e);
        }
    }

    return Redirect(Url.Dashboard());
}
  

Фильтры действий

 public abstract class ModelStateTempDataTransfer : ActionFilterAttribute
{
    protected static readonly string Key = typeof(ModelStateTempDataTransfer).FullName;
}

public class ExportModelStateToTempData : ModelStateTempDataTransfer
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        //Only export when ModelState is not valid
        if (!filterContext.Controller.ViewData.ModelState.IsValid)
        {
            //Export if we are redirecting
            if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
            {
                filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
            }
        }

        base.OnActionExecuted(filterContext);
    }
}

public class ImportModelStateFromTempData : ModelStateTempDataTransfer
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        ModelStateDictionary modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary;

        if (modelState != null)
        {
            //Only Import if we are viewing
            if (filterContext.Result is ViewResult)
            {
                filterContext.Controller.ViewData.ModelState.Merge(modelState);
            }
            else
            {
                //Otherwise remove it.
                filterContext.Controller.TempData.Remove(Key);
            }
        }

        base.OnActionExecuted(filterContext);
    }
}
  

Комментарии:

1. Это неверно. Существует много вреда … за всеми сообщениями должно следовать перенаправление. (1) Это единственный способ удалить запрос POST из истории браузера (2) В противном случае пользователи, нажимающие «НАЗАД» или «ОБНОВИТЬ», получат запутанное и раздражающее подтверждение «повторной отправки» (3) Пользователь, выбирающий «повторную отправку», не имеет возможности узнать, каким может быть конечный результат действия! Это было отличительной чертой веб-приложений профессионального качества более 15 лет. (Не распространено в ASP или ASP.NET веб-приложения, хотя) Кроме того, даже GET, который пытается неповторяемое изменение состояния, должен быть перенаправлен.

2. Я просто хотел сказать, что если проверка модели завершается неудачей, состояние сервера не изменяется, и поэтому, даже если тот же POST-запрос будет отправлен повторно, состояние сервера все равно не изменится. Но если вы решительно настроены подавить раздражающие подтверждения повторной отправки для этого конкретного случая (неудачная публикация без изменений состояния сервера), почему бы вам просто не перенаправить? Вероятно, вам понадобится сеанс (например, TempData), чтобы передать хотя бы сообщение об ошибке проверки перенаправленному запросу и сообщить пользователю, почему сообщение не удалось. Но опять же, отображение состояния сеанса в запросе GET не очень удобно…

3. «состояние сервера не изменено» // этот запрос — это не так, но вы предполагаете, что в следующий раз оно также не будет изменено // вы не можете сделать это предположение // кроме того, это только часть проблемы // и дублирование перехвата должно выполняться на стороне сервера, чтобы быть надежным// «просто перенаправить» как мне получить доступ к ModelState при следующем запросе?

4. Я отредактировал и связал с примером кода. Я надеюсь, что это то, что вы ищете.

5. Я думаю, что это недостающая ссылка из БЛОГА КАЗИ МАНЗУРА РАШИДА: weblogs.asp.net/rashid/archive/2009/04/01 /…

Ответ №2:

Что вы подразумеваете под «обязательным» перенаправлением? Часто мы используем try / catch в контроллере, если попытка прошла успешно, вы можете либо перенаправить на представление (если вам НУЖНО), либо также вернуть любое частичное представление или все, что вам нужно. Проблема часто заключается в повторном воспроизведении исходной страницы с сообщением об ошибке, поскольку запрос post не выполнен успешно.

Надеюсь, я вас правильно понял 🙂

Комментарии:

1. «обязательно» для профессиональных веб-приложений — уточните у fiddler — посмотрите, как это делают Google, IBM, PayPal или eBay… это редко для ASP или ASP.NET веб-приложения для правильной реализации этого, потому что Microsoft никогда не показывает технику в своих примерах (они не хотят сбивать людей с толку)