I want to write a modelbinder for ASP.NET MVC that will correct values that will be visible to the user. Maybe it will capitalize the initial letter of a value, trim strings, etc. etc.
I'd like to encapsulate this behavior within a modelbinder.
For instance here is a TrimModelBinder
to trim strings. (taken from here)
public class TrimModelBinder : DefaultModelBinder
{
protected override void SetProperty(ControllerContext controllerContext,
ModelBindingContext bindingContext,
System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
{
if (propertyDescriptor.PropertyType == typeof(string))
{
var stringValue = (string)value;
if (!string.IsNullOrEmpty(stringValue))
stringValue = stringValue.Trim();
value = stringValue;
}
base.SetProperty(controllerContext, bindingContext,
开发者_C百科 propertyDescriptor, value);
}
}
This will set the values into the model, but when the page is redisplayed the original values will persist (because they're in ModelState).
I'd like to just re-display the trimmed values to the user.
Theres a whole lot of methods to override - like OnPropertyValidated
, and OnPropertyValidating
etc.
I could probably get it to work, but I don't want to have some unintended side effect if I override the wrong method.
I'd rather not try to do a Trim() or whatever the logic is when I'm generating the view. I want to encapsulate this logic completely within a modelbinder.
Replace this class.
public class TrimModelBinder : DefaultModelBinder
{
protected override void SetProperty(ControllerContext controllerContext,
ModelBindingContext bindingContext,
System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
{
if (propertyDescriptor.PropertyType == typeof(string))
{
var stringValue = (string)value;
if (!string.IsNullOrEmpty(stringValue))
stringValue = stringValue.Trim();
value = stringValue;
bindingContext.ModelState[propertyDescriptor.Name].Value =
new ValueProviderResult(stringValue,
stringValue,
bindingContext.ModelState[propertyDescriptor.Name].Value.Culture);
}
base.SetProperty(controllerContext, bindingContext,
propertyDescriptor, value);
}
}
Edit: modified by simon
(original had null reference exception and added change to support hierarchical model)
protected override void SetProperty(ControllerContext controllerContext,
ModelBindingContext bindingContext,
System.ComponentModel.PropertyDescriptor propertyDescriptor,
object value)
{
string modelStateName = string.IsNullOrEmpty(bindingContext.ModelName) ? propertyDescriptor.Name :
bindingContext.ModelName + "." + propertyDescriptor.Name;
// only process strings
if (propertyDescriptor.PropertyType == typeof(string))
{
if (bindingContext.ModelState[modelStateName] != null)
{
// modelstate already exists so overwrite it with our trimmed value
var stringValue = (string)value;
if (!string.IsNullOrEmpty(stringValue))
stringValue = stringValue.Trim();
value = stringValue;
bindingContext.ModelState[modelStateName].Value =
new ValueProviderResult(stringValue,
stringValue,
bindingContext.ModelState[modelStateName].Value.Culture);
}
else
{
// trim and pass to default model binder
base.SetProperty(controllerContext, bindingContext, propertyDescriptor, (value == null) ? null : (value as string).Trim());
}
}
else
{
base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
}
}
From within the model binder you have access to the ModelBindingContext
. On that you have access to ModelState
and you should be able to modify the values in that dictionary to be the trimmed values.
Maybe something like:
string trimmedValue = GetTheTrimmedValueSomehow();
modelBindingContext.ModelState[modelBindingContext.ModelName] = trimmedValue;
精彩评论