1

I have a HomeController with an Index.cshtml Razor view that uses an InitialChoicesViewModel with validation attributes. The Index view contains the following form:

@using (Html.BeginForm("CreateCharacter", "DistributePoints", FormMethod.Get))

This goes to a different controller (which is what I want):

public class DistributePointsController : Controller
{
    public ActionResult CreateCharacter(/* my form parameters */)
    // ...
}

How do I perform server-side validation on the form (such as checking ModelState.IsValid), returning my original Index view with a correct ValidationSummary on error? (On success I want to return the CreateCharacter view of the other controller.)


Based on John H's answer, I resolved this as follows:

@using (Html.BeginForm("CreateCharacter", "Home"))

HomeController:

[HttpPost]
// Only some of the model fields are posted, along with an additional name field.
public ActionResult CreateCharacter(InitialChoicesViewModel model, string name)
{
    if (ModelState.IsValid)
    {
        return RedirectToAction("CreateCharacter", "DistributePoints",
        new {name, model.Level, model.UseAdvancedPointSystem});
    }

    // Unsure how to post a collection - easier to reload from repository.
    model.ListOfStuff = _repository.GetAll().ToList();

    return View("Index", model);
}

I had to add a parameterless constructor to my view model, too.

TrueWill
  • 25,132
  • 10
  • 101
  • 150
  • 1
    This looks fine. There are times where you have to rebuild parts of your model in order for the view to be redisplayed. The perfect example of that is repopulating dropdown lists, as only the selected value of the dropdown is ever sent back to the server from the form. Plus, if you already have the data you need available server-side, it's better to query for it, rather than trusting input from the user. – John H Jan 01 '14 at 00:06

3 Answers3

3
[HttpPost]
public ActionResult CreateCharacter(InitialChoicesViewModel model)
{
    if (ModelState.IsValid)
        return RedirectToAction("SomeSuccessfulaction");

    return View("~/Views/Home/Index.cshtml", model);
}

The ~/ denotes the relative root of your site.

The code above complies with the Post-Redirect-Get pattern, in order to prevent some types of duplicate form submission problems. It does that by redirecting to a separate action when the form submission is successful, and by returning the current view, complete with ModelState information, on error.

John H
  • 14,422
  • 4
  • 41
  • 74
0

By default, ASP.NET MVC checks first in \Views\[Controller_Dir]\, but after that, if it doesn't find the view, it checks in \Views\Shared. If you do return View("~/Views/Wherever/SomeDir/MyView.aspx") You can return any View you'd like.

But for now in your case, try the following

public ActionResult CreateCharacter(SomeModel model)
{
if(!ModelState.IsValid){
 return View("~/Views/Home/Index.cshtml", model )
}
return View();
}
Ankush Jain
  • 5,654
  • 4
  • 32
  • 57
0

To check your ModelState just use an if statement in Controller:

if(ModelState.IsValid) 
{
   ...
}

If there is any error add you can add an error message to the ModelState Dictionary like this:

ModelState.AddModelError("Somethings failed", ErrorCodeToString(e.StatusCode));

After that return your same View and pass it to your model

return View(model);

If you add "@Html.ValidationSummary()" in your View, it will get the errors from the ModelState Dictionary and display them.But if you show values yourself maybe with different styles you can do it manually, take a look at this question

And if there is no error you can return your CreateCharacter View like this, just redirect user to the appropriate action:

return RedirectToAction("CreateCharacter","DistributePoints");
Community
  • 1
  • 1
Selman Genç
  • 100,147
  • 13
  • 119
  • 184