【问题标题】:Nested binding in ASP.NET MVC RazorASP.NET MVC Razor 中的嵌套绑定
【发布时间】:2022-01-06 15:29:23
【问题描述】:

说明

嵌套对象需要绑定到下拉列表,嵌套对象已经有一个预选值。可能的值是枚举类型。带有一些其他数据的下拉列表将被发送回控制器。

代码 - 类型和类:

[Serializable]
public enum DummyEnum
{
   DummyZero = 0,
   DummyOne = 1
}

public class Dummy
{
   public Guid Id { get; set; }
   public Dictionary<Guid, DummyEnum> DummyEnum { get; set; }
}

public class DummyViewModel
{
    public Dictionary<Guid, List<Dummy>> Dummies { get; set; }
}

public class DummyController
{
    private void Init(DummyViewModel model)
    {
       model.EnumList = Enum.GetValues(typeof(DummyEnum))
                    .Cast<DummyEnum>()
                    .Select(e => new SelectListItem
                    {
                        Value = (e).ToString(),
                        Text = e.ToString()
                    });
    }
}

HTML

<td>
    @Html.DropDownListFor(
         m => m.Dummies[dummiesKey][dummyIndex]
                 .Enum[Id],
         new SelectList(Model.EnumList, "Value", "Text", e.ToString()))
</td>

<select 
    data-val="true" 
    data-val-required="The Enum field is required." 
    id="Dummies_guid__0__Enum_guid_" 
    name="Dummies[guid][0].Enum[guid]" 
    style="display: none;"
>
    <option value="DummyOne">DummyOne</option>
    <option selected="selected" value="DummyZero ">DummyZero</option>
</select>

问题

问题在于模型似乎无法将有效负载映射回对象或错过对绑定对象的引用。所有内容都正确填写了 guid、索引和枚举值。

有效载荷:

Dummies[guid][0].Enum[guid]: DummyZero     
Dummies[guid][0].Enum[guid]: DummyZero 

尝试

我尝试了以下想法,但对我来说并不成功。

我错过了什么?

