Asp.net mvc 模型未在POST上正确提交/绑定

Asp.net mvc 模型未在POST上正确提交/绑定,asp.net-mvc,Asp.net Mvc,场景: 我有一个表,其中包含从ViewModel填充的行。每行都有复选框,允许用户选中一行或多行,然后从下拉菜单中的操作中进行选择,以编辑选定行的属性 到目前为止,一切正常,我可以让ViewModel正确通过,然后在后期操作方法中使用它及其所有属性。我可以根据用户选择的选项进行更改 但是,由于下拉列表中的某些选项会做出相当大且不可逆转的更改,因此我使用GET调用一个新视图,并使用选定的行填充一个新表,并要求用户确认他们想要进行更改。到目前为止,一切都还不错。新视图按预期仅填充上一个视图中选定的行

场景: 我有一个表,其中包含从ViewModel填充的行。每行都有复选框,允许用户选中一行或多行,然后从下拉菜单中的操作中进行选择,以编辑选定行的属性

到目前为止,一切正常,我可以让ViewModel正确通过,然后在后期操作方法中使用它及其所有属性。我可以根据用户选择的选项进行更改

但是,由于下拉列表中的某些选项会做出相当大且不可逆转的更改,因此我使用GET调用一个新视图,并使用选定的行填充一个新表,并要求用户确认他们想要进行更改。到目前为止,一切都还不错。新视图按预期仅填充上一个视图中选定的行

问题: 在用户确认其意图后,将使用POST调用操作方法。正确填充当前视图的ViewModel正在正确地进入控制器。我得到了ViewModel,但与填充视图的属性不同

视图模型

public class ProjectIndexViewModel
{        
    public List<ProjectDetailsViewModel> Projects { get; set; }
    public string FlagFormEditProjects { get; set; }
    public string FlagFormNewProjectStatus { get; set; }
}
公共类项目索引模型
{        
公共列表项目{get;set;}
公共字符串FlagFormEditProjects{get;set;}
公共字符串FlagFormNewProjectStatus{get;set;}
}
列表项目
用于填充表中的行,而项目在控制器中的后期操作方法中没有正确绑定

选中复选框的初始视图。请注意选择下拉选项时调用的其中一个javascript函数的示例,该函数用于提交表单

@using (Html.BeginForm("EditProjectsTable", "Project", FormMethod.Get, new { name = "formEditProjects", id = "formEditProjects" }))
{         
    @Html.HiddenFor(item => item.FlagFormEditProjects)
    @Html.HiddenFor(item => item.FlagFormNewProjectStatus) 
    ....
    <table>
        <thead>
            ....
        </thead>
        <tbody>
            @for (int i = 0; i < Model.Projects.Count; i++)
            {
                <tr>
                    <td>@Html.DisplayFor(x => x.Projects[i].ProjectNumber)</td>
                    <td>@Html.DisplayFor(x => x.Projects[i].ProjectWorkType)</td>
                    .... // more display properties
                    <td>
                        @Html.CheckBoxFor(x => x.Projects[i].Selected, new { @class = "big-checkbox" })
                        @Html.HiddenFor(x => x.Projects[i].ProjectModelId)
                    </td>
                </tr>
            }                         
        </tbody>
    </table>
}

function submitFormRemoveProjects() {
    $("#FlagFormEditProjects").attr({
        "value": "RemoveProjects"
    });
    $('#formEditProjects').submit();
}
@使用(Html.BeginForm(“EditProjectsTable”,“Project”,FormMethod.Get,new{name=“formEditProjects”,id=“formEditProjects”}))
{         
@Html.HiddenFor(item=>item.FlagFormEditProjects)
@Html.HiddenFor(item=>item.FlagFormNewProjectStatus)
....
....
@对于(int i=0;ix.Projects[i].ProjectNumber)
@DisplayFor(x=>x.Projects[i].ProjectWorkType)
..//更多显示属性
@Html.CheckBoxFor(x=>x.Projects[i]。选中,新建{@class=“big checkbox”})
@Html.HiddenFor(x=>x.Projects[i].ProjectModelId)
}                         
}
函数submitFormRemoveProjects(){
$(“#FlagFormEditProjects”).attr({
“值”:“移除项目”
});
$('#formEditProjects')。提交();
}
返回“确认”视图的操作方法(工作正常)

