【问题标题】:ASP.NET MVC file download and jQuery parameterASP.NET MVC 文件下载和 jQuery 参数
【发布时间】:2013-12-19 23:38:19
【问题描述】:

我有一个(ViewResult)控制器,它接收一个字符串参数,生成一个 PDF 文件,并将 PDF 文件发送回浏览器。我已经测试了控制器本身,它工作正常。不幸的是,当我尝试从 $.ajax jQuery 函数(传递一个简单的字符串)向该控制器发布信息时,控制器 always 将字符串参数接收为 null。我已经尝试了一百种不同的 $.ajax 函数配置。这是控制器,它向浏览器返回一个 PDF(它可以工作......只要我在方法中创建 HTML):

[HttpPost]
public ActionResult HtmlToPdf(String htmlData)
{ }

这是我在视图中使用的 jQuery(由单击按钮触发):

function getPdf() {
    var htmlData = “blah, blah, etc.”;
    $.ajax({
        url: '/Home/HtmlToPdf',
        type: 'post',
        data: JSON.stringify(htmlData),
        contentType: 'application/json; charset=utf-8',
        success: handleSuccess,
        error: handleError
    });
}

我已经尝试过'post'、'get'、json、text、html、stringify、不同的内容类型等。有谁知道如何正确地将字符串(上面的 var 'htmlData')发送到控制器?邮政?得到?还有什么?谢谢。

【问题讨论】:

  • 尽量不要对您的对象进行字符串化,将其发送为data: htmlData
  • 试过了。仍然为空。
  • 嗯,我之前也遇到过类似的问题...我会删除contentType 部分,我发现即使按照您的方式对其进行编码(即使使用正确的类型) ,通过删除它,MVC 将正确地破译它。只是我的 2 美分 ;)
  • 尝试使用 Razor 对 Url 进行编码,例如 @Url.Action("myAction", "myController")`

标签: jquery asp.net-mvc download


【解决方案1】:

您需要将其作为 json 对象发送:

function getPdf() {
    var htmlData = “blah, blah, etc.”;
    var dataToPost = { htmlData: htmlData };
    $.ajax({
        url: '/Home/HtmlToPdf',
        type: 'POST',
        data: JSON.stringify(dataToPost),
        dataType: 'json',
        contentType: 'application/json; charset=utf-8',
        success: handleSuccess,
        error: handleError
    });
}

然后,您只需像您所做的那样将其声明为参数即可访问 HomeController。关键是您需要将参数的名称作为 JSON 对象的一部分传递。您的变量名也是“htmlData”这一事实无关紧要。以上可以很容易地......

var stuff = "blah, etc...";
var dataToPost = { htmlData: stuff };

显然,对于多个参数,您的对象中只有更多项目...

var dataToPost = { arg1: someData, arg2: 2, arg3: true }

...与...

public ActionResult DoStuff(string arg1, int? arg2, bool? arg3) {}

如果要传递数组,请将 traditional:true 添加到 $.ajax 参数对象。

我还注意到,我一直将“POST”以大写形式显示,因为如果您查看文档 heredatatype: 参数(例如“json”)以小写形式列出,但“GET” type: 的 'POST' 是大写的。

-------------- 更新 ------------------ -------

如 cmets 中所述,对于简单的文件下载,使用 GET 可能更容易。

基本控制器是这样的(我正在精简代码,所以还没有测试过)

public FileResult DownloadFile(string filename)
{
    byte[] fileContent = new byte[0];
    using(FileStream fs = File.OpenRead(filename)) {
        fileContent = new byte[fs.Length];
        fs.Read(fileContent, 0, Convert.ToInt32(fs.Length));
    }
    UTF8Encoding encoder = new UTF8Encoding();
    return File(encoder.GetBytes(fileContent), "applicaton/text", filename);
}

然后在javascript中做:

$.get('/Home/DownloadFile',
    function(data, textStatus, jqXHR) { /* don't think anything needs to be done */ }
).error(alert('Download failed'));

这显然会下载一个文本文件,因此您需要使用编码(可能/可能不需要?)和 PDF 的 contentType 字符串(我认为它只是“应用程序/PDF”)。另外,重复一遍,我没有测试过这个确切的代码,只是从现有应用程序中编辑了逻辑。祝你好运。

【讨论】:

  • 很奇怪;还是不行。我必须使用 GET,因为控制器正在返回 FileStreamResult。如果我使用 Html.ActionLink 而不是普通按钮,则正确调用控制器操作....我只是不能像我想要的那样传递长字符串。使用按钮(和 $.ajax 函数)将调用控制器操作,但成功后,浏览器不会呈现生成的 PDF 文件。我需要在“成功”中使用特定的操作/命令来简单地呈现服务器的响应吗?
  • (回应您上面的更新):这看起来太简单了!我会在星期一试试。 FWIW,我是唯一一个曾经 涉足 jQuery(!) 的 .NET 开发人员。再次感谢。
  • "jQuery 1.5 中引入的 jqXHR.success()、jqXHR.error() 和 jqXHR.complete() 回调方法在 jQuery 1.8 中已被弃用。"
【解决方案2】:

尝试将您的 data 作为 json 对象发送并将 dataType 设置为 'json'

function getPdf() {
    var htmlData = “blah, blah, etc.”;
    $.ajax({
        url: '/Home/HtmlToPdf',
        type: 'post',
        data: { htmlData: htmlData },
        dataType: 'json',
        contentType: 'application/json; charset=utf-8',
        success: handleSuccess,
        error: handleError
    });
}

【讨论】:

  • 我也试过了,没有成功。真的,我已经使用了数十种不同的 $.ajax 函数“配置”。我开始怀疑它是否与 POST 与 GET 或其他一些事情有关。
  • 哦,还有一件事:如果我使用上面的语法(数据:{ htmlData:htmlData }),该函数会抛出错误函数。我不知道为什么。如果我只使用 [data: htmlData],则成功调用了控制器。 :-p
  • @TheDudeDude - 当您将 dataType: 'json' 发送为 json 时,您添加了吗?
  • @TheDudeDude - 如果这仍然不适合您,另一种尝试是再次删除 dataType 属性并将您的 data 属性更改为如下所示:data: $.param({htmlData: htmlData })。您问题中示例的问题是您发送的数据没有键/值对,因此当 MVC 接收到它时,它只是一个原始字符串,而不是它可以匹配的实际 HTTP POST/GET 参数那个行动。我建议的版本会将帖子数据发送为htmlData=blah%2C+blah%2C+etc.,MVC 理论上应该正确解释...
【解决方案3】:

感谢您的回答。我认为他们都是正确的,而且很好。不过,我放弃了这个,因为我认为我正在尝试做一些不太可能的事情:向服务器发送 ajax 调用并通过将二进制文件返回给浏览器让服务器“完成工作”(作为PDF)。 ajax 函数正在执行、获取成功消息并运行其成功函数。迷失在这一切的事实是浏览器应该接收文件响应,而不是 ajax 响应。对不起,如果我没有很好地解释它。无论如何,我退后一步:我通过将 .NET 报告 (.rdlc) 呈现为 PDF 并将其发送到浏览器来生成我的文件。粗鲁,但有效。事后看来,我认为 ajax 甚至不是解决这个问题的方法。 :-p。再次感谢您的帮助。

【讨论】:

  • 这可以在 AJAX 中完成,因为我们一直都在这样做。我最近没有查看代码,但回想一下,使用的一种技术是执行初始 POST 以生成文件并返回数据以更新屏幕,然后在成功函数中发出第二个返回文件的 POST。我查一下代码。
  • @starnamer 哦,很好的答案!我没有想到两个单独的帖子。我想我会重新访问,谢谢!
【解决方案4】:

使用双重 POST 方法和来自here 的免费 jQuery 扩展“fileDownload”

/*
* jQuery File Download Plugin v1.4.1
*
* http://www.johnculviner.com
*
* Copyright (c) 2013 - John Culviner
*
* Licensed under the MIT license:
*   http://www.opensource.org/licenses/mit-license.php
*/

这基本上在一些代码中包装了一个 POST,这有助于处理一些复杂性......

我们已经(删除了大块(!)...

        $.ajax({
            url: emr.baseURL + '/Control/SaveData',
            type: 'POST',
            data: JSON.stringify(dataToPost),
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            success: function (json) {
// stuff deleted which updates page
                        $.fileDownload(
                            '/Control/Export',
                            {
                                data: {
// data list deleted...
                                    ))
                                },
                                httpMethod: 'POST'
                            });
                    }
            },
            error: function () {
// deleted
            }
        });

使用控制器方法(减少)

public JsonResult SaveData(/* ... */)
{
    /*
     ... do stuff ...
     */
    return /* JsonResult... */;
}

[HttpPost]
public void Export(/* ... */)
{
    /*
     ...
     */
    HttpContext context = System.Web.HttpContext.Current;
    /*
     ...
     */
    byte[] XLSXdata;
    /*
     ...Fill XLXSdata...
     */
    context.Response.Clear();
    context.Response.ClearHeaders();
    context.Response.ClearContent();
    context.Response.Buffer = false;
    context.Response.ContentType = "application/vnd.ms-excel";
    context.Response.AddHeader("content-disposition", "attachment;filename="+filename);
    context.Response.Charset = "";
    context.Response.BinaryWrite(XLSXdata);
    context.Response.Flush();
    context.Response.End();
}

显然,这是明确控制响应中的内容。

希望这会有所帮助!/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 2023-04-07
    • 2012-01-25
    • 2014-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多