模型将空格字符绑定到字符属性



我有一个带有char属性的简单视图模型。。。

public char Character1 { get; set; }

默认模型绑定似乎没有将空格字符(")转换为此属性,导致以下ModelState错误。。。

The Character1 field is required.

html输入元素是用javascript:创建的

var input = $('<input type="password" name="Character' + i + '" id="input-' + i + '" data-val="true" data-val-custom maxlength="1"></input>');
  • 该属性上没有[Required]属性
  • 发布的值在模型错误AttemptedValue属性中肯定是"
  • 由于上述错误,ModelState.IsValid返回false
  • 绑定后,模型属性具有空字符值

为什么空格字符没有绑定到char属性?

更新:

char属性更改为string将按预期绑定。

我认为这是DefaultModelBinder的失败。如果在操作中使用FormCollection,字符串将返回为空格。

这个IModelBinder实现显示了默认模型绑定器的行为,并给出了一个可能的解决方案:

public class CharModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var dmb = new DefaultModelBinder();
        var result = dmb.BindModel(controllerContext, bindingContext);
        // ^^ result == null
        var rawValueAsChar = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ConvertTo(typeof(char));
        // ^^ rawValueAsChar == null
        var rawValueAsString = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).AttemptedValue;
        if(!string.IsNullOrEmpty(rawValueAsString))
            return rawValueAsString.ToCharArray()[0];
        return null;
    }
}

在您的Global.asax中注册:

ModelBinders.Binders.Add(typeof(char), new CharModelBinder());

原因很简单,char被定义为值类型(struct),而string被定义为引用类型(class)。这意味着char是不可为null的,并且必须有一个值。

这就是为什么DefaultModelBinder(您可能正在使用)会自动将此属性的验证元数据设置为required,即使您没有添加[Required]属性。

以下是ModelMetaData.cs的来源(第58行):

_isRequired = !TypeHelpers.TypeAllowsNullValue(modelType);

因此,Character1属性的ModelMetaData.Required最终被设置为true

但是,您可以显式配置DataAnnotationsModelValidatorProvider而不是,以使用以下命令自动将值类型设置为required

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

请参阅MSDN

好的,我在System.Web.Mvc.ValueProviderResult:中发现了有问题的代码

private static object ConvertSimpleType(CultureInfo culture, object value, Type destinationType)
    {
      if (value == null || destinationType.IsInstanceOfType(value))
        return value;
      string str = value as string;
      if (str != null && string.IsNullOrWhiteSpace(str))
        return (object) null;
      ...
}

我不确定这是否是一个bug。

最近在.NET Core中遇到了这个问题,因为SimpleTypeModelBinder有相同的检查,所以添加了以下内容:

使用系统;使用Microsoft.AspNetCore.Mvc.ModelBinding;公共类CharModelBinderProvider:IModelBinderProvider{///<inheritcoc/>公用IModelBinder GetBinder(ModelBinderProviderContext上下文){if(context==null){throw new ArgumentNullException((context)的名称);}if(context.Metadata.ModelType==typeof(char)){返回new CharModelBinder();}返回null;}}使用系统;使用System.ComponentModel;使用System.Runtime.ExceptionServices;使用System.Threading.Tasks;使用Microsoft.AspNetCore.Mvc.ModelBinding;///<inheritcoc/>///<摘要>///一个<参见cref=";T: Microsoft.AspNetCore.Mvc.ModelBinding.IModelBinder"/>对于char。///<摘要>///<备注>///这里的区别在于,我们允许空间作为<参见cref=";T: Microsoft.AspNetCore.Mvc.ModelBinding.SimpleTypeModelBinder"/>没有。///<备注>公共类CharModelBinder:IModelBinder{private只读TypeConverter _charConverter;公共CharModelBinder(){这个_charConverter=新的charConverter();}///<inheritcoc/>公共任务BindModelAsync(ModelBindingContext绑定上下文){if(bindingContext==null){throw new ArgumentNullException((bindingContext)的名称);}var valueProviderResult=bindingContext.ValueProvider.GetValue(bindingContext.ModelName);if(valueProviderResult==valueProviderResult.None){//禁止进入return Task.CompletedTask;}bindingContext.ModelState.SetModelValue(bindingContext.ModelName,valueProviderResult);尝试{var value=valueProviderResult.FirstValue;var模型=这个_charConverter.ConvertFrom(null,valueProviderResult.Culture,value);这CheckModel(bindingContext,valueProviderResult,model);return Task.CompletedTask;}catch(异常异常){var isFormatException=异常为FormatException;if(!isFormatException&&exception.InerException!=null){//TypeConverter抛出System.Exception包装FormatException,因此我们捕获内部异常。exception=ExceptionDispatchInfo.Capture(exception.InerException).SourceException;}bindingContext.ModelState.TryAddModelError(bindingContext_ModelName,异常,bindingContext.ModelMetadata);//我们能够找到该类型的转换器,但转换失败。return Task.CompletedTask;}}受保护的虚拟void CheckModel(ModelBindingContext绑定上下文,ValueProviderResult值ProviderResult,对象模型){//转换newModel时,null值可能表示对其他所需模型的转换失败(不能将ValueType设置为null)。//这将检测在给定当前bindingContext的情况下是否可以接受空模型值。如果没有,则会记录一个错误。if(model==null&&!bindingContext.ModelMetadata.IsReferenceOrNullableType){bindingContext.ModelState.TryAddModelError(bindingContext.ModelName,bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(valueProviderResult.ToString());}其他的{bindingContext.Result=ModelBindingResult.Success(模型);}}}

在启动过程中:

serviceCollection.AddMvc(options => { options.ModelBinderProviders.Insert(0, new CharModelBinderProvider()); })

最新更新