MVC 3自定义模型绑定到平面形式变量结构

时间:2013-08-12 13:18:13

标签: asp.net-mvc-3 custom-model-binder

当请求包含平面的表单变量集合时,我很难获得自定义模型绑定器。

我有一个包含嵌套ViewModel的ViewModel类,例如

public class ViewModel1
{
    public long Id { get; set; }
    public ViewModel2 NestedType { get; set; }
}

public class ViewModel2
{
    public string Name { get; set; }
    public string Surname { get; set; }
}

我的问题是,如果我使用Fiddler提交表单变量为NestedType.Name的请求,那么我的自定义模型绑定器执行正常,但是,我必须处理的请求是我无法控制的,这种情况下,它是通过来自JQGrid实例的ajax请求发布的,并且是“平坦的”即

Id=5
Name=firstname
Surname=surname

Id=5
NestedType.Name=firstname
NestedType.Surname=surname

有什么方法可以让它发挥作用吗?

提前致谢。

编辑:

为了澄清一点,我的控制器动作如下所示:

public ActionResult GridEditRow(ViewModel1 viewModel)

如下所述,我宁愿在执行控制器代码之前触发自定义绑定器,而不是调用TryUpdateModel()。

4 个答案:

答案 0 :(得分:1)

试试这个:

var viewModel = new ViewModel1();
UpdateModel(viewModel.NestedType);

答案 1 :(得分:1)

不是最佳解决方案,但您可以为该类型添加另一个参数:

public ActionResult GridEditRow(ViewModel1 viewModel, ViewModel2 viewModel2)

这应绑定Name属性,即使它没有正确的前缀。

答案 2 :(得分:0)

您可以通过以下方式更改ActionResult:

public ActionResult GridEditRow(int id, string firstname, string surname)
{
  VewModel2 model2 = new VewModel2
{
Name  = firstname,
Surname = surname
}

  VewModel1 model1 = new VewModel1
{
Id = id,
NestedType  = model2 
}

return View(model1 )  

}

答案 3 :(得分:0)

我遇到过类似的问题。正如您所认为的那样,可能的决定之一是自定义模型绑定器。虽然问题很老,但我会把答案放在这里(因为为什么不呢?)。因此,自定义模型绑定器的代码如下。

public class CustomModelBinder : DefaultModelBinder {
        protected override void BindProperty(
            ControllerContext controllerContext, 
            ModelBindingContext bindingContext, 
            System.ComponentModel.PropertyDescriptor propertyDescriptor) {
                if (bindingContext.ModelType == typeof(ViewModel1)) {
                    var name = propertyDescriptor.Name;

                    // Try to implement default binding.
                    // Also one could try base.BindProperty(...).
                    var value = bindingContext.ValueProvider.GetValue(name);
                    if (value != null)
                        propertyDescriptor.SetValue(bindingContext.Model, value.ConvertTo(propertyDescriptor.PropertyType));

                    // If the default binding is not working then search for nested values.
                    else {
                        value = bindingContext.ValueProvider.GetValue("NestedType." + name);
                        if(value != null)
                            propertyDescriptor.SetValue(bindingContext.Model, value.ConvertTo(propertyDescriptor.PropertyType));
                    }
                } else
                    base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        }
    }

在Global.asax中注册活页夹:

ModelBinders.Binders.Add(typeof(ViewModel1), new CustomModelBinder());

注册的另一种可能性是在控制器的操作中使用属性。

我认为这个决定比其他决定更普遍,但也更慢(因为反思)。

帮助我的裁判:http://dotnetslackers.com/articles/aspnet/Understanding-ASP-NET-MVC-Model-Binding.aspx