如何在ASP.NET MVC 4中通过Ajax请求下载文件

19

以下是我的代码:

ActionResult DownloadAttachment(student st)
{          
    var file = db.EmailAttachmentReceived.FirstOrDefault(x => x.LisaId == st.Lisaid);

    byte[] fileBytes = System.IO.File.ReadAllBytes(file.Filepath);
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, file.Filename);                 
}

这是我正在使用的脚本

$(function () {
    $("#DownloadAttachment").click(function () {
        $.ajax({
            url: '@Url.Action("DownloadAttachment", "PostDetail")',
            contentType: 'application/json; charset=utf-8',
            datatype: 'json',
            type: "GET",
            success: function () {
                alert("sucess");
            }
        });    
    });
});      

如何使用上述代码返回可下载的文件?

6个回答

19

我认为不需要使用Ajax调用,你可以像下面的例子一样简单地使用超链接。

查看代码

<a href="@Url.Action("DownloadAttachment", "PostDetail", new { studentId = 123 })">Download Form</a>

控制器方法

public ActionResult DownloadAttachment(int studentId)
{          
    // Find user by passed id
    var file = db.EmailAttachmentReceived.FirstOrDefault(x => x.LisaId == studentId);    
    byte[] fileBytes = System.IO.File.ReadAllBytes(file.Filepath);    
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, file.Filename);                           
}

2
这个例子对我很有用。该示例发送了一个HttpGet请求,因此在URL中将数据负载(仅一个记录ID)作为参数包含。但是,如果我想发送一个HttpPost请求,并将数据有效载荷作为对象(包含许多字段)包含在请求中,该怎么办? - Mike Finch
另外,我能否在HttpPost请求中包含AntiForgeryToken? - Mike Finch

10

请在ajax成功后尝试此操作

success: function () {
    window.location = '@Url.Action("DownloadAttachment", "PostDetail")';
}

更新的回答:

public ActionResult DownloadAttachment(int studentId)
{          
    // Find user by passed id
    // Student student = db.Students.FirstOrDefault(s => s.Id == studentId);

    var file = db.EmailAttachmentReceived.FirstOrDefault(x => x.LisaId == studentId);

    byte[] fileBytes = System.IO.File.ReadAllBytes(file.Filepath);

    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, file.Filename);                       

}

Ajax请求:

$(function () {
        $("#DownloadAttachment").click(function () {
            $.ajax(
            {
                url: '@Url.Action("DownloadAttachment", "PostDetail")',
                contentType: 'application/json; charset=utf-8',
                datatype: 'json',
                data: {
                    studentId: 123
                },
                type: "GET",
                success: function () {
                    window.location = '@Url.Action("DownloadAttachment", "PostDetail", new { studentId = 123 })';
                }
            });

        });
    });

3
基本上,即使我们不使用ajax调用,仍然可以通过window.location下载文件,只是因为我们需要ajax请求,所以我们在success函数中使用它。感谢帮助! - rohit singh
4
DownloadAttachment 方法没有双重访问权限? - Harry
8
这将调用 DownloadAttachment 方法两次。如何避免这种情况发生? - Shaikh Farooque
39
完全没有必要使用ajax来完成这个任务,直接调用window.location即可。使用ajax只会导致相同的请求被发送两次。我不知道为什么会有人投赞成票。 - ADyson
2
这段代码中有一个冗余的ajax调用。你传递了相同的数据两次。问题在于,按设计,ajax被阻止从下载文件。 - John Lord
显示剩余5条评论

1
以下代码将帮助您在服务器上创建pdf/excel文件,并允许通过ajax调用在浏览器中下载。
创建pdf/excel文件的控制器
public async Task<JsonResult> CardStatusReportExport(ReportFilterInputModel cardStatusReportInputModel, string type, string sortOrder)
    {
        cardStatusReportInputModel.ReportType = Reprot_Type_Const.CardStatus;
        cardStatusReportInputModel.ReportFormat = type;

        var CardStatusReport = await _reportDocGeneration.DocGeneartion(cardStatusReportInputModel);
        string result = Path.GetTempPath();
        string fileName = "CardStatusReport" + DateTime.Now.ToString("yyyyMMddHHmmssfff");
        if (type.Equals(Constants.FILE_TYPE_PDF))
        {
            fileName = fileName + Constants.FILE_EXTENSION_PDF;
            System.IO.File.WriteAllBytes(result + fileName, CardStatusReport);
        }
        else
        {
            fileName = fileName + Constants.FILE_EXTENSION_EXCEL;
            System.IO.File.WriteAllBytes(result + fileName, CardStatusReport);
        }
        return Json(new { fileName = fileName});
    }

