Otra variante de la respuesta de @ takepara pero con un giro diferente:
1) Prefiero el mecanismo de atributo "StringTrim" de aceptación (en lugar del ejemplo de exclusión "NoTrim" de @Anton).
2) Se requiere una llamada adicional a SetModelValue para garantizar que ModelState se complete correctamente y que el patrón de validación / aceptación / rechazo predeterminado se pueda usar de forma normal, es decir, TryUpdateModel (modelo) para aplicar y ModelState.Clear () para aceptar todos los cambios.
Ponga esto en su entidad / biblioteca compartida:
/// <summary>
/// Denotes a data field that should be trimmed during binding, removing any spaces.
/// </summary>
/// <remarks>
/// <para>
/// Support for trimming is implmented in the model binder, as currently
/// Data Annotations provides no mechanism to coerce the value.
/// </para>
/// <para>
/// This attribute does not imply that empty strings should be converted to null.
/// When that is required you must additionally use the <see cref="System.ComponentModel.DataAnnotations.DisplayFormatAttribute.ConvertEmptyStringToNull"/>
/// option to control what happens to empty strings.
/// </para>
/// </remarks>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class StringTrimAttribute : Attribute
{
}
Entonces esto en su aplicación / biblioteca MVC:
/// <summary>
/// MVC model binder which trims string values decorated with the <see cref="StringTrimAttribute"/>.
/// </summary>
public class StringTrimModelBinder : IModelBinder
{
/// <summary>
/// Binds the model, applying trimming when required.
/// </summary>
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// Get binding value (return null when not present)
var propertyName = bindingContext.ModelName;
var originalValueResult = bindingContext.ValueProvider.GetValue(propertyName);
if (originalValueResult == null)
return null;
var boundValue = originalValueResult.AttemptedValue;
// Trim when required
if (!String.IsNullOrEmpty(boundValue))
{
// Check for trim attribute
if (bindingContext.ModelMetadata.ContainerType != null)
{
var property = bindingContext.ModelMetadata.ContainerType.GetProperties()
.FirstOrDefault(propertyInfo => propertyInfo.Name == bindingContext.ModelMetadata.PropertyName);
if (property != null && property.GetCustomAttributes(true)
.OfType<StringTrimAttribute>().Any())
{
// Trim when attribute set
boundValue = boundValue.Trim();
}
}
}
// Register updated "attempted" value with the model state
bindingContext.ModelState.SetModelValue(propertyName, new ValueProviderResult(
originalValueResult.RawValue, boundValue, originalValueResult.Culture));
// Return bound value
return boundValue;
}
}
Si no establece el valor de la propiedad en la carpeta, incluso si no desea cambiar nada, ¡bloqueará esa propiedad de ModelState por completo! Esto se debe a que está registrado como enlace para todos los tipos de cadenas, por lo que parece (en mis pruebas) que el cuaderno predeterminado no lo hará por usted.