从ASP.NET Web API中的控制器返回二进制文件

天大地大妈咪最大 提交于 2020-03-20 20:07:11

3 月,跳不动了?>>>

我正在使用ASP.NET MVC的新WebAPI开发Web服务,该服务将提供二进制文件,主要是.cab.exe文件。

以下控制器方法似乎有效,这意味着它返回一个文件,但是将内容类型设置为application/json

public HttpResponseMessage<Stream> Post(string version, string environment, string filetype)
{
    var path = @"C:\Temp\test.exe";
    var stream = new FileStream(path, FileMode.Open);
    return new HttpResponseMessage<Stream>(stream, new MediaTypeHeaderValue("application/octet-stream"));
}

有一个更好的方法吗?


#1楼

你可以试试

httpResponseMessage.Content.Headers.Add("Content-Type", "application/octet-stream");

#2楼

对于Web API 2 ,可以实现IHttpActionResult 。 这是我的:

using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

class FileResult : IHttpActionResult
{
    private readonly string _filePath;
    private readonly string _contentType;

    public FileResult(string filePath, string contentType = null)
    {
        if (filePath == null) throw new ArgumentNullException("filePath");

        _filePath = filePath;
        _contentType = contentType;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StreamContent(File.OpenRead(_filePath))
        };

        var contentType = _contentType ?? MimeMapping.GetMimeMapping(Path.GetExtension(_filePath));
        response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);

        return Task.FromResult(response);
    }
}

然后在您的控制器中这样:

[Route("Images/{*imagePath}")]
public IHttpActionResult GetImage(string imagePath)
{
    var serverPath = Path.Combine(_rootPath, imagePath);
    var fileInfo = new FileInfo(serverPath);

    return !fileInfo.Exists
        ? (IHttpActionResult) NotFound()
        : new FileResult(fileInfo.FullName);
}

这是您可以告诉IIS忽略带有扩展名的请求的一种方法,以便该请求将其发送到控制器:

<!-- web.config -->
<system.webServer>
  <modules runAllManagedModulesForAllRequests="true"/>

#3楼

虽然建议的解决方案可以正常工作,但是还有另一种方法可以从控制器返回字节数组,并且响应流的格式正确:

  • 在请求中,设置标题“接受:应用程序/八位字节流”。
  • 在服务器端,添加媒体类型格式化程序以支持此mime类型。

不幸的是,WebApi不包括“应用程序/八位字节流”的任何格式化程序。 在GitHub上有一个实现: BinaryMediaTypeFormatter (有一些小的改动以使其适用于webapi 2,更改了方法签名)。

您可以将此格式化程序添加到全局配置中:

HttpConfiguration config;
// ...
config.Formatters.Add(new BinaryMediaTypeFormatter(false));

如果请求指定了正确的Accept标头,则WebApi现在应该使用BinaryMediaTypeFormatter

我更喜欢这种解决方案,因为操作控制器返回byte []更易于测试。 但是,如果您要返回除“ application / octet-stream”(例如“ image / gif”)之外的其他内容类型,则另一种解决方案使您可以更好地控制。


#4楼

对于使用接受的答案中的方法下载相当大的文件时多次调用API的问题的人,请将响应缓冲设置为true System.Web.HttpContext.Current.Response.Buffer = true;

这样可以确保在将整个二进制内容发送到客户端之前,先在服务器端对其进行缓冲。 否则,您将看到多个请求被发送到控制器,如果处理不当,文件将损坏。


#5楼

对于使用.NET Core的用户:

您可以在API控制器方法中使用IActionResult接口,如下所示:

    [HttpGet("GetReportData/{year}")]
    public async Task<IActionResult> GetReportData(int year)
    {
        // Render Excel document in memory and return as Byte[]
        Byte[] file = await this._reportDao.RenderReportAsExcel(year);

        return File(file, "application/vnd.openxmlformats", "fileName.xlsx");
    }

此示例已简化,但应该理解这一点。 在.NET核心这个过程是如此比在.NET之前的版本更加简单-即没有设置响应类型,内容,标题等。

另外,当然,文件和扩展名的MIME类型将取决于个人需求。

参考: SO发帖人@NKosi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!