以下控制器代码将允许通过单个 AJAX 调用下载创建的文件。
[HttpGet]    
    public async Task<ActionResult> Download(string file)
    {
        var path = Path.Combine(Path.GetTempPath(),file);
        var memory = new MemoryStream();
        try
        {
            using (var stream = new FileStream(path, FileMode.Open))
            {
                await stream.CopyToAsync(memory);
            }
        }
        catch (Exception e)
        {
            ModelState.AddModelError("FileNotFoundError", e.Message);
            return Content(e.Message);
        }
        memory.Position = 0;
        return File(memory, GetContentType(path), Path.GetFileName(path));
    }

    private string GetContentType(string path)
    {
        var types = MediaType.GetMimeTypes();
        var ext = Path.GetExtension(path).ToLowerInvariant();
        return types[ext];
    }

使用以下 ajax 调用来创建 pdf/excel 文件并下载相应文件。
$.ajax({
                method: 'POST',
                data: { type: val, cardStatusReportInputModel: payload, sortOrder : sortOrder},
                url: '@Url.Action("CardStatusReportExport", "Reports")'
            }).done(function (data, statusText, xhdr) {
                try {
                    if (data.fileName != "") {
                        window.location.href = "@Url.RouteUrl(new { Controller = "Reports", Action = "Download"})/?file=" + data.fileName;
                        ShowMessageAlert('@Html.Raw(Localizer["Report has been exported successfully"].Value.ToString())');
                    }
                    $("#divLoader").hide();
                }
                catch (e) {
                    $("#divLoader").hide();
                }
            }).fail(function (xhdr, statusText, errorText) {
                alert('error');
                $("#divLoader").hide();
            });

0
public FileResult DownloadGeneralDocs(string docName)
    {
        string fileName = docName+".pdf";           
        var path = _globalWebSettings.Value.DownloadGeneralDocsPath;
        string filePath = "";
        if (fileName!="")
        {
            filePath = (_env.WebRootPath + string.Format("{0}{1}",path, fileName));
        }
        FileInfo file1 = new FileInfo(filePath);            
        byte[] fileBytes = System.IO.File.ReadAllBytes(file1.FullName);
        return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);            
    }

view.cshtml:
<script>
$(document).ready(function () {
    $("#docTable tbody tr td button").click(function (e) {
        var docName = $(this).closest("tr").find(".document_td_data").text();
        $.ajax({
            url: '@Url.Action("DownloadGeneralDocs", "Documents")',                    
                dataType: "html",
                cache:false,
                data: { 'docName': docName },
                success: function (data) {                     
                    window.location.href = "@Url.RouteUrl(new
                { Controller = "Documents", Action = "DownloadGeneralDocs" })/?docName=" + docName ;

                },
                error: function (err, response) {
                    console.log(err, response);
                    alert(err, response.responseText);
                }
            })

    });
});


3
在网上发布一大块没有解释的代码对任何人都没有帮助。你应该解释你的方法,并说明为什么你的答案更好或与其他答案不同。 - divibisan

0
实际上,没有必要对API进行双重调用。可以通过以下JavaScript代码来下载文件:
window.location.href = 
   '@Url.Action("DownloadAttachment", "PostDetail", new { studentId = 123 })';

如果您的代码不是放在.cshtml文件中:
window.location.href = '/PostDetail/DownloadAttachment?studentId=123';

-1
下面的方法可以帮助从jQuery对话框窗口调用Ajax请求执行操作,并且在操作返回成功结果后可以关闭对话框窗口。 控制器
    [HttpGet]
    public ActionResult DownloadCampaign(string filePath, string mode)
    {
        string contentType = string.Empty;
        var sDocument = filePath;
        if (!System.IO.File.Exists(sDocument))
        {
            return HttpNotFound();
        }

        if (mode == "action")
            return Json(new {fileName = filePath}, JsonRequestBehavior.AllowGet);

        if (sDocument.Contains(".pdf"))
        {
            contentType = "application/pdf";
        }
        else if (sDocument.Contains(".docx"))
        {
            contentType = "application/docx";
        }
        else if (sDocument.Contains(".xls"))
        {
            contentType = "application/xlsx";
        }

        return File(sDocument, contentType, sDocument);
    }

JQuery - Ajax请求

$(document)
    .ready(function() {
        $("#btnDownload").click(function () {
            var file = $("#FilePath").val();
            $.ajax({
                url: '@Url.Action("DownloadCampaign", "FileList")',
                data: { filePath: file, mode:'action' },
                method: 'GET',
                dataType: 'json',
                //contentType: 'application/json; charset=utf-8',

                success: function(data) {
                    @*window.location = '@Url.RouteUrl("DownloadCampaign", "FileList", new { filePath = data1.fileName })';*@
                    window.location.href = "@Url.RouteUrl(new
                    { Controller = "FileList", Action = "DownloadCampaign" })/?filePath=" + data.fileName + "&mode=download";
                    $("#downloadFile_dialog").dialog("close");
                },
                error: function (req, status, errorObj) {
                    alert("Error");
                }
            });

        });
});

如果您需要更多关于此事的信息,请与我联系。

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