模型将空格字符绑定到字符属性
本文关键字:字符 属性 绑定 模型 空格 | 更新日期: 2024-09-24 12:46:47
我有一个带有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 - 绑定后,模型属性具有空字符值
'0
为什么空格字符没有绑定到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()); })