简体   繁体   中英

How can i use a ModelBinder to correct values that will then be visible to the user?

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, 
                          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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM