自定义模型绑定器来绑定嵌套属性值
问题描述:
我需要这个的原因:在我的一个控制器中,我想以不同于应用程序其余部分的方式绑定所有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
,但我不知道如何说服基类在处理小数属性时使用我的模型活页夹。
答
你可以无条件申请模型绑定在你的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的应用befoire它的自定义值:
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);
}