2010-07-20 1 views
4

если я начать на Detail странице:, как я могу держать свой URL, когда моя проверка неудачу в ASP.NET MVC контроллер действий

http:\\www.mysite.com\App\Detail 

У меня есть действие контроллера под названием Update, который обычно называют redirectToAction Назад к подробнее страница. но у меня есть ошибка, которая попадает в валидацию, и мне нужно вернуться до перенаправления (, чтобы избежать потери всего моего ModelState). Вот мой код контроллера:

public override ActionResult Update(Application entity) 
    { 
     base.Update(entity); 
     if (!ModelState.IsValid) 
     { 
      return View("Detail", GetAppViewModel(entity.Id)); 
     } 
     return RedirectToAction("Detail", new { id = entity.Id }) 

, но теперь я вижу, вид с сообщениями об ошибках валидации (как я использую HTML.ValidationSummary()), но URL выглядит следующим образом:

http:\\www.mysite.com\App\Update 

является в любом случае я могу избежать изменения URL-адреса без какого-либо взлома помещения modelstate в некоторые временные переменные? Есть ли лучшая практика здесь, поскольку единственные примеры, которые я видел, ставят ModelState в некоторых tempdata между звонками redirectToAction.

ответ

5

С ASP.NET MVC 2, нет какого-либо такого API- вызова, который поддерживает URL оригинального метода действия, когда return View() вызывается из другого метода действия.

Таким образом, рекомендуемое решение и общепринятое соглашение в ASP.NET MVC должно иметь соответствующий, аналогично именованный метод действий, который принимает только глагол HTTP POST. Таким образом, в вашем случае, если другой метод действия с именем Detail, как это, должен решить вашу проблему с другим URL-адресом, когда проверка не выполняется.

[HttpPost] 
public ActionResult Detail(Application entity) 
{ 
    base.Update(entity); 
    if (ModelState.IsValid) 
    { 
     //Save the entity here 
    } 
    return View("Detail", new { id = entity.Id }); 
} 

Это решение в соответствии с ASP.NET MVC передовой практики, а также избавляет от необходимости возиться с modestate и tempdate.

Кроме того, если вы еще не изучили эту опцию, тогда Проверка на стороне клиента в asp.net mvc также может обеспечить некоторое решение проблемы вашего URL-адреса. Я подчеркиваю , так как этот подход не будет работать, если в браузере отключен javascript.

Итак, лучшим решением будет метод действия с именем Detail, но принимающий только HTTP POST глагол.

+0

@Bikal Gurung - спасибо. ,Я всегда думал, что это была странная практика, поскольку имя действия на самом деле не представляет то, что вы делаете, но я согласен, что это решит проблему, о которой я спрашиваю о – leora

+0

, которую вы можете исправить с помощью [ActionName («Подробности») ] public ActionResult WhatEverMethodName() Теперь этот метод будет соответствовать «/ Details» –

+0

«Это решение соответствует лучшим практикам ASP.NET MVC ...» - я бы сказал, что это ** не ** в соответствии с лучшими практики. Возвращение формы запроса POST напрямую противоречит шаблону PRG, который лучше всего подходит для всего веб-сайта, а не только для ASP.NET MVC. Существует множество способов соблюдения шаблона PRG в ASP.NET MVC, но наиболее распространенным способом является уже упомянутый подход ModelState-> TempData-> ModelState. Вы можете прочитать больше на PRG здесь: http://en.wikipedia.com/wiki/Post/Redirect/Get и хорошая реализация с атрибутами по адресу http://tinyurl.com/39p54k8 –

1

Лучшая практика, которую вы просите, на самом деле то, что вы объяснили, не нужно делать: ставить модель в tempdata. Tempdata предназначен для этого, поэтому я бы не назвал это взломом.

Если это много повторяющийся код, вы можете использовать атрибут modeldatatotempdata MVCContrib. Но в магазине все еще есть TempData.

3

Проблема на самом деле вызвана вашей реализацией. Это не отвечает на ваш вопрос, но в нем описывается, где вы ошиблись в первую очередь.

Если вы хотите использовать страницу, которая используется для обновления или редактирования элемента, URL-адрес должен отражать это. Например.

Вы посещаете http: \ www.mysite.com \ App \ Detail и отображает некоторую информацию о чем-то. Это то, что описывает URL-адрес, который он собирается сделать. В вашем контроллере метод Detail() вернет представление Detail.aspx.

Чтобы отредактировать элемент, вы посетите http: \ www.mysite.com \ App \ Edit и измените информацию, которую хотите обновить, форма будет отправлена ​​обратно на тот же URL-адрес - вы можете справиться с этим в контроллере с этими методами:

[HttpGet] 
public ActionResult Edit() { 
    MyModel model = new MyModel(); 
    ... 
    return View(model); 
} 

[HttpPost] 
public ActionResult Edit(MyModel model) { 
    ... 
    if (ModelState.IsValid) { 
     // Save and redirect 
     ... 
     return RedirectToAction("Detail"); 
    } 
    return View(model); 
} 

Если вы когда-нибудь найти себе делать это ...

return View("SomeView", model); 

вы делаете свою жизнь труднее (а также нарушение принципов позади URL-адресов).

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

Я извиняюсь, что это потенциально не очень полезно, но вы попадаете в ловушку анти-шаблона MVC, отображая один и тот же вид из другого именованного метода.

2

Как @Malcolm саи, лучшая практика это поставить ModelState в TempData, но не делать это вручную! Если вы сделаете это вручную в каждом действии контроллера, где это уместно, вы представите огромное количество повторяющегося кода и значительно увеличите стоимость обслуживания.

Вместо этого реализуйте пару атрибутов , которые выполняют эту работу за вас. Kazi Manzur has an approach (прокрутите вниз до конца сообщения), который был широко распространен, а Эван Нагл показывает implementation with tests, который по сути такой же, как у Кази, но с разными именами. Поскольку он также предоставляет модульные тесты, которые гарантируют работу атрибутов, реализация их в вашем коде будет означать небольшую стоимость обслуживания или ее отсутствие. Единственное, что вам нужно будет отслеживать, это то, что действия контроллера украшены соответствующими атрибутами, которые также могут быть протестированы.

Если у вас есть атрибуты на месте, ваш контроллер может выглядеть примерно так (я намеренно упрощенным, потому что я не знаю, класс, который наследует от):

[HttpPost, PassState] 
public ActionResult Update(EntityType entity) 
{ 
    // Only update if the model is valid 
    if (ModelState.IsValid) { 
     base.Update(entity); 
    } 
    // Always redirect to Detail view. 
    // Any errors will be passed along automagically, thanks to the attribute. 
    return RedirectToAction("Detail", new { id = entity.Id }); 
} 

[HttpGet, GetState] 
public ActionResult Detail(int id) 
{ 
    // Get stuff from the database and show the view 
    // The model state, if there is any, will be imported by the attribute. 
} 

Вы сказали, что вы чувствуете, положив ModelState в TempData чувствует себя как «хак» - почему? Я согласен с вами в том, что делать это с помощью повторяющегося кода в каждом действии с контроллером кажется взломанным, но это не то, что мы делаем здесь. Фактически, this is exactly what TempData is for. И я не думаю, что этот код выглядит взломанным ... не так ли?

Хотя решения этой проблемы могут оказаться более простыми, например, просто переименовать метод действий для сохранения URL-адреса, я бы настоятельно рекомендовал против этого подхода. Он задает эту проблему, но вводит пару других - например, вы все равно не будете иметь защиты от отправки в виде двойной формы, и у вас будут довольно запутывающие имена действий (где звонок Detail фактически меняется на сервере).

Смежные вопросы