MVC3: Why won't my ModelError propagate to my view?
I'm working on a .NET MVC3 app. When I get an error in my controller, the error never ends up in my view. Why?
My action method looks like this:
[HttpPost]
public ActionResult Create(UserProfile model)
{
if ( !ModelState.IsValid )
{
return View(model);
}
try
{
DependencyResolver.Current.GetService<IUserProfileService>().CreateUser(
model.Email, /* mapped to UserName param; we use email addy as the username */
model.Password,
model.Email,
model.FirstName,
model.LastName,
model.Phone,
model.Fax,
model.RememberMe);
}
catch ( Exception ex )
{
ViewData.ModelState.AddModelError( string.Empty, ex );
return View(model);
}
return RedirectToAction(Actions.Subscriptions);
}
My view is pretty boring:
...
@using (Html.BeginForm())
{
@Html.ValidationSummary( true )
<div>
<div class="row">
<label>@Html.LabelFor(m => m.FirstName)</label>
@Html.TextBoxFor(m => m.FirstName)
@Html.ValidationMessageFor( m => m.FirstName )
</div>
<div class="row">
<label>@Html.LabelFor(m =&开发者_如何学运维gt; m.LastName)</label>
@Html.TextBoxFor(m => m.LastName)
@Html.ValidationMessageFor( m => m.LastName )
</div>
... etc. ...
</div>
}
If I post a form for a person whose username is already in use (e.g. legacy data where the email used for username is different than the email used for the email address), the CreateUser()
call throws an exception:
System.ApplicationException was caught
Message=Error Creating User: User already exists
We then fall into the catch block, add the error to the ModelState collection, and return the view. So far, so good -- examining the ModelState shows the error on the 10th element in the collection (the 1st 9 elements map to the individual model properties).
But my view never displays the error! I expect it to appear where I call @Html.ValidationSummary()
, but there's only an empty element there:
<div class="validation-summary-errors"><ul><li style="display:none"></li></ul></div>
This happens whether I pass true
or false
to @Html.ValidationSummary()
, and whether I name the source of the error when I add to the ModelState collection or not:
ViewData.ModelState.AddModelError( string.Empty, ex );
ViewData.ModelState.AddModelError( "UserName", ex );
So, the user posts the form, it's rejected, and it's just redisplayed with no error message, so the don't know what to do to fix the problem.
So, I'm trying to figure out why my error isn't propagated back to the view. And, I'd like to intercept the error message and make it more explicit, so it's obvious that the "User" we're talking about is the email they entered on the form.
Any help appreciated!
OK, I finally found the problem: the AddModelError()
method has two overloads, one that takes an Exception, and one that takes a string. When I pass the entire exception:
ViewData.ModelState.AddModelError( string.Empty, ex );
, I get no error rendered in the ValidationSummary. When I pass the exception's Message string:
ViewData.ModelState.AddModelError( string.Empty, ex.Message );
the error message renders properly.
Now back to our regularly scheduled programming.
I believe it has to match the property name exactly when you add a model error. I dont see one for username?
Ensure any validation message works
- Set the flag in the web.config:
- Include a reference to the jQuery library ~/Scripts/jquery-1.4.4.js
- Include a reference to the library that hooks this magic at ~/Scripts/jquery.unobtrusive-ajax.js
- make sure your model has a [Required()] attribute on a field so you can test the validation (non nullable integer fields are by default required and dont need an attribute)
精彩评论