如何防止复杂类型的默认绑定器?

时间:2012-11-14 19:22:22

标签: asp.net-mvc-4 model-binding

我有一个自定义类型Money的模型绑定器。绑定器工作正常,但内置的绑定/验证正在进行,并将数据标记为无效。

我的活页夹看起来像这样:

public class MoneyModelBinder : DefaultModelBinder 
{
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var money = (Money)bindingContext.Model;
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Amount").AttemptedValue;
        var currencyCode = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Iso3LetterCode").AttemptedValue;

        Money parsedValue;
        if (String.IsNullOrEmpty(value))
        {
            money.Amount = null;
            return;
        }

        var currency = Currency.FromIso3LetterCode(currencyCode);

        if(!Money.TryParse(value, currency, out parsedValue))
        {
            bindingContext.ModelState.AddModelError("Amount", string.Format("Unable to parse {0} as money", value));
        }
        else
        {
            money.Amount = parsedValue.Amount;
            money.Currency = parsedValue.Currency;
        }
    }
}

当用户在文本框中键入类似“45,000”的值时,我的活页夹会正确地获取值,解析它并将其设置到模型中。

我遇到的问题是默认验证然后启动状态The value '45,000' is not valid for Amount,因为它是十进制类型有意义,但我已经绑定了数据。如何防止我已经处理的默认绑定器绑定数据?

我不确定这是否有所不同,但我正在使用Html.EditorFor和编辑器,如下所示:

@model Money

<div class="input-prepend">
  <span class="add-on">@Model.Currency.Symbol</span>
    @Html.TextBoxFor(m => m.Amount, new{
                            placeholder=string.Format("{0}", Model.Currency), 
                            @class="input-mini",
                            Value=String.Format("{0:n0}", Model.Amount)
                            })
    @Html.HiddenFor(x => x.Iso3LetterCode)
</div>

3 个答案:

答案 0 :(得分:5)

您只需将Amount属性标记为只读:

[ReadOnly(true)]
public decimal? Amount { get; set; }

答案 1 :(得分:2)

如果您的ModelBinder代码驻留在同一个项目中,您可以将属性setter访问修饰符更改为internal。这样,DefaultModelBinder无法看到setter。

public class MyViewModel{
 public Money Stash { get; internal set; }
}

另一种方式可能只是使用字段

public class MyViewModel{
 public Money Stash;
}

这背后的原因是DefaultModelBinder只绑定读写属性。上述两个建议都将阻止这些条件得到满足。

答案 2 :(得分:1)

根据我的经验,有几种方法可以实现这一点(例如,允许默认绑定器绑定,但清除属性上的错误),但这样做的方式可以让任何维护代码的人明白你的意图是要覆盖不受欢迎的行为,即:

protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
{
    if (propertyDescriptor.Name != "Amount")
    {
        base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
    }
}

在这里的else块中实际执行自定义绑定也可能有意义,但这是由你来决定的。

相关问题