Validating integer field with custom model binder in ASP.NET MVC
I ran into an issue that I thought was interesting.
Take an input form that has an input field for an integer value (cost, in my case). I do not want "$100" or "Twenty Dollars" to be sent to the database as it will likely complain. I want to add an error to the model and send it back to the user. Seemed simple ;).
I am using a custom model binder because I am using some inheritance in my domain model. I have multiple types of events, each type implementing IEvent - thus, I needed a custom model binder.
The issue I have is, when I am trying to bind the cost field, and the conversion from string to int fails, I am really not sure how best to handle this.
My Custom Model Binder public class EventModelBinder : IModelBinder { #region IModelBinder Members
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// Trivial code ... binding other fields...
_event.ProjectedCost = GetA<int>(bindingContext, "ProjectedCost").GetValueOrDefault(-1);
return _event;
}
#endregion
// From Scott Hanselman's blog :)
private Nullable<T> GetA<T>(ModelBindingContext bindingContext, string key) where T : struct
{
if (String.IsNullOrEmpty(key)) return null;
ValueProviderResult valueResult;
Nullable<T> ret;
//Try it with the prefix...
bindingContext.ValueProvider.TryGetValue(bindingContext.ModelName + "." + key, out valueResult);
//Didn't work? Try without the prefix if needed...
if (valueResult == null && bindingContext.FallbackToEmptyPrefix == true)
{
bindingContext.ValueProvider.TryGetValue(key, out valueResult);
}
if (valueResult == null)
{
return null;
}
try
{
ret = (Nullable<T>)valueResult.ConvertTo(typeof(T));
}
catch
{
return null;
}
return ret;
}
This works really well - if Enums are null or not selected, I can validate against them and let the user know it is required. For the cost field, I get -1 if the conversion failed. But, when I go to validate the data on the server and go back to the UI, the Model.Event.ProjectedCost field is null
My EventService
// ...
protected bool ValidateEvent(IEvent eventToValidate)
{
if (eventToValidate.ProjectedCost < 0)
_validationDictionary.AddError("ProjectedCost", "Incorrect format");
return _validationDictionary.IsValid;
}
public bool SaveEvent(IEvent _event)
{
if (!ValidateEvent(_event))
return false;
try
{
_repository.SaveEvent(_event);
return true;
}
catch
{
return false;
}
My Edit.aspx View
<h2>Edit</h2>
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<p>
<label for="ProjectedCost">ProjectedCost:</label>
<%= Html.TextBox("ProjectedCost", Model.Event.ProjectedCost) %>
<%= Html.ValidationMessage("ProjectedCost", "*") %>
</p>
<% Html.RenderPartial(String.Format("~/Views/Shared/{0}Form.ascx", Model.Event.Type), Model.Event, ViewData); %>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>
In my view, Model.Event.ProjectedCost is null if it doesn't validate, giving me this (Line 54 is the culprit):
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Source Error:
Line 52: <p>
Line 53: <label for="ProjectedCost">ProjectedCost:</label>
Line 54: <%= Html.TextBox("ProjectedCost", (Model.Event.ProjectedCost == null ? 0 : Model.Event.ProjectedCost)) %>
Line 55: <%= Html.ValidationMessage("ProjectedCost", "*") %>
Line 56: </p>
What I'd开发者_如何学Python kind of like to do is send the value the user entered back to the user, but my custom model binder and/or validation logic seems to be setting something to null?
I realize this may not be the easiest question to read, so let me know if I can clarify in any way!
You could use javascript to restrict the input of the the textbox to just integers.
Seems that if you call AddModelError without SetModelValue first, you'll get a shiny-new NullReferenceExceptions sometimes:
http://www.crankingoutcode.com/?aspxerrorpath=/2009/02/01/IssuesWithAddModelErrorSetModelValueWithMVCRC1.aspx
精彩评论