简体   繁体   English

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

[英]Create MVC Custom Model Binder for model tuples

Need assistance in creating a MVC Custom Model Binder to post multiple model tuple to controller. 需要帮助创建MVC Custom Model Binder以将多个模型元组发布到控制器。 Never worked with custom model binder. 从未使用自定义模型绑定器。 Have looked at other answers to this issue but, don't seem to come close in dealing with a tuple of models or provide desired solution. 看过这个问题的其他答案但是,似乎没有接近处理模型元组或提供所需的解决方案。 Any ideas are appreciated. 任何想法都表示赞赏。 - Thanks - 谢谢

View 视图

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

Contoller 位指示

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

Why dont you try keeping the "Contact, Communications, Addresses" models inside a new model and bind it to the view. 为什么不尝试将“联系人,通信,地址”模型保留在新模型中并将其绑定到视图。

It will make handling very simple. 它将使处理变得非常简单。

For those who might be interested in the outcome of this implementation for this approach, I would like to report that it has worked out very well and exceeded all expectations in flexibility. 对于那些可能对这种方法的实施结果感兴趣的人,我想报告它已经很好地完成了并且在灵活性方面超出了所有期望。 Originally, it was used to solve a three model object tuple, it has since expanded to a four model object tuple successfully, Keep in mind that this approach does have a limit of 8 items though, there is a way of cascading the tuple to more items, not sure if it is even practical. 最初,它用于解决三个模型对象元组,它已经成功扩展到四个模型对象元组,请记住,这种方法确实有8个项目的限制,但有一种方法将元组级联到更多物品,不确定它是否实用。 Here are some code snippets that might be of use: 以下是一些可能有用的代码片段:

//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();

The ease of using a tuple as a model is greatly diminished if it is necessary to add binding lines to a custom binder for each tuple. 如果需要将绑定行添加到每个元组的自定义绑定器中,则使用元组作为模型的容易性会大大降低。

Here is a custom model binder that will work with all tuples. 这是一个自定义模型绑定器,可以与所有元组一起使用。 It calls itself recursively so that type binders that are registered will still function. 它以递归方式调用自身,以便注册的类型绑定器仍然可以运行。 Now it is only necessary to change your tuple model in one place, which is ideal. 现在只需要在一个地方更改你的元组模型,这是理想的。

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);
    }
}

Note: It is necessary to create the System.ITuple interface type from a string, because it is a protected interface. 注意:必须从字符串创建System.ITuple接口类型,因为它是受保护的接口。

I hope this saves you some time. 我希望这能节省你一些时间。 8) 8)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM