我正在尝试从ASP.NET Web API方法返回Excel文件。我正在使用Web API作为我的ASP.NET Web表单应用程序的一部分。实际上,Web API方法可能会返回其他文件类型,但我现在正在尝试使用Excel文件进行稳定。
我能够跨用户代理访问ASP.NET Web API,但由于某种原因,我无法弄清楚如何让Web API成功将Excel文件返回给所有用户代理。出于某种原因,只有IE似乎能够解释HTTP响应并提供给定的请求的Excel文件。 Fiddler解释HTTP响应并识别出也返回了二进制文件。目前的代码如下:
public class FilesController : ApiController
{
public HttpResponseMessage GetExcelFile(int id)
{
ExcelFile excelFile = new ExcelService().GetExcelFile(id);
HttpResponseMessage result;
if (excelFile == null)
{
result = new HttpResponseMessage(HttpStatusCode.NotFound);
return result;
}
FileInfo fi = new FileInfo(
string.Format("{0}/{1}/{2}",
System.Web.Hosting.HostingEnvironment.MapPath("~/"),
new ConfigUtilities().GetTemplateReportFilesRootPath(),
excelFile.Name));
if (!fi.Exists)
{
result = new HttpResponseMessage(HttpStatusCode.NotFound);
return result;
}
long length = fi.Length;
result = new HttpResponseMessage();
result.StatusCode = HttpStatusCode.OK;
var stream = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read);
MemoryStream memStream = new MemoryStream();
stream.CopyTo(memStream);
result.Content = new ByteArrayContent(memStream.ToArray());// new StreamContent(stream);
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/vnd.ms-excel.sheet.macroEnabled.12");
result.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName =
String.Format(@"{0}", excelFile.DisplayName.Replace(@"""", "-"))
};
result.Content.Headers.ContentLength = length;
return result;
}
}
最初流式传输文件的源代码如下所示,但是我已经修改了几十次,几乎没有尝试返回文件的试错,所以它现在看起来像第一个代码块:
result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName =
String.Format(@"{0}", excelFile.DisplayName.Replace(@"""", "-")),
Size = fi.Length
};
result.Content.Headers.ContentLength = fi.Length;
return result;
IE识别HTTP响应中的文件。 Chrome和FireFox虽然都有不同的反应。 Chrome如下:
FireFox如下:
我已经阅读了所有的stackoverflow线程和谷歌我能做的一切,但我似乎无法解决这个问题。我只是尝试从标准HTTP GET请求访问WebAPI,以便我可以通过网页上的标准HTTP超链接标记来提供文件。
Fiddler展示了以下内容:
以下是原始视图:
答案 0 :(得分:2)
这是一个官方示例,用于显示正确的文件下载。您可以找到完整的示例here。
行动结果:
public class OkFileDownloadResult : IHttpActionResult
{
private readonly ApiController _controller;
public OkFileDownloadResult(string localPath, string contentType, string downloadFileName,
ApiController controller)
{
if (localPath == null)
{
throw new ArgumentNullException("localPath");
}
if (contentType == null)
{
throw new ArgumentNullException("contentType");
}
if (downloadFileName == null)
{
throw new ArgumentNullException("downloadFileName");
}
if (controller == null)
{
throw new ArgumentNullException("controller");
}
LocalPath = localPath;
ContentType = contentType;
DownloadFileName = downloadFileName;
_controller = controller;
}
public string LocalPath { get; private set; }
public string ContentType { get; private set; }
public string DownloadFileName { get; private set; }
public HttpRequestMessage Request
{
get { return _controller.Request; }
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Execute());
}
private HttpResponseMessage Execute()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(File.OpenRead(MapPath(LocalPath)));
response.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(ContentType);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = DownloadFileName
};
return response;
}
private static string MapPath(string path)
{
// The following code is for demonstration purposes only and is not fully robust for production usage.
// HttpContext.Current is not always available after asynchronous calls complete.
// Also, this call is host-specific and will need to be modified for other hosts such as OWIN.
return HttpContext.Current.Server.MapPath(path);
}
}
ApiController的扩展方法
public static OkFileDownloadResult Download(this ApiController controller, string path, string contentType)
{
string downloadFileName = Path.GetFileName(path);
return Download(controller, path, contentType, downloadFileName);
}
public static OkFileDownloadResult Download(this ApiController controller, string path, string contentType, string downloadFileName)
{
if (controller == null)
{
throw new ArgumentNullException("controller");
}
return new OkFileDownloadResult(path, contentType, downloadFileName, controller);
}
在控制器中使用模式:
[Route("file")]
public OkFileDownloadResult GetFile()
{
return this.Download("Download.xml", "application/xml");
}