在ASP.NET MVC中从视图传递模型到控制器

5
我正在开发我的第一个ASP.NET MVC应用程序,遇到了一个问题,即使在阅读整个互联网后也无法解决。
因此,我有几个视图(它们是报告),使用视图模型创建,该视图模型基于用户选择的条件进行填充。我正在尝试构建一种方法,该方法接受模型并以Excel格式导出它(使用EPPlus),但需要从这些视图之一发送模型。这是某种功能/可用性要求,而不是技术要求。用户可以运行报告,并在查看报告后单击按钮/链接,将创建他们正在查看的报告的Excel版本。我希望传递基于显示的视图的模型,因为已经完成了基于用户报告选择标准构建此特定视图模型的工作。
这一切都很好,我可以成功地从显示报告的视图传递模型到构建报告的方法中。我传递的所有数据似乎都在那里,除了其中的一组模型(IEnumerable)。 <--这就是我卡住的地方。在断点处,IEnumerable集合中没有任何项,但是在最初将视图模型创建并传递到视图时,情况绝对不是这样。
我卡住了 - 请帮忙。
视图模型:
public class ReportViewModel
{

    public int ProjectId { get; set; }

    [Display(Name = "Project Name")]
    public string ProjectName { get; set; }

    [Display(Name = "Project #")]
    public string ProjectNumber { get; set; }

    public IEnumerable<SystemModel> SelectedSystems { get; set; }//has items when created and passed into the View intially, but not when the Model is passed from the View to the method/controller. 

    [Display(Name = "All Systems")]
    public bool AllSystems { get; set; }

    [Display(Name = "In Progress Systems")]
    public bool InProgressSystems { get; set; }

    [Display(Name = "Completed Systems")]
    public bool CompletedSystems { get; set; }

    [Display(Name = "Unchecked Systems")]
    public bool UncheckedSystems { get; set; }

    [Display(Name = "Systems with Problems - Ours")]
    public bool JciIssue { get; set; }

    [Display(Name = "Systems with Problems - Other's")]
    public bool OtherIssue { get; set; }

    [Display(Name = "Include Points with Problems")]
    public bool IncludePoints { get; set; }

}

查看:

    @model ProjectOps_5.ViewModels.ReportViewModel


@{
    ViewBag.Title = "Software Cx Status Report";
}

<h2>Software Cx Status Report</h2>

<div>
    <div>
        <hr />

 @Html.ActionLink("Export to Excel", "ExportExcel", Model)//call to method

//the report

方法:

    public void ExportExcel(ReportViewModel model)
        {
           //make Excel file
        }
3个回答

8

您无法将包含复杂对象或集合的属性的模型传递给GET方法。内部 ActionLink() 方法调用每个属性的 .ToString() 方法,因此基本上 DefaultModelBinder 将尝试设置属性如下:

model.SelectedSystems = "System.Collections.Generic.IEnumerable<SystemModel>";

当然,这种方法会失败,因为属性是null

幸运的是,它不起作用,否则您将生成一个非常丑陋的查询字符串,并且很容易超出查询字符串的限制并引发异常。

相反,传递ProjectId属性(我假设它唯一地标识了对象),并在ExportExcel()方法中再次获取模型。

@Html.ActionLink("Export to Excel", "ExportExcel", new { ID = Model.ProjectId })

并且在控制器中

public void ExportExcel(int ID)
{
  // Get your ReportViewModel based on the ID and do stuff
}

谢谢你提供的信息,这解释了很多问题。然而,Model.ProjectId无法获取我需要的SystemModels,因为为了创建IEnumerable<SystemModel> SelectedSystems,我已经通过一堆if then else、循环等操作了。这就是我试图重用这个列表而不必再次运行该代码的主要原因。也许再次运行它并不是那么大的问题,但我必须考虑如何传递原始报告选择的所有选择/过滤条件。 - amartin
1
无法确定您需要做什么,因为细节不足,但是您可以在ActionLink()中传递其他路由值来定义您的过滤器/排序等。 - user3559349
除了 ProjectId 之外,您是否可以将 SystemModels 的某些属性传递给该方法,以便用于过滤报告所需的结果?您可以考虑在生成视图之前将集合存储在 Session 中,然后在 ExportExcel() 方法中从会话中读取集合。 - user3559349
我还不太了解 Session,但听起来值得研究一下。我需要关机休息了。谢谢。 - amartin
1
我所能做的就是按照问题直接回答 :)。建议你先进行一些研究,如果有问题再提出一个新的问题。 - user3559349
显示剩余2条评论

1
将整个视图模型传递给另一个方法可能不是最好的选择,因为您不知道模型的大小(SelectedSystems中元素的数量)。如果它太大,您可能会超过最大请求长度或使用户等待太长时间,直到请求完成。
但是,如果您绝对确定这就是您需要的 - 可以使用表单完成:
    @using (Html.BeginForm("ExportExcel", null, FormMethod.Post))
    {
        @Html.Hidden("ProjectId", Model.ProjectId)
        @Html.Hidden("ProjectName", Model.ProjectName)
        ...
        @for(int i = 0; i < Model.SelectedSystems.Count(); i++)
        {
            var systemModel = Model.SelectedSystems.ElementAt(i);
            @Html.Hidden("SelectedSystems[" + i + "].Property1", systemModel.Property1)
            @Html.Hidden("SelectedSystems[" + i + "].Property2", systemModel.Property2)
        }
        <input type="submit" value="Export to Excel" />
    }

然而,更好的方法是使用你想要导出的所有对象的一些标识符(不确定在你的情况下可能是什么),并将这些 ID 作为 ActionLink 路由值传递。

-1
你可以尝试以下逻辑,这个逻辑需要在发送请求之前完成(或者取决于您的页面,但应该在发送请求之前可用)。
var html = "";
for (index = 0; index < SelectedSystems.length; index++) {
    html += '<input type="hidden" name="SelectedSystems[' + index + '].PropertyName" id="SelectedSystems _' + index + '_PropertyName" value="YourValue"/>';
}
$("#divSelectedSystems").html(html); //Here divSelectedSystems is one dummy div with that id

我不确定你的意思。你能详细说明/澄清一下吗? - amartin
我的意思是,如果它是集合属性,那么您必须为每个记录和每个属性添加隐藏字段,并带有索引。因此,我希望您想要传递属性IEnumerable<SystemModel> SelectedSystems的数据,因此对于第一条记录,您必须添加1个隐藏字段(用于1个字段),如<input type="hidden" name="SelectedSystems[0].PropertyName" id="SelectedSystems_0_PropertyName" />,对于第二条记录,<input type="hidden" name="SelectedSystems[1].PropertyName" id="SelectedSystems_1_PropertyName" />,并且应该在您的页面中绑定,以便您可以在JavaScript中循环并添加到任何空div中。 - Ravi
请告诉我,如果您仍然不理解。 - Ravi

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