如何将 JavaScript 数组发布到 MVC 3 控制器操作(由于文件下载而没有 AJAX)

How do I post a JavaScript array to an MVC 3 controller action (no AJAX due to file download)?

本文关键字:文件下载 AJAX 操作 控制器 数组 JavaScript MVC      更新时间:2023-09-26

我正在尝试做一些看起来应该很容易的事情,但我是MVC和基于约定的编程的新手。

我有一个jQuery数据表,它通过AJAX获取PDF文档的行。在fnRowCallback中,我添加了复选框,以便用户可以选择要合并的多个文档以进行一次下载。选中复选框时,文档 ID 将添加到 JavaScript 数字数组中,文件名将添加到另一个数组中,以便在组合时,它们可以用于生成的 PDF 中的书签。有没有办法将这两个变量发送到控制器操作?到目前为止,我所能做的就是JSON.stringify()其中一个变量,并使用我放在视图上的隐藏字段将其发送到控制器并在控制器中反序列化它,但是当我尝试添加第二个变量时,我把它搞砸了。必须有一种更简单的方法,但我什至无法弄清楚复杂的方法,我读过的所有文章都使用 AJAX。但是,我不能使用 AJAX,因为您无法在响应中发送回二进制文件。

JavaScript:

var aiSelectedPDFs = new Array();
var aiSelectedDocumentIDs = new Array();
$('#imgDownload').click(function () {
    $('#selectedPDFs').val(JSON.stringify(aiSelectedPDFs));
    $('#selectedDocumentIDs').val(JSON.stringify(aiSelectedDocumentIDs));
    $('#DownloadSelectedPdfs').submit();
});

视图:

<img id="imgDownload" src="@(Url.RootUrl())Content/images/icons/pdf.gif" 
    alt="Download selected documents" title="Download selected documents" />
@using (Html.BeginForm("DownloadSelectedPdfs", "Controller", FormMethod.Post, 
    new { id = "DownloadSelectedPdfs" }))
{
    <input type="hidden" id="selectedPdfs" name="jsonSelectedPdfs"/>
    <input type="hidden" id="selectedDocumentIDs" name="jsonSelectedDocumentIDs"/>
}

控制器:

    [HttpPost]
    public ActionResult DownloadSelectedPdfs(string jsonSelectedDocumentIDs)
    {
        var selectedDocumentIDs = new JavaScriptSerializer().Deserialize<int[]>(
            jsonSelectedDocumentIDs);
        var invoices = new Dictionary<string, byte[]>();
        foreach (int documentID in selectedDocumentIDs)
        {
            invoices.Add(documentID.ToString(), 
                _documentService.GetDocument(documentID));
        }
        return new FileContentResult(PdfMerger.MergeFiles(invoices), 
            "application/pdf");
    }

你的答案是90%正确,Kroehre。感谢您如此快速的回复。唯一的问题是应用程序无法确定要使用什么控制器操作,因此页面无法加载,我被重定向到我的友好错误页面。不过,解决方案非常简单,我将把代码放在下面。

视图(我省略了div,因为我觉得它们用表示语义玷污了代码,其中没有显示任何内容,尽管它们没有语法影响。只是个人喜好,所以不是缺少的10%的一部分。;-) ):

<img id="imgDownload" src="@(Url.RootUrl())Content/images/icons/pdf.gif" 
    alt="Download selected documents" title="Download selected documents" />
@using (Html.BeginForm("DownloadSelectedPdfs", "Controller", FormMethod.Post, 
    new { id = "DownloadSelectedPdfs" })) { }

脚本(创建了类似的多个隐藏输入,但命名使它们是具有属性的同一对象(:

var aiSelectedPDFs = new Array();
var aiSelectedDocumentIDs = new Array();
$('#imgDownload').click(function () {
    var form = $('#DownloadSelectedPdfs');
    form.html('');
    for (var i = 0; i < aiSelectedPDFs.length; i++) {
        form.append('<input type="hidden" name="selectedPDFs[' + i + '].RefNumber" 
            value="' + aiSelectedPDFs[i] + '" />');
        form.append('<input type="hidden" name="selectedPDFs[' + i + '].DocumentID" 
            value="' + aiSelectedDocumentIDs[i] + '" />');
    }
    form.submit();
});

控制器(添加了新类来处理多个相关的 JavaScript 变量(:

public class PDFViewModel
{
    public int RefNumber { get; set; }
    public int DocumentID { get; set; }
}
[HttpPost]
public ActionResult DownloadSelectedPdfs(List<PDFViewModel> selectedPDFs)
{
    var pdfs = new Dictionary<string, byte[]>();
    foreach (var selectedPDF in selectedPDFs)
    {
        var document = _documentService.GetDocument(selectedPDF.DocumentID);
        var tabName = string.Format("pdf_{0}", selectedPDF.RefNumber);
        pdfs.Add(tabName, document);
    }
    return new FileContentResult(PdfMerger.MergeFiles(pdfs), "application/pdf");
}

数组可以通过为每个值指定数组名称和索引来通过表单传输。我已经修改了你的代码:

视图(将隐藏的输入替换为容器(:

<img id="imgDownload" src="@(Url.RootUrl())Content/images/icons/pdf.gif" 
    alt="Download selected documents" title="Download selected documents" />
@using (Html.BeginForm("DownloadSelectedPdfs", "Controller", FormMethod.Post, 
    new { id = "DownloadSelectedPdfs" }))
{
    <div id="pdfs"></div>
    <div id="docs"></div>
}

脚本(为数组中的项目添加/填充隐藏输入,而不是使用字符串化(:

var aiSelectedPDFs = new Array();
  var aiSelectedDocumentIDs = new Array();
  function createInputs(container, name, values){
    $(container).html('');
    for(var i = 0; i<values.length; i++){
      $(container).append('<input type="hidden" name="' + name + '[' + i + ']" value="' + values[i] + '" />');
    }    
  }
  $('#imgDownload').click(function () {
    createInputs('#pdfs', 'selectedPdfs', aiSelectedPDFs);
    createInputs('#docs', 'selectedDocumentIDs', aiSelectedDocumentIDs);
    $('#DownloadSelectedPdfs').submit();
  });

控制器(更新输入参数以与发布的数组对齐,利用 MVC3 的内置模型绑定器(:

[HttpPost]
    public ActionResult DownloadSelectedPdfs(List<int> selectedPdfs, List<int> selectedDocumentIDs)
    {
        var invoices = new Dictionary<string, byte[]>();
        foreach (int documentID in selectedDocumentIDs)
        {
            invoices.Add(documentID.ToString(), 
                _documentService.GetInvoice(documentID));
        }
        return new FileContentResult(PdfMerger.MergeFiles(invoices), 
            "application/pdf");
    }

*注意 - 我对参数使用了List<int>而不是int[]因为类型必须能够在实例化后添加元素,以便模型绑定器在读取已发布的值时正常运行。