Why does Razor view add “CS$<>8__locals1” prefix to input names when accessing indexer of model assigned to local variable?

半腔热情 提交于 2019-12-24 03:29:50

问题


I'm building a simple ASP.NET MVC 5.2.3.0 view that displays a user name and a checkbox list of roles. You can check or uncheck the checkboxes to control which roles the user is in. Here is my ViewModel:

public class EditUserVM
{
    public string Id { get; set; }
    public string UserName { get; set; }
    public List<UserRoleVM> Roles { get; set; }
}

public class UserRoleVM
{
    public string RoleId { get; set; }
    public string RoleName { get; set; }
    public bool IsMember { get; set; }
}

And it's displayed like this:

@model  VMContainer<EditUserVM>

@* omitted for exmaple *@

var userVM = Model.ViewModel;
<div class="panel panel-primary">
    <div class="panel-heading"><h4 style="display:inline">User: @userVM.UserName</h4></div>

    <div class="panel-body">
        @Html.ValidationSummary(false, "", new { @class = "text-danger" })

        <h4>Users Roles</h4>

        @using (Html.BeginForm())
        {
            @Html.AntiForgeryToken()

            <div class="form-horizontal">
                @Html.HiddenFor(m => userVM.Id)
                @Html.HiddenFor(m => userVM.UserName)

                <table class="table table-bordered table-striped">
                    <thead><tr><th></th><th>Role</th></tr></thead>
                    <tbody>
                        @for (int x = 0; x<userVM.Roles.Count; x++){
                            <tr>
                                <td>
                                    @Html.HiddenFor(m => userVM.Roles[x].RoleId)
                                    @Html.CheckBoxFor(m => userVM.Roles[x].IsMember)
                                </td>
                                <td>@Html.DisplayFor(m => userVM.Roles[x].RoleName)</td>
                            </tr>
                        }
                    </tbody>
                </table>

                <div>
                    <input type="submit" value="Save" class="btn btn-success" />
                    @Html.ActionLink("Cancel", "Users", null, new { @class = "btn btn-default" })
                </div>
            </div>
        }

Notice the model type is VMContainer. This is a wrapper used by my views so that in case there is an error generating the inner T ViewModel, it can display an error instead of the normal view content. To make it easier to access the EditUserVM and because that is all I need to submit, not the VMContainer wrapper, I assign it to a local variable var userVM = Model.ViewModel;. I've used this pattern a lot in previous projects. The problem is when I inspect the page in developer tools, all of my inputs are named wrong. They all get a prefix for what looks like a generated class. For example, @Html.HiddenFor(m => userVM.Id) renders:

Through trial and error, I narrowed this down to not happening if I remove the for loop. That is with the for loop commented out, the remaining inputs are named correctly. Through further trial and error I discovered that what really triggers it is accessing the Roles indexer using a variable. E.G. If I remove the loop and just do this, it produces the wrong name for all of the inputs:

                @Html.HiddenFor(m => userVM.Id)
                @Html.HiddenFor(m => userVM.UserName)
                @{ int x = 0; }
                @Html.HiddenFor(m => userVM.Roles[x].RoleId);

It does not generate the wrong names if I use the constant [0] in place of [x] or m.ViewModel.Roles[x] instead of userVM.Roles[x]. So to try to spell it out completely, it seems to occur when accessing the indexer of a local variable's descendant using a variable for the index parameter.

I found this or something similar acknowledged for MVC 6 (at the time) but I don't understand the problem. I'm a little surprised this still exists if it is in fact a bug. Although it's hard to describe, it doesn't seem like it would be a totally uncommon scenario. Can someone explain what is going on and hopefully offer a fix? I prefer to only post an EditUserVM to my action when the form submits.


回答1:


@for (int x = 0; x<userVM.Roles.Count; x++){

A workaround could be declaring the variable x in the top of your page.

Source: https://github.com/aspnet/Mvc/issues/2890



来源:https://stackoverflow.com/questions/46495736/why-does-razor-view-add-cs8-locals1-prefix-to-input-names-when-accessing-i

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!