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

时间:2009-12-16 16:39:36

标签: 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 );
 }
}

更新

这就是我最终做的事情:

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 );
    }
}

3 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:5)

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

我修改了Phil Haack in his article提供的示例,以演示如何完成:

    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;
        }
    }

答案 2 :(得分:1)

您可以创建自己的ValidationAttribute来检查值是否具有正确的格式。然后你可以查看属性是否使用此属性进行修饰并以适当的方式绑定它。属性不需要是ValidationAttibute,但它似乎是个好主意。