[HttpGet]
[授权(角色=“系统管理员、帐户管理员、用户”)]
公共异步任务EditProjectsTable([Bind(Include=“Projects,FlagFormEditProjects,FlagformNewProjectStatus”)]ProjectIndexViewModel ProjectIndexViewModel)
{
//将ProjectIndexViewModel的项目集合重新填充到
//仅包括已选定的项目
返回视图(projectIndexViewModel);
}
从上面的Action方法返回的视图(工作正常)请注意,调用的Action方法是通过Html.BeginForm调用中的actionName变量动态设置的

@using (Html.BeginForm(actionName, "Project", FormMethod.Post))
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(model => model.FlagFormNewProjectStatus)
    ....
    <table>
        <thead>
            ....
        </thead>
        <tbody>
            @for (int i = 0; i < Model.Projects.Count; i++)
            {
                <tr>
                    <td>@Html.HiddenFor(x => x.Projects[i].ProjectModelId)</td>
                    <td>@Html.DisplayFor(x => x.Projects[i].ProjectNumber)</td>
                    <td>@Html.DisplayFor(x => x.Projects[i].ProjectWorkType)</td>
                    .... // more display properties
                </tr>
             }
         </tbody>
     </table>
     <input type="submit" value="Delete Permanently" />
}
@使用(Html.BeginForm(actionName,“Project”,FormMethod.Post))
{
@Html.AntiForgeryToken()
@Html.HiddenFor(model=>model.FlagFormNewProjectStatus)
....
....
@对于(int i=0;ix.Projects[i].ProjectModelId)
@DisplayFor(x=>x.Projects[i].ProjectNumber)
@DisplayFor(x=>x.Projects[i].ProjectWorkType)
..//更多显示属性
}
}
从该视图调用的控制器操作方法之一的示例,该方法与视图中的项目不同。不知何故,它的项目数与最初选择的项目数相同,但如果只选择了一个,它的项目模型Id最低。我不知道如何描述正在发生的事情。但总而言之,正确的ViewModel并没有进入如下所示的POST方法示例中

[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Sys Admin, Account Admin")]
public async Task<ActionResult> DeleteConfirmedMultipleProjects([Bind(Include = "Projects")] ProjectIndexViewModel projectIndexViewModel)
{
    if (ModelState.IsValid)
    {
        // Remove Projects from db and save changes
        return RedirectToAction("../Project/Index");
    }
    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
[HttpPost]
[ValidateAntiForgeryToken]
[授权(Roles=“Sys Admin,Account Admin”)]
公共异步任务DeleteConfirmedMultipleProject([Bind(Include=“Projects”)]ProjectIndexViewModel ProjectIndexViewModel)
{
if(ModelState.IsValid)
{
//从数据库中删除项目并保存更改
返回重定向到操作(“../Project/Index”);
}
返回新的HttpStatusCodeResult(HttpStatusCode.BadRequest);
}

请帮忙

我认为你的问题来自这一部分:

@Html.CheckBoxFor(x => x.Projects[i].Selected, new { @class = "big-checkbox" })
@Html.HiddenFor(x => x.Projects[i].ProjectModelId)
我以前遇到过这个错误,我所做的是向
ProjectDetailsViewModel
添加一个布尔属性,比如
IsSelected
。 那么你应该:

@Html.CheckBoxFor(x => x.Projects[i].IsSelected, new { @class = "big-checkbox" })
然后在方法上,您应该添加:

foreach (var project in ProjectIndexViewModel.Projects  )
        {
            if (project.IsSelected==true)
                "put your logic here"
        }

问题是,当您从第一个视图提交到
EditProjectsTable()
方法时,所有表单控件的值都会添加到
ModelState

重新填充
ProjectDetailsViewModel
集合不会更新
ModelState
,返回视图时,
DisplayFor()
方法将显示正确的值,因为
DisplayFor()
使用模型的值,但是

@Html.HiddenFor(x => x.Projects[i].ProjectModelId)
将使用
Mod中的值
@Html.HiddenFor(x => x.Projects[i].ProjectModelId)
[HttpGet]
[Authorize(Roles = "Sys Admin, Account Admin, User")]
public async Task<ActionResult> EditProjectsTable(ProjectIndexViewModel projectIndexViewModel)
{
    // Repopulate the Projects collection of ProjectIndexViewModel to
    // include only those that have been selected
    ModelState.Clear(); // add this
    return View(projectIndexViewModel);
}