在 MVC 应用程序中,将复杂模型中的列表绑定问题

5

我是一个新手使用.NET MVC Web应用程序,我正在使用Web应用程序的版本4。 我正在开发一个页面来管理简单成员身份提供程序的角色,并希望它是动态的。为了清楚我的意思,它将类似于这样:

UsersInRoles

就像那样非常简单。为此,我有一个复杂的ViewModel,如下所示:

public class UserInRolesModel
{
    public List<string> AllRoleNames { get; set; }
    public List<UserInRoles> UsersInRoles { get; set; }

    public UserInRolesModel()
    {
        AllRoleNames = new List<string>();
        UsersInRoles = new List<UserInRoles>();
    }

    public UserInRolesModel(List<string> allRoleNames, List<UserInRoles> usersInRoles)
    {
        AllRoleNames = allRoleNames;
        UsersInRoles = usersInRoles;
    }
}

public class UserInRoles
{
    public UserInRoles(string user, List<string> userRoles, IEnumerable<string> allRoleNames)
    {
        User = user;
        Roles = SetRoles(userRoles, allRoleNames);
    }

    private List<bool> SetRoles(List<string> userRoles, IEnumerable<string> allRoleNames)
    {
        return allRoleNames.Select(userRoles.Contains).ToList();
    }

    public string User { get; set; }
    public List<bool> Roles { get; set; }

    public void UpdateRoles(List<string> allRoleNames)
    {
        var roleProvider = (SimpleRoleProvider)System.Web.Security.Roles.Provider;

        var rolesAdded = new List<string>();
        for (int i = 0; i < Roles.Count; i++)
        {
            if (Roles[i])
            {
                rolesAdded.Add(allRoleNames[i]);
            }
        }
        roleProvider.AddUsersToRoles(new[] { User }, rolesAdded.ToArray());
    }
}

在我的视图中,我有类似下面这样的内容来显示角色名称:
<th><strong>@Html.DisplayFor(m => m.AllRoleNames, "AllRoleNames")</strong></th>

我有一个DisplayTemplates文件夹,其中包含AllRoleNames.cshtml文件,以下是文件内容(目前不关注页面布局):

@model List<string>

@if (Model != null)
{ 
    for (int i = 0; i < Model.Count; i++)
    {
        @Html.HiddenFor(m => m[i])
        @Html.DisplayFor(m => m[i])
    } 
}

到目前为止,一切顺利。它正确显示名称。 但是,当我尝试按下保存按钮时,MVC应该从HTML中获取适当的名称以绑定到我的HTTP Post控制器操作中的对象模型:

[HttpPost]
public ActionResult AdminUsers(UserInRolesModel model)
{
    //code to save roles goes here
    return View(model);
}

但我得到了一个空的模型。(现在我只关心角色名称列表,因为一旦弄清楚它发生了什么,我也可以弄清楚我的UserInRoles对象列表发生了什么)
我可以找出MVC为什么无法正确绑定。这是因为生成的HTML类似于:
<input id="AllRoleNames__0_" name="AllRoleNames.[0]" type="hidden" value="Admin">
Admin
<input id="AllRoleNames__1_" name="AllRoleNames.[1]" type="hidden" value="Extrator">
Extrator

当应该是 "AllRoleNames[0]" 时,name属性被生成为 "AllRoleNames.[0]",其中有一个多余的点。我在这个 问题 中找到了一个答案提出的 hack。它可能有效,但当我测试时,我发现我的HtmlFieldPrefix已经没有点了,所以当然不起作用。
我的问题是,为什么MVC生成这些带有点的名称,是否有一种方法告诉它正确地生成它们?
2个回答

3

我发现将List作为模型传递是非常痛苦的。如果你传递一个包含List的类,事情会变得更容易。然后你可以使用for循环,这样它们就会按照你的预期开始运行了,例如:

for(int i = 0; i < model.MyList.Count; i++)
{
    @Html.HiddenFor(model => model.MyList[i])
    @Html.DisplayFor(model  => model.MyList[i])
} 

应正确返回您的属性名称。

实际上,PITaylor,我在模型中使用列表没有得到好的结果。所以,通过你的回答,我发现我可以在视图中处理所有内容,而不需要DisplayTemplate。因此,我只是像你建议的那样,在for循环中使用了类似@Html.HiddenFor(m => m.AllRoleNames[i])的东西。此外,我还使用相同的逻辑来显示用户权限的复选框。感谢您的回答。 - strongwind
没问题...我也曾经自己吃过这个亏,不得不学习它。 - PlTaylor

0
这是因为您使用了一个 for 循环而不是 foreach,请尝试在 AllRoleNames 模板中使用以下代码:
foreach (var role in Model)
{
    @Html.HiddenFor(m => role)
    @Html.DisplayFor(m => role)
} 

嗨Daniele,谢谢你的回复。事实上,当我尝试使用foreach语句时,我摆脱了那个点。但它也摆脱了我的集合,因为生成的代码对于所有项目都是“AllRoleNames.role”。你看到我在列表上失去了[0],[1]吗?所以,当我提交回来时,它也不会绑定到模型。感谢您的答案,但它没有起作用... - strongwind

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接