Asp.net mvc 3 用于绑定嵌套特性值的自定义模型绑定器

Asp.net mvc 3 用于绑定嵌套特性值的自定义模型绑定器,asp.net-mvc-3,model-binding,defaultmodelbinder,Asp.net Mvc 3,Model Binding,Defaultmodelbinder,我需要这样做的原因是:在我的一个控制器中,我希望以不同于应用程序其余部分的方式绑定所有十进制值。我不想在Global.asax中注册模型绑定器(通过ModelBinders.Binders.Add(typeof(decimal),new DecimalModelBinder());) 我尝试从DefaultModelBinder类派生并重写其BindProperty方法,但这只适用于模型实例的立即(非嵌套)十进制属性 我用以下示例来说明我的问题: namespace ModelBinderTes

我需要这样做的原因是:在我的一个控制器中,我希望以不同于应用程序其余部分的方式绑定所有十进制值。我不想在Global.asax中注册模型绑定器(通过
ModelBinders.Binders.Add(typeof(decimal),new DecimalModelBinder());

我尝试从
DefaultModelBinder
类派生并重写其
BindProperty
方法,但这只适用于模型实例的立即(非嵌套)十进制属性

我用以下示例来说明我的问题:

namespace ModelBinderTest.Controllers
{
    public class Model
    {
        public decimal Decimal { get; set; }
        public DecimalContainer DecimalContainer { get; set; }
    }

    public class DecimalContainer
    {
        public decimal DecimalNested { get; set; }
    }

    public class DecimalModelBinder : DefaultModelBinder
    {
        protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
        {
            if (propertyDescriptor.PropertyType == typeof (decimal))
            {                
                propertyDescriptor.SetValue(bindingContext.Model,  999M);
                return;
            }

            base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        }
    }

    public class TestController : Controller
    {

        public ActionResult Index()
        {
            Model model = new Model();
            return View(model);
        }

        [HttpPost]
        public ActionResult Index([ModelBinder(typeof(DecimalModelBinder))] Model model)
        {
            return View(model);
        }

    }
}

此解决方案仅将
Model
Decimal
属性设置为999,但不对
DecimalContainer
DecimalNested
属性执行任何操作。我意识到这是因为在我的
DecimalModelBinder
BindProperty
覆盖中调用了
base.BindProperty
,但是我不知道如何说服基类在处理十进制属性时使用我的模型绑定器。

您可以在
应用程序中无条件地应用模型绑定器\u Start

ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
然后有一个自定义授权筛选器(是的,在模型绑定器之前运行的授权筛选器),它将向HttpContext中注入一些值,模型绑定器稍后可以使用这些值:

[AttributeUsage(AttributeTargets.Method)]
public class MyDecimalBinderAttribute : ActionFilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        filterContext.HttpContext.Items["_apply_decimal_binder_"] = true;
    }
}
然后在模型绑定测试中,如果HttpContext在应用之前包含自定义值:

public class DecimalModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (controllerContext.HttpContext.Items.Contains("_apply_decimal_binder_"))
        {
            // The controller action was decorated with the [MyDecimalBinder]
            // so we can proceed
            return 999M;
        }

        // fallback to the default binder
        return base.BindModel(controllerContext, bindingContext);
    }
}
现在只剩下用自定义过滤器装饰控制器操作,以启用decimal活页夹:

[HttpPost]
[MyDecimalBinder]
public ActionResult Index(Model model)
{
    return View(model);
}