C# ASP.NET Core 2.0模型对于表单中未使用的项返回null

C# ASP.NET Core 2.0模型对于表单中未使用的项返回null,c#,asp.net,asp.net-mvc,viewmodel,C#,Asp.net,Asp.net Mvc,Viewmodel,上下文 ASP.NET核心2.0 MVC项目 问题 使用类似以下内容的视图模型: public class UpdateReturnIssueViewModel { public IssueTrackerIssue Issue { get; set; } public bool CloseIssue { get; set; } } public class IssueTrackerIssue { [Required] [DatabaseGene

上下文

ASP.NET核心2.0 MVC项目

问题

使用类似以下内容的视图模型:

public class UpdateReturnIssueViewModel
{
    public IssueTrackerIssue Issue { get; set; }

    public bool CloseIssue { get; set; }
}
public class IssueTrackerIssue
{
        [Required]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ID { get; set; }

        [StringLength(19)]
        public string OrderNumber { get; set; }

        [Range(1, 50)]
        public int Quantity { get; set; }

        [StringLength(200)]
        public string ReturnCustomerComment { get; set; }
}
    [HttpGet]
    public IActionResult UpdateReturnIssue(int ID)
    {
        // populate the view model in some way

        return View(this.updateReturnIssueViewModel);
    }
其中IssueTrackerIssue是这样的:

public class UpdateReturnIssueViewModel
{
    public IssueTrackerIssue Issue { get; set; }

    public bool CloseIssue { get; set; }
}
public class IssueTrackerIssue
{
        [Required]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ID { get; set; }

        [StringLength(19)]
        public string OrderNumber { get; set; }

        [Range(1, 50)]
        public int Quantity { get; set; }

        [StringLength(200)]
        public string ReturnCustomerComment { get; set; }
}
    [HttpGet]
    public IActionResult UpdateReturnIssue(int ID)
    {
        // populate the view model in some way

        return View(this.updateReturnIssueViewModel);
    }
我按如下方式获取视图的数据:

public class UpdateReturnIssueViewModel
{
    public IssueTrackerIssue Issue { get; set; }

    public bool CloseIssue { get; set; }
}
public class IssueTrackerIssue
{
        [Required]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ID { get; set; }

        [StringLength(19)]
        public string OrderNumber { get; set; }

        [Range(1, 50)]
        public int Quantity { get; set; }

        [StringLength(200)]
        public string ReturnCustomerComment { get; set; }
}
    [HttpGet]
    public IActionResult UpdateReturnIssue(int ID)
    {
        // populate the view model in some way

        return View(this.updateReturnIssueViewModel);
    }
在我看来,我只使用(即为标记定义输入asp)IssueTrackerIssue.OrderNumber和CloseIssue

这将被发送到控制器,因此:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult UpdateReturnIssue(UpdateReturnIssueViewModel viewModel)
{
    if (this.ModelState.IsValid)
    {
        // Some other processing
    }
}
在控制器中检查viewModel时,我看到除了在View中使用的属性之外,所有内容都为null

问题


如何使视图模型的完整内容从一个控制器传递到另一个视图并完整地返回到控制器?换句话说,如果视图未使用视图模型的某些部分,我如何才能完全往返于视图模型?

我认为没有一种方法可以传递值,而不将其包含在表单中。可以使用隐藏字段存储要传回服务器的数据。以下是razor语法,用于为表单中的现有模型字段创建隐藏字段

@Html.HiddenFor(x => x.HiddenFieldName)

这里有两个问题需要解决

1) 正如@JoshMein和其他人善意地指出的,必须在表单上使用值,否则它们将以null形式发回控制器。使用隐藏值可以克服这一问题

