Returning binary file from controller in ASP.NET Web API

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 controller method seems to work, meaning that it returns a file, but it's setting the content type to application/json :

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

Is there a better way to do this?


Try using a simple HttpResponseMessage with its Content property set to a StreamContent :

// using System.IO;
// using System.Net.Http;
// using System.Net.Http.Headers;

public HttpResponseMessage Post(string version, string environment,
    string filetype)
{
    var path = @"C:Temptest.exe";
    HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
    var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
    result.Content = new StreamContent(stream);
    result.Content.Headers.ContentType = 
        new MediaTypeHeaderValue("application/octet-stream");
    return result;
}

A few things to note about the stream used:

  • You must not call stream.Dispose() , since Web API still needs to be able to access it when it processes the controller method's result to send data back to the client. Therefore, do not use a using (var stream = …) block. Web API will dispose the stream for you.

  • Make sure that the stream has its current position set to 0 (ie the beginning of the stream's data). In the above example, this is a given since you've only just opened the file. However, in other scenarios (such as when you first write some binary data to a MemoryStream ), make sure to stream.Seek(0, SeekOrigin.Begin); or set stream.Position = 0;

  • With file streams, explicitly specifying FileAccess.Read permission can help prevent access rights issues on web servers; IIS application pool accounts are often given only read / list / execute access rights to the wwwroot.


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

    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"/>
    

    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 works 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").

    链接地址: http://www.djcxy.com/p/65896.html

    上一篇: ASP.NET Web API中的可选参数

    下一篇: 在ASP.NET Web API中从控制器返回二进制文件