【问题讨论】:

    标签: c# asp.net-mvc razor data-binding


    【解决方案1】:

    问题中所述的问题与 mvc 将 Dictionary 转换为 List>绑定或使用 JSON 有关。

    所有需要做的就是像 mvc 那样分解对象并提供必要的数据。如dicitionary binding 中所述。

    对象的类型为Dictionary&lt;Guid, List&lt;Dummy&gt;&gt;。所以对象实际上变成了List&lt;KeyValuePair&lt;Guid, List&lt;List&lt;KeyValuePair&lt;Guid, enum&gt;&gt;&gt;&gt;&gt;

    现在分解一下

    MVC 需要正在使用的第一个对象的索引。为了得到这个索引,我们需要自己将字典转换为一个列表。更具体的字典的值或键。

    var dummies= Model.Dummies[key];
    var dummiesIndex = Model.Dummies.Values.ToList().IndexOf(dummies);
    

    需要在帖子旁边提供索引。这可以通过将其添加到下拉列表上方作为字典中键旁边的隐藏字段来完成。

    @Html.Hidden("dummies.Index", dummiesIndex)
    @Html.Hidden("dummies[" + dummiesIndex + "].Key", key)
    

    接下来是对象列表。再次需要为绑定提供索引。

     @Html.Hidden("dummies[" + dummiesIndex + "].Value.Index", dummyIndex)
    

    最后一步是另一个字典,这就像第一个字典

    @Html.Hidden("dummies[" + dummiesIndex + "].DummyEnum.Index", dummyEnumIndex)
    @Html.Hidden("dummies[" + dummiesIndex + "].DummyEnum.Key", yourKey)
    

    对于您想要实际发布的值,您需要遵循上述完整路径。

    @Html.DefaultCombo("dummies[" + dummiesIndex + "].DummyEnum[" + dummyEnumIndex+ "]", "Value", "Text", Model.EnumList, enum)
    

    现在 MVC 可以重新映射您的对象。

    【讨论】:

      【解决方案2】:

      前端响应将采用您在此处设置的格式。然后 ASP 中间件会将所有这些字符串解析回后端的对象。

      所以这里的关键时刻是:

      • 控制器操作参数类型 - 它可以是您的任何类型,但应该与您的前端相关;
      • 前端的 select 元素 name 属性值 - 它应该包含完整的现有路径。

      我从您的代码示例中得到以下内容。

      1. 您有DummyViewModel 视图模型类。它有属性Dummies
      2. 您有Dummy 类,它嵌套在DummyViewModel 中,为Dummies。二级词典。
      3. 您有DummyEnum 枚举类,它在DummyEnum 值处使用。相同的名称,不同的相邻级别。
      4. SelectList 值正常。它们直接来自枚举。
      5. 根据结构,要设置第一个枚举值,您需要通过设置 KEY 和 VALUE 来导航其级别。然后再做另一个级别。对我来说,这个结构中的第一个枚举值应该是这样的:
      Dummies[dummiesKeyGuid][dummyIndexId].DummyEnum[dummyEnumKeyGuid];
      

      您在每个步骤中都有以下类型:

      • Dummies[dummiesKeyGuid]&lt;List&lt;Dummy&gt;&gt;;
      • Dummies[dummiesKeyGuid][dummyIndexId]&lt;Dummy&gt;;
      • Dummies[dummiesKeyGuid][dummyIndexId].DummyEnum[dummyEnumKeyGuid]&lt;DummyEnum&gt;

      所以应该更新@Html.DropDownListFor(...) 以将路径设置为name

      还有:

      1. 您的操作应将Dummies 类型作为参数。
      ActionResult SomeFromProcessingAction(DummyViewModel Dummies)
      
      1. 您应该处理传递的字符串化参数映射到Dictionary 类型。它可以在 ASP(前端)之外使用,但存在问题。请检查这篇文章及其主题:https://stackoverflow.com/a/29820891/6344916。有时,在那里不使用Dictionary 会更容易。只是其他类,如 List 或 Array。

      从您的 HTML 示例中,我没有让 m.Dummies 类型在其结构中包含 Enum 字段。 dummiesKey 不能有 "guid" 值。 GUID 是另一种类型,可以很容易地制作为ToString(),但不能以其他方式制作。

      恕我直言。名称中的 Dummys 太多。它混淆并破坏了它的理解。

      另外,它的嵌套结构非常麻烦。您可以使用较小的用户表单来设置值并在后端获取较小的对象或事件值,而不是使用巨大的对象参数。

      List 类没有映射要求,只需对字典进行非规范化,映射它们会更容易。他们在前端的导航也是如此。如果需要,您可以创建列表ToDictionary()。 :)=)

      例如,Dummy 可以写成 List&lt;T&gt;

      public class SomeElement
      {
        public Guid Id { get; set; }
        public DummyEnum Enum { get; set; }
      }
      
      public class Dummy //kind of aggregation
      {
        public Guid Id { get; set; }
        public List <SomeElement> DummyEnum { get; set; }
      }
      

      DummyViewModel 以此类推。或者去掉它,直接使用一些List。

      希望,这会有所帮助。

      【讨论】:

        【解决方案3】:

        我认为您的问题与嵌套属性或输入命名无关,您的实现似乎很好。

        您遇到的问题与Dictionary&lt;Guid, ...&gt; 默认模型绑定器行为有关。默认活页夹似乎无法正确处理它。 (即以Guid 为键的字典)

        我已经复制了你的问题,然后切换到Dictionary&lt;string, ...&gt;,这次一切正常。

        您可以克服这个问题的唯一方法应该是为Dictionary&lt;Guid, object&gt; 实现您自己的模型绑定器。

        我试图了解根本问题,它似乎位于 here(从字符串到 Guid 的无效显式转换),如 here 所述(稍后发现:-)...)

        【讨论】:

          猜你喜欢
          • 2021-09-24
          • 2016-09-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-07-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多