使用Jquery Post使用Web API下载文件

时间:2014-06-12 14:06:23

标签: c# jquery asp.net knockout.js asp.net-web-api2

我有一个返回文件流的Web Api函数

[HttpPost] 
public HttpResponseMessage DownloadDocument([FromBody] parameters)
    {
        try
        {
            var stream = FileHelper.GetFilesStream(fileUrl);
            HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StreamContent(stream) };
            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            result.Content.Headers.ContentDisposition.FileName = fileName;
            return result;
        }
        catch (Exception)
        {
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, "File Not Found");
        }
    }

如何在Jquery Ajax中调用此方法来下载文件,以便弹出保存文件对话框。我正在使用knockout.js,在按钮的单击事件处理程序中,我调用此WebAPI方法并获取流,但我不知道如何将其保存到文件中。

3 个答案:

答案 0 :(得分:2)

您无法从ajax调用下载文件。您需要使用get请求下载文件。

您可以使用上面的ajax帖子,但是将文件保存在数据库中,然后返回带有文档ID或URL的json以下载文档。然后,您可以添加将下载文档的隐藏iframe。

请看一下这个答案,该答案说明了如何操作:https://stackoverflow.com/a/16086443/2326610

答案 1 :(得分:1)

AFAIK你无法通过JQuery直接下载文件。解决这个问题的一种方法是在html中声明一个隐藏的iframe:

<iframe id='hiddenIframe' src="" style="display:none; visibility:hidden;" ></iframe>

单击“下载”按钮/链接,然后在jQuery中,您只需设置iframe源:

$('#downloadButton').click(function(){
    $('#hiddenIframe').attr('src', 'api/DownloadDocument');
})

答案 2 :(得分:0)

您可以通过修改向webapi发送数据的方式来解决此问题。

在您的Javascript中,您可以创建隐藏的表单并将所需的数据附加到该表单,然后提交。

coffeescript中提供的示例代码,但应易于阅读/转换:

downloadDocument: (fileUri, otherProp, successCallback) =>
    if $('#hidden-form').length > 0
        $('#hidden-form').remove()

    $('<form>').attr(
        method: 'POST',
        id: 'hidden-form',
        action: '/your/url/to/method'
    ).appendTo('body');

    $('<input>').attr({
        type: 'hidden',
        id: 'fileUri',
        name: 'fileUri',
        value: fileUri
    }).appendTo('#hidden-form')
    $('<input>').attr({
        type: 'hidden',
        id: 'otherProp',
        name: 'otherProp',
        value: otherProp
    }).appendTo('#hidden-form')

    $('#hidden-form').bind("submit", successCallback)
    $('#hidden-form').submit()

然后我还会创建一个DTO对象,它作为webAPI控制器中的参数,而不是从请求体读取:

public DownloadDocumentDTO
{
    public string fileUri {get;set;}
    public object otherProp {get;set;}
}

[HttpPost] 
public HttpResponseMessage DownloadDocument(DownloadDocumentDTO _dto)
{
    ....
}

控制器方法中的代码应该没问题。 应该注意的是,如果你试图传递更复杂的数据(不知道你是否做过,因为它没有提到),那么你需要向隐藏表单添加更多输入,它不适用于传递对象起来。