2) 我的视图是一个主-细节类型视图,细节集合总是返回null,即一个空集合。我现在意识到这是由于我在视图中编码细节集合迭代的方式。我在用

            @foreach (IssueTrackerIssueComment comment in Model.Issue.Comments)
            {
                <tr>
                    <td><input asp-for="@comment.ID" type="hidden" /></td>
                    <td><input asp-for="@comment.DateCreated" type="hidden" /></td>
                    <td><input asp-for="@comment.LastUpdated" type="hidden" /></td>
                    <td>
                        <input asp-for="@comment.DateCreated" class="form-control" type="date" asp-format="{0:yyyy-MM-dd}" />
                    </td>
                    <td>
                        <input asp-for="@comment.Narrative" class="form-control" />
                    </td>
                    <td>
                        <button asp-action="DeleteReturnIssueComment" asp-route-id=@comment.ID class="btn btn-primary">
                            <span class="glyphicon glyphicon-trash" />
                        </button>
                    </td>
                </tr>
            }
@foreach(模型.Issue.Comments中的IssueTrackerIssueComment注释)
{
}
ASP.NET显然无法确定这些@comment项已绑定到模型,因此无法将它们传递回控制器

因此,我将细节集合从ICollection更改为IList,并使用@for而不是@foreach,因此:

            @for (int i = 0; i < Model.Issue.Comments.Count; i++)
            {
                <tr>
                    <td><input asp-for="@Model.Issue.Comments[i].ID" type="hidden" /></td>
                    <td><input asp-for="@Model.Issue.Comments[i].DateCreated" type="hidden" /></td>
                    <td><input asp-for="@Model.Issue.Comments[i].LastUpdated" type="hidden" /></td>
                    <td>
                        <input asp-for="@Model.Issue.Comments[i].DateCreated" class="form-control" type="date" asp-format="{0:yyyy-MM-dd}" />
                    </td>
                    <td>
                        <input asp-for="@Model.Issue.Comments[i].Narrative" class="form-control" />
                    </td>
                    <td>
                        <button asp-action="DeleteReturnIssueComment" asp-route-id=@Model.Issue.Comments[i].ID class="btn btn-primary">
                            <span class="glyphicon glyphicon-trash" />
                        </button>
                    </td>
                </tr>
            }
for(int i=0;i
现在使用@Model而不是@comment来引用这些项目,所有内容都绑定得很好,我可以在控制器中看到注释。

您是否尝试使用隐藏表单输入?一个选项是使用隐藏字段。另一个选项是在返回控制器时(发布后)从数据库中获取记录。如果您不需要编辑视图中的数据,那么生成所有从控件生成的额外html,然后将其发送到浏览器,然后再次将其原封不动地发送回来,这将是毫无意义的额外开销。如果在POST方法中需要数据,只需再次从数据库中获取数据即可。视图模型的目的是在视图中表示数据,视图模型不包含数据模型(这完全违背了使用视图模型的目的)-它们包含视图中使用的数据模型的属性。这是可行的,但我只注意基本属性。我的实际IssueTrackerIssue类(即,对于这个问题不简化)包含一个ICollection,该ICollection在视图的表中使用。这也被完全返回为null。这意味着复杂的结构不能传递给控制器。当然不可能是这样,或者主-细节视图变成了一个真正的少数视图。@ifinlay在这种情况下,我通常按照莱昂纳多上面的评论做。我再次从数据库中提取记录,并且只为允许用户编辑的字段设置值。好的,这几乎为我提供了一个解决方案。但我仍在为主细节问题而挣扎。ICollection以@foreach显示在表单上。我已经对此进行了修改,以便将未显示的注释属性隐藏起来。返回控制器时,ICollection继续为null。该值为null,因为集合中没有项。因此,我假设问题变成了“如何将主细节表单的细节元素返回给控制器”@ifinlay如果在返回到服务器时从数据库中提取,则不需要为集合分配新值。只需让它保留它的值,并且只为可以编辑的字段分配新的值。一个更简单的澄清示例。假设Person类具有ID、ForeName、LastName和ICollection。地址具有ID、第1行和第2行。“我的视图”具有隐藏ID的ForeName和LastName的输入标记。它还有一个@foreach循环,其中隐藏了Line1、Line2和Address.ID的输入标记。假设对于特定的人,ICollection有3个地址。当我把它发回控制器时,我得到ID、ForeName、LastName的值。但ICollection为空。它中没有地址,因此无法访问任何地址更改。所以我不能让大师级的细节工作。谢谢!你也许可以让我免于数小时的调试