Returning binary file from controller in ASP.NET Web API

后端 未结 8 782
离开以前
离开以前 2020-11-22 02:55

I\'m working on a web service using ASP.NET MVC\'s new WebAPI that will serve up binary files, mostly .cab and .exe files.

The following co

相关标签:
8条回答
  • 2020-11-22 03:33

    For anyone having the problem of the API being called more than once while downloading a fairly large file using the method in the accepted answer, please set response buffering to true System.Web.HttpContext.Current.Response.Buffer = true;

    This makes sure that the entire binary content is buffered on the server side before it is sent to the client. Otherwise you will see multiple request being sent to the controller and if you do not handle it properly, the file will become corrupt.

    0 讨论(0)
  • 2020-11-22 03:34

    You can try the following code snippet

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

    Hope it will work for you.

    0 讨论(0)
  • 2020-11-22 03:45

    You could try

    httpResponseMessage.Content.Headers.Add("Content-Type", "application/octet-stream");
    
    0 讨论(0)
  • 2020-11-22 03:46

    For Web API 2, you can implement IHttpActionResult. Here's mine:

    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);
        }
    }
    

    Then something like this in your controller:

    [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);
    }
    

    And here's one way you can tell IIS to ignore requests with an extension so that the request will make it to the controller:

    <!-- web.config -->
    <system.webServer>
      <modules runAllManagedModulesForAllRequests="true"/>
    
    0 讨论(0)
  • 2020-11-22 03:46

    While the suggested solution works fine, there is another way to return a byte array from the controller, with response stream properly formatted :

    • In the request, set header "Accept: application/octet-stream".
    • Server-side, add a media type formatter to support this mime type.

    Unfortunately, WebApi does not include any formatter for "application/octet-stream". There is an implementation here on GitHub: BinaryMediaTypeFormatter (there are minor adaptations to make it work for webapi 2, method signatures changed).

    You can add this formatter into your global config :

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

    WebApi should now use BinaryMediaTypeFormatter if the request specifies the correct Accept header.

    I prefer this solution because an action controller returning byte[] is more comfortable to test. Though, the other solution allows you more control if you want to return another content-type than "application/octet-stream" (for example "image/gif").

    0 讨论(0)
  • 2020-11-22 03:48

    For those using .NET Core:

    You can make use of the IActionResult interface in an API controller method, like so...

        [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");
        }
    

    This example is simplified, but should get the point across. In .NET Core this process is so much simpler than in previous versions of .NET - i.e. no setting response type, content, headers, etc.

    Also, of course the MIME type for the file and the extension will depend on individual needs.

    Reference: SO Post Answer by @NKosi

    0 讨论(0)
提交回复
热议问题