Jak RedirectToAction w ASP.NET MVC bez utraty danych żądania

123

Korzystając z ASP.NET MVC, istnieją sytuacje (takie jak przesłanie formularza), które mogą wymagać pliku RedirectToAction.

Jedna z takich sytuacji ma miejsce, gdy po przesłaniu formularza napotkasz błędy walidacji i musisz przekierować z powrotem do formularza, ale chcesz, aby adres URL odzwierciedlał adres URL formularza, a nie stronę akcji, do której przesyła.

Ponieważ wymagam, aby formularz zawierał pierwotnie POSTzredagowane dane, dla wygody użytkownika, a także dla celów weryfikacji, w jaki sposób mogę przekazać dane przez RedirectToAction()? Jeśli użyję parametru viewData, moje POSTparametry zostaną zmienione na GETparametry.

Matt Mitchell
źródło
Oto pytanie podobne (na ten sam temat), ale inne niż to. W każdym razie, nadal może zainteresować tych, którzy są zainteresowani tym pytaniem: http://stackoverflow.com/questions/129335/how-do-you-redirecttoaction-using-post-intead-of-get
Chris Pietschmann
Dlaczego po prostu nie zwracasz tego samego widoku, jeśli wystąpi błąd? RedirectToAction jest zwykle wywoływane, jeśli model jest prawidłowy - lub czy czegoś mi brakuje ?!
niico

Odpowiedzi:

81

Rozwiązaniem jest użycie właściwości TempData do przechowywania żądanych składników Request.

Na przykład:

public ActionResult Send()
{
    TempData["form"] = Request.Form;
    return this.RedirectToAction(a => a.Form());
}

Następnie w akcji „Formularz” możesz:

public ActionResult Form()
{
    /* Declare viewData etc. */

    if (TempData["form"] != null)
    {
        /* Cast TempData["form"] to 
        System.Collections.Specialized.NameValueCollection 
        and use it */
    }

    return View("Form", viewData);
}
Matt Mitchell
źródło
1
RedirectToAction (a => a.Form ()) nie kompiluje się dla mnie przy użyciu MVCv2, czy używasz MVCv3?
ChrisAnnODell
1
Było to przed MVC1 (2008). Uważam, że lambdy zostały usunięte na pewnym etapie (istnieje projekt Codeplex MVCContrib, który je ponownie wprowadza, chociaż równie dobrze możesz użyć ich atrybutu pomocnika na tym etapie: stackoverflow.com/questions/1936/ ... ). W mvc2 powinieneś być w stanie przejść do RedirectToAction ("Form"), tj. Nazwać jako ciąg znaków, chociaż luźno pamiętam, że MVC 2 lub 3 wprowadziły atrybut pomocniczy podobny do tego w MVCContrib, jeśli chcesz szukać.
Matt Mitchell,
37

Należy pamiętać, że TempData przechowuje kolekcję formularzy w sesji. Jeśli nie podoba Ci się to zachowanie, możesz zaimplementować nowy interfejs ITempDataProvider i użyć innego mechanizmu do przechowywania danych tymczasowych. Nie zrobiłbym tego, chyba że wiesz na pewno (poprzez pomiary i profilowanie), że użycie stanu sesji jest dla Ciebie szkodliwe.

Haacked
źródło
13

Spójrz na MVCContrib , możesz to zrobić:

using MvcContrib.Filters;

[ModelStateToTempData]
public class MyController : Controller {
    //
    ...
}
Dan
źródło
8

Istnieje inny sposób uniknięcia danych tymczasowych. Wzorzec, który mi się podoba, obejmuje utworzenie 1 akcji zarówno dla oryginalnego renderowania, jak i ponownego renderowania nieprawidłowego formularza. To wygląda mniej więcej tak:

var form = new FooForm();

if (request.UrlReferrer == request.Url)
{
     // Fill form with previous request's data
}

if (Request.IsPost())
{
     if (!form.IsValid)
     {
         ViewData["ValidationErrors"] = ...
     } else {
         // update model
         model.something = foo.something;
         // handoff to post update action
         return RedirectToAction("ModelUpdated", ... etc);
     }
}

// By default render 1 view until form is a valid post
ViewData["Form"] = form;
return View();

To mniej więcej wzór. Trochę pseudo. Dzięki temu możesz utworzyć 1 widok do obsługi renderowania formularza, ponownego wyświetlania wartości (ponieważ formularz zostanie wypełniony poprzednimi wartościami) i wyświetlania komunikatów o błędach.

Podczas wysyłania do tej akcji, jeśli jest ona prawidłowa, przekazuje kontrolę nad inną akcją.

Staram się, aby ten wzorzec był łatwy w ramach walidacji .NET, gdy budujemy wsparcie dla MVC.

Dane O'Connor
źródło
Używam również TempData, problem, jak rozumiem, z twoim rozwiązaniem Deeno polega na tym, że jeśli użytkownik odświeży stronę po opublikowaniu nieprawidłowych danych, otrzyma potwierdzenie „Czy chcesz ponownie przesłać dane formularza”. Korzystanie z rozwiązania TempData, jak mówi MattMitchell, eliminuje ten problem.
user10479
Chłodny. Wygląda na to, że ktoś zauważył ten podstawowy pomysł w wersji zapoznawczej 5.
Matt Mitchell
2

Jeśli chcesz przekazać dane do przekierowanej akcji, możesz użyć metody:

return RedirectToAction("ModelUpdated", new {id = 1});
// The definition of the action method like  public ActionResult ModelUpdated(int id);
lzlstyle
źródło
0

TempData to rozwiązanie, które utrzymuje dane przed działaniem.

Employee employee = new Employee
                {
                        EmpID = "121",
                        EmpFirstName = "Imran",
                        EmpLastName = "Ghani"
                };
                TempData["Employee"] = employee;
Aswal
źródło