C# 如何使用 jQuery Ajax 调用从 ASP.NET Web Api 下载 CSV 文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15334227/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 16:27:18  来源:igfitidea点击:

How to download CSV file from ASP.NET Web Api using jQuery Ajax call

c#jqueryasp.net-web-api

提问by cuongle

I am working on how to download CSV file from ASP.NET Web Api from jQuery ajax call. The CSV file is generated dynamically from Web API server based on custom CsvFormatter.

我正在研究如何通过 jQuery ajax 调用从 ASP.NET Web Api 下载 CSV 文件。CSV 文件是基于自定义 CsvFormatter 从 Web API 服务器动态生成的。

Ajax from jQuery:

来自 jQuery 的 Ajax:

   $.ajax({
        type: "GET",
        headers: {
            Accept: "text/csv; charset=utf-8",
        },
        url: "/api/employees",
        success: function (data) {
        }
    });

On the server, the EmployeeCsvFormatteris implemented similar with below article, derived from BufferedMediaTypeFormatter:

在服务器上,EmployeeCsvFormatter实现与以下文章类似,源自BufferedMediaTypeFormatter

http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters

http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters

public class EmployeeCsvFormatter : BufferedMediaTypeFormatter
{
    public EmployeeCsvFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
    }
    ...
}

I also added override method to indicate that I would like to download like normal way to download file (can see the download file in download tab):

我还添加了覆盖方法来表明我想像正常下载文件一样下载(可以在下载选项卡中看到下载文件):

 public override void SetDefaultContentHeaders(Type type, 
    HttpContentHeaders headers, MediaTypeHeaderValue mediaType)       
{
    base.SetDefaultContentHeaders(type, headers, mediaType);
    headers.Add("Content-Disposition", "attachment; filename=yourname.csv");
    headers.ContentType =  new MediaTypeHeaderValue("application/octet-stream");
}

But it does not work, the download file does not showed in status bar or in download tab on Chrome, even though from Fiddler, I see it the response seems correct:

但它不起作用,下载文件没有显示在状态栏或 Chrome 的下载选项卡中,即使从 Fiddler 中,我看到响应似乎是正确的:

HTTP/1.1 200 OK
Server: ASP.NET Development Server/11.0.0.0
Date: Mon, 11 Mar 2013 08:19:35 GMT
X-AspNet-Version: 4.0.30319
Content-Disposition: attachment; filename=yourname.csv
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: application/octet-stream
Content-Length: 26
Connection: Close

1,Cuong,123
1,Trung,123

My method from ApiController:

我来自 ApiController 的方法:

public EmployeeDto[] Get()
{
    var result = new[]
               {
                   new EmployeeDto() {Id = 1, Name = "Cuong", Address = "123"},
                   new EmployeeDto() {Id = 1, Name = "Trung", Address = "123"},
               };

    return result;
}

It must be wrong somewhere which I have not figured out. How can I make it work by downloading CSV file like normal way?

一定是我没有弄清楚的地方是错误的。如何通过像正常方式下载 CSV 文件来使其工作?

采纳答案by flup

jQuery Plugin for Requesting Ajax-like File Downloadsdoes it without Ajax using a simple form submit.

jQuery Plugin for Requesting Ajax-like File Downloads使用简单的表单 submit在没有 Ajax 的情况下完成它。

Internally:

内部:

jQuery('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
    .appendTo('body').submit().remove()

It has an ajax-style interface so from outside you can call it like this

它有一个ajax风格的界面,所以从外面你可以这样调用它

$.download('/api/employees','format=csv');

Another simple approach using:

另一种简单的方法使用:

$('#btnDownload').click(function (e) {
    e.preventDefault();
    window.location = "/api/employees?format=csv";
});

On the server, MediaTypeMappingsmust be used by adding one more constructor:

在服务器上,MediaTypeMappings必须通过添加一个更多的构造函数来使用:

    public EmployeeCsvFormatter(MediaTypeMapping mediaTypeMapping)
        : this()
    {
        MediaTypeMappings.Add(mediaTypeMapping);
    }

Then, add this formatter into Web Api configuration:

然后,将此格式化程序添加到 Web Api 配置中:

   configuration.Formatters.Add(new EmployeeCsvFormatter
            (new QueryStringMapping("format", "csv", "text/csv")));

回答by nmushov

You can also set the request header in beforeSend by modifying the xhr.

也可以通过修改 xhr 来设置 beforeSend 中的请求头。

    $.ajax({
    url: "/api/employees",
    type: "GET",
    beforeSend: function (xhr) {
        xhr.setRequestHeader("Accept", "text/csv");
    },
    success: function (data) {
            }
    });

回答by Sudhanshu Mishra

As an alternative approach, one can offer the download on click of an anchor () or button with the URL requested set to the API method that responds with the attachment.

作为另一种方法,可以通过单击锚点 () 或按钮提供下载,并将请求的 URL 设置为响应附件的 API 方法。

In the CsvMediaTypeFormatter(Derived from System.Net.Http.Formatting.MediaTypeFormatter), in addition to mapping the text/csv MIME type as shown in the answers above, I found the following needs to be done:

CsvMediaTypeFormatter(Derived from System.Net.Http.Formatting.MediaTypeFormatter) 中,除了如上面的答案所示映射 text/csv MIME 类型外,我发现还需要完成以下工作:

public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
        {
            base.SetDefaultContentHeaders(type, headers, mediaType);
            headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = string.Concat("data", DateTime.UtcNow.ToString("yyyyMMddhhmmss"), ".csv")
            };

            headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        }

Note: When writing the stream, set the Content-Lengthheader and remember to Flush the stream. I found that without a call to Flush(), the returned response does not make it back to the client successfully even when the correct content length has been set.

注意:写流的时候,设置Content-Lengthheader,记得Flush the流。我发现如果没有调用Flush(),即使设置了正确的内容长度,返回的响应也不会成功返回到客户端。