下载使用MVC5选择的多个文件

Seb*_*ba. 3 javascript c# asp.net-mvc-5

我正在 MVC5 中开发一个如下所示的视图:

在此处输入图片说明

我需要选择表的一个或多个记录,并能够在数据库中下载以前保存的文件。我一直在寻找解决方案并进行了多次测试,但我找不到解决方案。我试图从 javascript 将选定的代码发送到控制器并从中下载文档,但我无法做到。下载可能是在您可以的情况下,获取所有文件并生成一个 zip,或者自动将所有文件下载到浏览器的默认文件夹。我将不胜感激任何可以帮助我的人......您好!

这是我的 ajax 调用:

  $.ajax({
            type: "POST",
            url: "/GestionGarantias/Garantias/Download",
            data: { pCodigo: mCodigo },//Here I would send the list of //codes, but now to test, I only call the controller regardless of the value, //because the values in the list set them in the handy controller to test.
            xhrFields: {
                responseType: 'blob'
            },
            success: function (data) { //Here should I bring a zip with all files supposedly?
                var a = document.createElement('a');
                var url = window.URL.createObjectURL(data);
                a.href = url;
                a.download = 'myfile.zip'; //------------------> I UNDERSTAND THAT THIS IS THE NAME THAT WE SHOULD INDICATE FOR Download ... is it so?
                a.click();
                window.URL.revokeObjectURL(url);
            },
            error: function (request, status, errorThrown) {
                //alert("Se produjo un error al descargar los adjuntos.");
            }
        });
Run Code Online (Sandbox Code Playgroud)

我的控制器:

[HttpPost]
        public ActionResult Download(List<String> codes)
        {
            codes = new List<string>();
            codes.Add("1079");
            codes.Add("1078");
            codes.Add("1077");
            MemoryStream ms = null;

            foreach (string codigoGar in codes)
            {
                string mimetypeOfFile = "";
                Garantias oGarantia = ControladorGarantias.getGarantia(SessionHelper.GetEntorno(), codigoGar);
                var stream = new MemoryStream(oGarantia.comprobante);
                ms = new MemoryStream();

                byte[] buffer = new byte[256];
                if (stream.Length >= 256)
                    stream.Read(buffer, 0, 256);
                else
                    stream.Read(buffer, 0, (int)stream.Length);

                try
                {
                    System.UInt32 mimetype;
                    FindMimeFromData(0, null, buffer, 256, null, 0, out mimetype, 0);
                    System.IntPtr mimeTypePtr = new IntPtr(mimetype);
                    mimetypeOfFile = Marshal.PtrToStringUni(mimeTypePtr);
                    Marshal.FreeCoTaskMem(mimeTypePtr);
                }
                catch (Exception e)
                {
                    return null;
                }

                string fileName = "";

                if (!string.IsNullOrEmpty(mimetypeOfFile))
                {
                    switch (mimetypeOfFile.ToLower())
                    {
                        case "application/pdf":
                            fileName = "Comprobante_" + oGarantia.nombreService + "_" + oGarantia.nroFactura + ".pdf";
                            break;
                        case "image/x-png":
                            fileName = "Comprobante_" + oGarantia.nombreService + "_" + oGarantia.nroFactura + ".png";
                            break;
                        case "image/pjpeg":
                            fileName = "Comprobante_" + oGarantia.nombreService + "_" + oGarantia.nroFactura + ".jpg";
                            break;
                    }
                }
                using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, true))
                {
                    var entry = zip.CreateEntry(fileName);
                    using (var fileStream = stream)
                    using (var entryStream = entry.Open())
                    {
                        fileStream.CopyTo(entryStream);
                    }
                }
            }
            return File(ms.ToArray(), "application/zip");
        }
Run Code Online (Sandbox Code Playgroud)

我所做的是在其中创建一个列表,仅用于测试。我的想法是针对表中选择的每条记录,找到它们的信息,(文件)并将它们添加到 zip 中。

我究竟做错了什么?非常感谢!并原谅无知。

Chr*_*att 8

你的问题有两部分。首先是获取所有文件的问题,其次是下载文件的问题。在我们解决这些问题之前,让我们退后一步,了解请求-响应循环的工作原理。

使用 HTTP,客户端发出请求,服务器返回响应。重要的是,这里有一个精确的 1-1 相关性。一个请求只能有一个响应。这意味着如果您需要提供多个文件作为下载,则必须将它们压缩,因为您只能返回一个文件,而不能返回多个文件。创建 zip 文件允许您只返回一个文件,同时仍然满足允许用户一次下载所有文件的要求。

然后是 AJAX 的问题。XMLHttpRequestJavaScript 中的对象本质上是一个瘦客户端。它发出 HTTP 请求并接收响应,仅此而已。与通过地址栏导航时由 Web 浏览器发出的请求不同,响应不会自动完成,而是由您自己负责,因为开发人员要处理响应并实际使某些事情发生。

顺便说一下,第一部分是创建一个可以返回 zip 文件作为响应的操作。这实际上非常简单:您只需要返回一个FileResult

[HttpPost]
public ActionResult DownloadCodes(List<int> codes)
{
    // use codes to get the appropriate files, however you do that

    using (var ms = new MemoryStream())
    using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, true))
    {
        foreach (var file in files)
        {
            // write zip archive entries
        }

        return File(ms.ToArray(), "application/zip");
    }
}
Run Code Online (Sandbox Code Playgroud)

对于 zip 存档条目的写入,这取决于文件数据的来源。如果您有文件系统引用,则只需执行以下操作:

zip.CreateEntryFromFile(file, Path.GetFileName(file));
Run Code Online (Sandbox Code Playgroud)

如果您有字节数组,例如您从数据库中的 varbinary 列返回的内容:

var entry = zip.CreateEntry(file.Name);
using (var fileStream = new MemoryStream(file.Data))
using (var entryStream = entry.Open())
{
    fileStream.CopyTo(entryStream);
}
Run Code Online (Sandbox Code Playgroud)

Wherefile.Namefile.Data分别是指您存储文件名的位置和存储文件数据的位置的属性。

现在,您可以简单地对此操作进行普通表单发布,并且由于响应是在 Web 浏览器中无法查看的文件类型(zip 存档),因此浏览器将自动提示下载。此外,由于这在浏览器中无法查看,因此选项卡/窗口中的实际视图也不会更改,从而无需使用 AJAX 来完成停留在同一页面上的正常需求。但是,如果需要,您可以使用 AJAX,但您只能在现代浏览器中使用 AJAX 处理文件响应(基本上除了 IE 10 或更低版本之外的任何东西)。如果您不需要支持旧版本的 IE,那么您需要的代码将类似于:

jQuery

$.ajax({
    url: '/url/to/download/code/action',
    data: data // where `data` is what you're posting, i.e. the list of codes
    xhrFields: {
        responseType: 'blob'
    },
    success: function (data) {
        // handle file download
    }
});
Run Code Online (Sandbox Code Playgroud)

纯 JavaScript

var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function () {
    var data = xhr.response;
    // handle file download
}
xhr.open('POST', '/url/to/download/codes/action');
xhr.send();
Run Code Online (Sandbox Code Playgroud)

无论你走哪条路,处理文件下载的代码是:

var a = document.createElement('a');
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = 'myfile.pdf';
a.click();
window.URL.revokeObjectURL(url);
Run Code Online (Sandbox Code Playgroud)


Muh*_*sim 0

使用以下类来下载文件:

public class FileDownloadResult : ContentResult
{
    private string fileName;
    private Stream fileData;
    private bool downloadFlag;
    public FileDownloadResult(string fileName, Stream fileData, bool downloadFlag)
    {
        this.fileName = fileName;
        this.fileData = fileData;
        this.downloadFlag = downloadFlag;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        if (string.IsNullOrEmpty(this.fileName))
            throw new Exception("A file name is required.");
        if (this.fileData == null)
            throw new Exception("File data is required.");
        var contentDisposition = "";
        if (!downloadFlag)
            contentDisposition = string.Format("inline; filename={0}", this.fileName);
        else
            contentDisposition = string.Format("attachment; filename={0}", this.fileName);
        context.HttpContext.Response.AddHeader("Content-Disposition", contentDisposition);


        if (downloadFlag)
            ContentType = "application/force-download";
        else
        {
            if (this.fileName.IndexOf(".pdf", fileName.IndexOf(".")) > 0)
                ContentType = "application/pdf";
            else if (this.fileName.IndexOf(".csv", fileName.IndexOf(".")) > 0)
                ContentType = "application/csv";
            else if (this.fileName.IndexOf(".xls", fileName.IndexOf(".")) > 0)
                ContentType = "application/xls";
            else if (this.fileName.IndexOf(".xlsx", fileName.IndexOf(".")) > 0)
                ContentType = "application/xslx";
            else
                ContentType = "application/txt";
        }
        context.HttpContext.Response.AddHeader("Content-Type", ContentType);

        byte[] buffer = new byte[1024];


        int count = 0;
        while ((count = fileData.Read(buffer, 0, buffer.Length)) > 0)
        {
            context.HttpContext.Response.OutputStream.Write(buffer, 0, count);
            context.HttpContext.Response.Flush();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的控制器中,使用如下:

public FileDownloadResult Download(string fileName, Stream fileStream)
{
     return new FileDownloadResult(fileName, fileStream, true);
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你 :)