Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to trim strings after data entry. Should I create a custom model binder?

People also ask

Which interface should be implemented to create custom binder?

To create custom model binder class, it needs to inherit from IModelBinder interface. This interface has async method named "BindModelAsync" and it has parameter of type ModelBindingContext. The ModelBindingContext class provides the context that model binder functions.

What is the purpose of model binding?

Model binding is a well-designed bridge between the HTTP request and the C# action methods. It makes it easy for developers to work with data on forms (views), because POST and GET is automatically transferred into a data model you specify. ASP.NET MVC uses default binders to complete this behind the scene.

What are model binders?

Model binding is a process in which we bind a model to controller and view. It is a simple way to map posted form values to a . NET Framework type and pass the type to an action method as a parameter. It acts as a converter because it can convert HTTP requests into objects that are passed to an action method. Example.


  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.IsNullOrWhiteSpace(stringValue))
        {
          value = stringValue.Trim();
        }
        else
        {
          value = null;
        }
      }

      base.SetProperty(controllerContext, bindingContext, 
                          propertyDescriptor, value);
    }
  }

How about this code?

ModelBinders.Binders.DefaultBinder = new TrimModelBinder();

Set global.asax Application_Start event.


This is @takepara same resolution but as an IModelBinder instead of DefaultModelBinder so that adding the modelbinder in global.asax is through

ModelBinders.Binders.Add(typeof(string),new TrimModelBinder());

The class:

public class TrimModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext,
    ModelBindingContext bindingContext)
    {
        ValueProviderResult valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (valueResult== null || valueResult.AttemptedValue==null)
           return null;
        else if (valueResult.AttemptedValue == string.Empty)
           return string.Empty;
        return valueResult.AttemptedValue.Trim();
    }
}

based on @haacked post: http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx


One improvement to @takepara answer.

Somewere in project:

public class NoTrimAttribute : Attribute { }

In TrimModelBinder class change

if (propertyDescriptor.PropertyType == typeof(string))

to

if (propertyDescriptor.PropertyType == typeof(string) && !propertyDescriptor.Attributes.Cast<object>().Any(a => a.GetType() == typeof(NoTrimAttribute)))

and you can mark properties to be excluded from trimming with [NoTrim] attribute.


In ASP.Net Core 2 this worked for me. I'm using the [FromBody] attribute in my controllers and JSON input. To override the string handling in the JSON deserialization I registered my own JsonConverter:

services.AddMvcCore()
    .AddJsonOptions(options =>
        {
            options.SerializerSettings.Converters.Insert(0, new TrimmingStringConverter());
        })

And this is the converter:

public class TrimmingStringConverter : JsonConverter
{
    public override bool CanRead => true;
    public override bool CanWrite => false;

    public override bool CanConvert(Type objectType) => objectType == typeof(string);

    public override object ReadJson(JsonReader reader, Type objectType,
        object existingValue, JsonSerializer serializer)
    {
        if (reader.Value is string value)
        {
            return value.Trim();
        }

        return reader.Value;
    }

    public override void WriteJson(JsonWriter writer, object value,
        JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}