如何使用自定义模型绑定器过滤表单数据

Jos*_*ose 9 asp.net-mvc

我有一堆表格,其中输入了货币值,我希望他们能够输入"$ 1,234.56".默认情况下,模型绑定器不会将其解析为小数.

我想要做的是创建一个自定义模型绑定器继承DefaultModelBinder,重写BindProperty方法,检查属性描述符类型是否为十进制,如果是,只需从值中删除$和.

这是最好的方法吗?

码:

public class CustomModelBinder : DefaultModelBinder
{
 protected override void BindProperty( ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor )
 {
  if( propertyDescriptor.PropertyType == typeof( decimal ) || propertyDescriptor.PropertyType == typeof( decimal? ) )
  {
   var newValue = Regex.Replace( bindingContext.ValueProvider[propertyDescriptor.Name].AttemptedValue, @"[$,]", "", RegexOptions.Compiled );
   bindingContext.ValueProvider[propertyDescriptor.Name] = new ValueProviderResult( newValue, newValue, bindingContext.ValueProvider[propertyDescriptor.Name].Culture );
  }

  base.BindProperty( controllerContext, bindingContext, propertyDescriptor );
 }
}
Run Code Online (Sandbox Code Playgroud)

更新

这就是我最终做的事情:

public class CustomModelBinder : DataAnnotationsModelBinder
{
    protected override void BindProperty( ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor )
    {
        if( propertyDescriptor.PropertyType == typeof( decimal ) || propertyDescriptor.PropertyType == typeof( decimal? ) )
        {
            decimal newValue;
            decimal.TryParse( bindingContext.ValueProvider[propertyDescriptor.Name].AttemptedValue, NumberStyles.Currency, null, out newValue );
            bindingContext.ValueProvider[propertyDescriptor.Name] = new ValueProviderResult( newValue, newValue.ToString(), bindingContext.ValueProvider[propertyDescriptor.Name].Culture );
        }
        base.BindProperty( controllerContext, bindingContext, propertyDescriptor );
    }
}
Run Code Online (Sandbox Code Playgroud)

Cra*_*ntz 5

在活页夹中这样做是合理的.但是,我认为Decimal.Parse使用货币格式提供者或数字样式(参见文档)比剥离"$"和调用更可靠base.对于初学者来说,它会处理非美国货币,这对你来说可能是个问题.


lom*_*axx 5

在MVC3中,您可以注册一个专门为十进制类型实现IModelBinder接口的自定义模型绑定器,然后通过使用bindingContext上的ModelMetaData.DataTypeName属性告诉它处理货币或十进制.

我已经修改了Phil Haack在他的文章中提供的示例,以演示如何完成它:

    public class DecimalModelBinder : IModelBinder
    {

        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            var modelState = new ModelState { Value = valueResult };

            decimal actualValue = 0;
            try
            {

                if(bindingContext.ModelMetadata.DataTypeName == DataType.Currency.ToString())
                    decimal.TryParse(valueResult.AttemptedValue, NumberStyles.Currency, null, out actualValue);
                else
                    actualValue = Convert.ToDecimal(valueResult.AttemptedValue,CultureInfo.CurrentCulture);


            }
            catch (FormatException e)
            {
                modelState.Errors.Add(e);
            }

            bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
            return actualValue;
        }
    }
Run Code Online (Sandbox Code Playgroud)