【问题标题】:Custom Model Binder to bind nested property values用于绑定嵌套属性值的自定义模型绑定器
【发布时间】:2012-02-24 16:59:56
【问题描述】:

我需要这个的原因:在我的一个控制器中,我想以与我的应用程序的其余部分不同的方式绑定所有 Decimal 值。我不想在 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,但我不知道如何说服基类在处理十进制属性时使用我的模型绑定器。

【问题讨论】:

    标签: asp.net-mvc-3 model-binding defaultmodelbinder


    【解决方案1】:

    您可以在Application_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);
        }
    }
    

    现在剩下的就是使用自定义过滤器装饰您的控制器操作以启用小数绑定:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-16
      • 2011-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-05
      相关资源
      最近更新 更多