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:\Temp\test.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?
While the suggested solution works fine, there is another way to return a byte array from the controller, with response stream properly formatted :
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 :
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").
For Web API 2, you can implement
IHttpActionResult
. Here's mine:Then something like this in your controller:
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:
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.
Try using a simple
HttpResponseMessage
with itsContent
property set to aStreamContent
: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'sresult
to send data back to the client. Therefore, do not use ausing (var stream = …)
block. Web API will dispose the stream for you.Make sure that the stream has its current position set to 0 (i.e. 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 tostream.Seek(0, SeekOrigin.Begin);
or setstream.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.You could try
The overload that you're using sets the enumeration of serialization formatters. You need to specify the content type explicitly like: