使用DefaultModelBinder自定义模型绑定

时间:2015-04-17 14:23:59

标签: c# asp.net-mvc

我正在尝试了解自定义绑定应该如何工作。

假设一个简单的动作

[HttpPost]
public ActionResult MyAction(CustomType parameter) {
    // do something
}

...以及以下表单数据

{
    parameter : "mydata"
    parameter.Property1 : "something"
    parameter.Property2 : 3
}

...以及以下非常简单的自定义活页夹

public class MyBinder : DefaultModelBinder {

        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {

            if (bindingContext.ModelType.Equals(typeof(CustomType))) {
                string parameter = controllerContext.HttpContext.Request.Form[bindingContext.ModelName];
                object model = controllerContext.HttpContext.Cache[parameter];

                return model;
            }

            return base.BindModel(controllerContext, bindingContext);

        }

        protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) {
            // not called
            return base.CreateModel(controllerContext, bindingContext, modelType);
        }

        protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor) {
            // not called
            base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        }

    }

我可以看到调用BindModel方法。但是,一旦我返回自定义对象,就永远不会为BindPropertyProperty1调用Property2方法。这是有道理的,因为我没有打电话给base.BindModel()

所以我的问题是:应该 BindModel如何实现,以便在超类中创建CustomType并调用BindModel

2 个答案:

答案 0 :(得分:0)

我暂时没有这样做,但是IIRC,您可以使用属性集来构建新的CustomType,而不是return new CustomType();

类似的东西:

return new CustomType
{
    Property1 = request.Form.Get("Property1"),
    ...
};

答案 1 :(得分:0)

我检查了DefaultModelBinder的源代码,发现了内部方法BindComplexElementalModel。使用此自定义数据绑定器可以实现所需的模型绑定行为。

public class MyBinder : DefaultModelBinder {

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {

        if (bindingContext.ModelType.Equals(typeof(CustomType))) {
            // get an instance of the model using the model prefix
            string parameter = controllerContext.HttpContext.Request.Form[bindingContext.ModelName];
            object model = controllerContext.HttpContext.Cache[parameter];

            // populate the remaining model properties using reflection (yuck)
            MethodInfo bindComplexElementalModel =
                base.GetType().GetMethod("BindComplexElementalModel", BindingFlags.NonPublic | BindingFlags.Instance);

            bindComplexElementalModel.Invoke(this, new object[] { controllerContext, bindingContext, model });

            return model;
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}

当然,使用内部框架方法并不是一个干净的解决方案,因此我将这个问题保持开放,希望有人能提供更好的答案。