Une autre variante de @takepara de réponse, mais avec une tournure différente:
1) je préfère l'opt-in "StringTrim" attribut mécanisme (plutôt que de l'opt-out "NoTrim" exemple de @Anton).
2) Un appel supplémentaire à SetModelValue est nécessaire pour assurer la ModelState est rempli correctement et la validation par défaut/accepter/rejeter le modèle peut être utilisé comme d'habitude, c'est à dire tryupdatemodel pour mettre(modèle) pour appliquer et ModelState.Clear() pour accepter toutes les modifications.
Mettez ceci dans votre entité/bibliothèque partagée:
/// <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
{
}
Ensuite dans votre application MVC/bibliothèque:
/// <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 vous ne définissez pas la valeur de la propriété dans le classeur, même lorsque vous ne voulez pas changer quoi que ce soit, vous allez bloquer cette propriété de ModelState tout à fait! C'est parce que vous êtes inscrit à titre de liaison de tous les types de chaînes, de sorte qu'il apparaît (dans mes tests) que le classeur par défaut ne le fera pas pour vous, alors.