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

问题描述:

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

查看

@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. 
} 

对于那些可能对此方法的实施结果感兴趣的人,我想报告它已经很好地完成了,并且超出了所有的灵活性期望。最初,它被用来解决三个模型对象元组,它已经成功扩展到四个模型对象元组,但请记住,这种方法的限制有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(); 

你为什么不尝试保持一个新的模式里面的“联系人,通讯,地址”模型,并将其绑定到视图。

它会使处理非常简单。

的方便使用一个元组,就好像它是需要绑定行添加到每个元组定制绑定模型会大大减少的。

这是一个自定义模型联编程序,它将与所有元组一起工作。它会递归调用它自己,以便注册的类型绑定器仍然可以运行。现在只需要在一个地方改变你的元组模型,这是理想的。

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)