我有一个Asp.Net WebApi和一个Asp.Net MVC Web项目。 Web Api提供文件下载功能。浏览器请求MVC WebClient中的DownloadController,它与Web Api文件下载控制器进行通信。
我提到了this文章来实现WebApi的文件下载。(我试图直接从浏览器调用web api,如示例中所提到的那样有效)。但在我的情况下,我需要通过MVC Web App将文件发送到浏览器。 我得到了内存流到Web服务器(MVC控制器),并在WebServer临时文件夹(C:\ Temp文件夹)中,它创建了一个文件但是大小为0kb并且无法打开(无法读取文件,某些进程是使用它)。重新启动IIS时,它会给出错误"格式异常:不是有效的PDF或已损坏的"。
浏览器获得了一个Download Pdf,它表示正在加载,但从未完成。
我保持内存流开放,直到文件下载在Web Api中完成。否则,我从Web Api到Web服务器得到一个null响应。
我做了一些不推荐的事情吗?处理这种情况的最佳方法是什么?
这是代码,
Web Api项目,下载文件功能
public HttpResponseMessage GetById(string fileid)
{
//fileid = e.g. <someguid>.pdf
try
{
var result = DownloadBlob(fileid);
if (result == null)
{
return new HttpResponseMessage(HttpStatusCode.NotFound);
}
result.BlobStream.Position = 0;
return Request.CreateResponse(HttpStatusCode.OK, result);
}
}
MVC Web App(与Web Api对话并需要发送文件响应)
public async Task<FileStreamResult> DownloadInvoice()
{
string id = "6bc7fb58-4bd3-4a09-bd90-98a837d4e441.pdf";
//Call WebApiClient
BcxApiConfiguration config = new BcxApiConfiguration();//This will load settings. These settings will be used in HMAC
BcxBillingApi<BcxInvoiceFile> invoiceApi = new BcxBillingApi<BcxInvoiceFile>(config.Uri, config.AppId, config.ApiKey, organisationId);
BcxInvoiceFile result = await invoiceApi.GetByIdAsync(id);
//WRITE TO FILE
string path = @"C:\Temp\" + result.BlobFileName;
var fileStream = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite);
fileStream.Position = 0;
fileStream.CopyTo(result.BlobStream);
return new FileStreamResult(fileStream, "application/pdf");
}
在Web Api中下载Helper,
public BcxInvoiceFile DownloadBlob(string blobFileId)
{
var billingFileInstanceFileName = String.Empty;
string destFile;
// Retrieve storage account from connection string.
var storageAccount = CloudStorageAccount.Parse(StorageAccountConnectionString);
// Create the blob client.
var blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve Storage container.
var container = blobClient.GetContainerReference(StorageContainer);
// Create the container if it doesn't already exist.
container.CreateIfNotExists();
// Retrieve Blob Reference.
var blockBlob = container.GetBlockBlobReference(blobFileId);
string text;
var memoryStream = new MemoryStream();
blockBlob.DownloadToStream(memoryStream);
text = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
// Strip off any folder structure so the file name is just the file name
var lastPos = blockBlob.Name.LastIndexOf('/');
var fileName = blockBlob.Name.Substring(lastPos + 1, blockBlob.Name.Length - lastPos - 1);
// Build and return the download model with the blob stream and its relevant info
var download = new BcxInvoiceFile
{
BlobStream = memoryStream,
BlobFileName = fileName,
BlobLength = blockBlob.Properties.Length,
BlobContentType = blockBlob.Properties.ContentType
};
return download;
// return billingFileInstanceFileName;
}
文件下载的模型类,
public class BcxInvoiceFile
{
public MemoryStream BlobStream { get; set; }
public string BlobFileName { get; set; }
public string BlobContentType { get; set; }
public long BlobLength { get; set; }
}
答案 0 :(得分:0)
好吧,我做了一些关于流的实验,并找到了一个简单的解决方案。 解决方案:
只需将字节数组从Web Api传递到MVC控制器,然后从MVC控制器创建文件流。
来自Web Api控制器,
result.BlobStream.Position = 0;
return Request.CreateResponse(HttpStatusCode.OK, result.BlobStream.GetBuffer());
来自MVC控制器,(没有我正在使用的Api客户端的普通c#代码)
public async Task<FileStreamResult> DownloadInvoice()
{
string invoiceId = new Guid(); //Test data
var url = "http://localhost:7000/api/v1/downloadfile/<invoiceid goes here>";
string path = @"C:\Temp\" + invoiceId + ".pdf";
using (var client = new HttpClient())
{
var response = client.GetAsync(url).Result;
var stream = await response.Content.ReadAsAsync<Byte[]>();
System.IO.File.WriteAllBytes(path, stream);
var fileStream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
return new FileStreamResult(fileStream, "application/pdf");
}
}
如果有人遇到更好的方法,请告诉我。