c# – 流畅的验证不接受带有千位分隔符的数字
我有一个ASP.NET MVC 5项目与Fluent Validation for MVC 5.我也使用jQuery掩码插件自动添加数千到双重值.
在我的模型中: [Display(Name = "Turnover")] [DisplayFormat(ApplyFormatInEditMode = true,ConvertEmptyStringToNull =true,DataFormatString ="#,##0")] public double? Turnover { get; set; } 在我看来,我有: <th class="col-xs-2"> @Html.DisplayNameFor(model=>model.Turnover) </th> <td class="col-xs-4"> @Html.TextBoxFor(model => model.Turnover,new { @class = "form-control number",placeholder="Enter number. Thousands added automatically" }) </td> <td class="col-xs-6"> @Html.ValidationMessageFor(model => model.Turnover,"",new { @class = "text-danger" }) </td> 为包含模型定义流畅的验证器,但不包含任何规则.我仅使用服务器端验证. public class MyModelValidator: AbstractValidator<MyModel> { public MyModelValidator() { } } 不幸的是,我收到的营业额验证错误如下: 我试过使用Model Binding来解决这个问题.但是,模型绑定器中的断点从不受到打击 – 流畅的验证似乎阻止了达到模型绑定的价值. 解决方法
几件事情提到:
>这个问题与Fluent Validation无关.我可以使用或不使用流畅的验证来重现/修复它. 现在就这个问题.实际上有两个解决方案.他们都使用以下帮助类进行实际的字符串转换: using System; using System.Collections.Generic; using System.Globalization; public static class NumericValueParser { static readonly Dictionary<Type,Func<string,CultureInfo,object>> parsers = new Dictionary<Type,object>> { { typeof(byte),(s,c) => byte.Parse(s,NumberStyles.Any,c) },{ typeof(sbyte),c) => sbyte.Parse(s,{ typeof(short),c) => short.Parse(s,{ typeof(ushort),c) => ushort.Parse(s,{ typeof(int),c) => int.Parse(s,{ typeof(uint),c) => uint.Parse(s,{ typeof(long),c) => long.Parse(s,{ typeof(ulong),c) => ulong.Parse(s,{ typeof(float),c) => float.Parse(s,{ typeof(double),c) => double.Parse(s,{ typeof(decimal),c) => decimal.Parse(s,}; public static IEnumerable<Type> Types { get { return parsers.Keys; } } public static object Parse(string value,Type type,CultureInfo culture) { return parsers[type](value,culture); } } 自定义IModelBinder 这是链接方法的修改版本.它是一个单一的类来处理所有的数值类型和它们各自的可空类型: using System; using System.Web.Mvc; public class NumericValueBinder : IModelBinder { public static void Register() { var binder = new NumericValueBinder(); foreach (var type in NumericValueParser.Types) { // Register for both type and nullable type ModelBinders.Binders.Add(type,binder); ModelBinders.Binders.Add(typeof(Nullable<>).MakeGenericType(type),binder); } } private NumericValueBinder() { } public object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext) { var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); var modelState = new ModelState { Value = valueResult }; object actualValue = null; if (!string.IsNullOrWhiteSpace(valueResult.AttemptedValue)) { try { var type = bindingContext.ModelType; var underlyingType = Nullable.GetUnderlyingType(type); var valueType = underlyingType ?? type; actualValue = NumericValueParser.Parse(valueResult.AttemptedValue,valueType,valueResult.Culture); } catch (Exception e) { modelState.Errors.Add(e); } } bindingContext.ModelState.Add(bindingContext.ModelName,modelState); return actualValue; } } 所有你需要的是在你的Application_Start中注册它: protected void Application_Start() { NumericValueBinder.Register(); // ... } 自定义TypeConverter 这不是特定于ASP.NET MVC 5,但是DefaultModelBinder将字符串转换委托给相关联的 幸运的是System.ComponentModel提供了可扩展的Type Descriptor Architecture,它允许您关联一个自定义的TypeConverter.管道部分有点复杂(您必须注册一个定制的 using System; using System.ComponentModel; using System.Globalization; class NumericTypeDescriptionProvider : TypeDescriptionProvider { public static void Register() { foreach (var type in NumericValueParser.Types) TypeDescriptor.AddProvider(new NumericTypeDescriptionProvider(type,TypeDescriptor.GetProvider(type)),type); } readonly Descriptor descriptor; private NumericTypeDescriptionProvider(Type type,TypeDescriptionProvider baseProvider) : base(baseProvider) { descriptor = new Descriptor(type,baseProvider.GetTypeDescriptor(type)); } public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType,object instance) { return descriptor; } class Descriptor : CustomTypeDescriptor { readonly Converter converter; public Descriptor(Type type,ICustomTypeDescriptor baseDescriptor) : base(baseDescriptor) { converter = new Converter(type,baseDescriptor.GetConverter()); } public override TypeConverter GetConverter() { return converter; } } class Converter : TypeConverter { readonly Type type; readonly TypeConverter baseConverter; public Converter(Type type,TypeConverter baseConverter) { this.type = type; this.baseConverter = baseConverter; } public override bool CanConvertTo(ITypeDescriptorContext context,Type destinationType) { return baseConverter.CanConvertTo(context,destinationType); } public override object ConvertTo(ITypeDescriptorContext context,CultureInfo culture,object value,Type destinationType) { return baseConverter.ConvertTo(context,culture,value,destinationType); } public override bool CanConvertFrom(ITypeDescriptorContext context,Type sourceType) { return baseConverter.CanConvertFrom(context,sourceType); } public override object ConvertFrom(ITypeDescriptorContext context,object value) { if (value is string) { try { return NumericValueParser.Parse((string)value,type,culture); } catch { } } return baseConverter.ConvertFrom(context,value); } } } (是的,很多样板代码为了添加一个基本的线!另一方面,没有必要处理可空类型,因为DefaultModelBinder已经这样做:) 与第一种方法类似,您需要注意的是: protected void Application_Start() { NumericTypeDescriptionProvider.Register(); // ... } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |