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 中。
我究竟做错了什么?非常感谢!并原谅无知。
你的问题有两部分。首先是获取所有文件的问题,其次是下载文件的问题。在我们解决这些问题之前,让我们退后一步,了解请求-响应循环的工作原理。
使用 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.Name和file.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)
使用以下类来下载文件:
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)
希望能帮助到你 :)
| 归档时间: |
|
| 查看次数: |
4585 次 |
| 最近记录: |