为模型元组创建MVC自定义模型绑定器

时间:2013-03-22 17:33:28

标签: asp.net-mvc tuples

需要帮助创建MVC Custom Model Binder以将多个模型元组发布到控制器。从未使用自定义模型绑定器。看过这个问题的其他答案但是,似乎没有接近处理模型元组或提供所需的解决方案。任何想法都表示赞赏。 - 谢谢

查看

@model Tuple<Contact, Communications, Addresses>
@using (Html.BeginForm()) {
  <div id="contact">
    <div class="editor-label">
         @Html.LabelFor(m => m.Item1.FirstName)
    </div>
    <div class="editor-field">
        @Html.TextBoxFor(m => m.Item1.FirstName)
    </div>
    <div class="editor-label">
        @Html.LabelFor(m => m.Item1.LastName)
    </div>
    <div class="editor-field">
        @Html.TextBoxFor(m => m.Item1.LastName)
    </div>
    <div>
        <input type="submit" value="Create" />
    </div>
  </div>
  <div id="communication">
    <div class="editor-label">
        @Html.LabelFor(m => m.Item2.TelephoneValue)
    </div>
    <div class="editor-field">
        @Html.TextBoxFor(m => m.Item2.TelephoneValue)
    </div>
  </div> 
  <div id="address">
    <div class="editor-label">
        @Html.LabelFor(m => m.Item3.Address1)
    </div>
    <div class="editor-field">
        @Html.TextBoxFor(m => m.Item3.Address1
    </div>
    <div class="editor-label">
        @Html.LabelFor(m => m.Item3.City)
    </div>
    <div class="editor-field"> 
        @Html.TextBoxFor(m => m.Item3.City)
    </div>
    <div class="editor-label">
        @Html.LabelFor(m => m.Item3.StateProvince)
    </div>
    <div class="editor-field">
        @Html.TextBoxFor(m => m.Item3.StateProvince)
    </div>
    <div class="editor-label">
        @Html.LabelFor(m => m.Item3.PostalCode) 
    </div>
    <div class="editor-field"> 
        @Html.TextBoxFor(m => m.Item3.PostalCode, new { id = "zip", style = "width:90px;" })
    </div>
  </div> 
}

位指示

[HttpPost]
public ActionResult CreateContact(Tuple<Contact, Communications, Addresses> tuple) {
      //…. Do tuple processing to transfer values to add values to App Service here.
}

3 个答案:

答案 0 :(得分:1)

为什么不尝试保持&#34;联系人,通讯,地址&#34;新模型中的模型并将其绑定到视图。

这将使处理变得非常简单。

答案 1 :(得分:0)

对于那些可能对此方法的实施结果感兴趣的人,我想报告它已经很好地完成了并且超出了所有期望的灵活性。最初,它用于解决三个模型对象元组,它已经成功扩展到四个模型对象元组,请记住,这种方法确实有8个项目的限制,但有一种方法将元组级联到更多物品,不确定它是否实用。以下是一些可能有用的代码段:

//Custom Model Binder
public class TupleModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext,
              ModelBindingContext bindingContext, Type modelType)
   {
      if (modelType == typeof(Tuple<ContactModel, CommunicationModel, AddressModel>))
            return new Tuple<ContactModel, CommunicationModel, AddressModel>(new ContactModel(), new CommunicationModel(), new AddressModel());
      if (modelType == typeof(Tuple<ContactModel, CommunicationModel, AddressModel, CustomerModel>))
            return new Tuple<ContactModel, CommunicationModel, AddressModel, CustomerModel>(new ContactModel(), new CommunicationModel(), new AddressModel(), new CustomerModel());

         return base.CreateModel(controllerContext, bindingContext, modelType);
      }
 }

 // In Global.asax Application_Start()
     ModelBinders.Binders.DefaultBinder = new TupleModelBinder();

答案 2 :(得分:0)

如果需要将绑定行添加到每个元组的自定义绑定器中,那么将元组用作模型的难易程度会大大降低。

这是一个可以与所有元组一起使用的自定义模型绑定器。它以递归方式调用自身,以便注册的类型绑定器仍然可以运行。现在只需要在一个地方改变你的元组模型,这是理想的。

public class CustomModelBinder : DefaultModelBinder
{
    private static Type _tupleInterfaceType = Type.GetType("System.ITuple", true, false);

    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        if (modelType.FindInterfaces((a, b) => a == (Type)b, _tupleInterfaceType).Length == 1)
        {
            object[] args = new object[modelType.GenericTypeArguments.Length];
            for (int i = 0; i < args.Length; i++)
            {
                if (modelType.GenericTypeArguments[i].IsValueType) args[i] = Activator.CreateInstance(modelType.GenericTypeArguments[i]);
                else args[i] = CreateModel(controllerContext, bindingContext, modelType.GenericTypeArguments[i]);
            }
            return Activator.CreateInstance(modelType, args);
        }
        return base.CreateModel(controllerContext, bindingContext, modelType);
    }
}

注意:必须从字符串创建System.ITuple接口类型,因为它是受保护的接口。

我希望这能节省你一些时间。 8)