30

I want to try to use Web API make a rest call but I want the response to be the actual binary image stored in a database, not a JSON base64 encoded string. Anyone got some pointers on this?

Update- This is what I ended up implementing:

 HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
 result.Content = new StreamContent(new MemoryStream(profile.Avatar));
 result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
 result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
 result.Content.Headers.ContentDisposition.FileName = "avatar.png";
 return result;
1

4 Answers 4

30

You can set the response content to a StreamContent object:

        var fileStream = new FileStream(path, FileMode.Open);

        var resp = new HttpResponseMessage()
        {
            Content = new StreamContent(fileStream)
        };

        // Find the MIME type
        string mimeType = _extensions[Path.GetExtension(path)];
        resp.Content.Headers.ContentType = new MediaTypeHeaderValue(mimeType);
Sign up to request clarification or add additional context in comments.

3 Comments

Marked your's as the answer because it was a direct response to the question and was closest to what I needed. Thanks for taking the time to answer!
For solution on how to return a file from the Web API, take a look at the very end of his own answer at stackoverflow.com/a/14819168/179138
How did you solve it, that the filestreim is closed after the request has finished
18

While this has been marked as answered, it wasn't quite what I wanted, so I kept looking. Now that I've figured it out, here's what I've got:

public FileContentResult GetFile(string id)
{
    byte[] fileContents;
    using (MemoryStream memoryStream = new MemoryStream())
    {
        using (Bitmap image = new Bitmap(WebRequest.Create(myURL).GetResponse().GetResponseStream()))
            image.Save(memoryStream, ImageFormat.Jpeg);
        fileContents = memoryStream.ToArray();
    }
    return new FileContentResult(fileContents, "image/jpg");
}

Granted, that's for getting an image through a URL. If you just want to grab an image off the file server, I'd imagine you replace this line:

using (Bitmap image = new Bitmap(WebRequest.Create(myURL).GetResponse().GetResponseStream()))

With this:

using (Bitmap image = new Bitmap(myFilePath))

EDIT: Never mind, this is for regular MVC. for Web API, I have this:

public HttpResponseMessage Get(string id)
{
    string fileName = string.Format("{0}.jpg", id);
    if (!FileProvider.Exists(fileName))
        throw new HttpResponseException(HttpStatusCode.NotFound);

    FileStream fileStream = FileProvider.Open(fileName);
    HttpResponseMessage response = new HttpResponseMessage { Content = new StreamContent(fileStream) };
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpg");
    response.Content.Headers.ContentLength = FileProvider.GetLength(fileName);
    return response;
}

Which is quite similar to what OP has.

2 Comments

In my case, I needed the Web API version.
What about the FileStream object... does anyone know if the Dispose() default method on the httpResponseMessage will properly destroy the Stream? Our security scanning is highlighting this as an unresolved potential resource leak.
2

I did this exact thing. Here is my code:

if (!String.IsNullOrWhiteSpace(imageName))
                {
                    var savedFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Path.Combine(uploadPath, imageName));
                    var image = System.Drawing.Image.FromFile(savedFileName);

                    if (ImageFormat.Jpeg.Equals(image.RawFormat))
                    {
                        // JPEG
                        using(var memoryStream = new MemoryStream())
                        {
                            image.Save(memoryStream, ImageFormat.Jpeg);

                            var result = new HttpResponseMessage(HttpStatusCode.OK)
                                {
                                    Content = new ByteArrayContent(memoryStream.ToArray())
                                };

                            result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
                            result.Content.Headers.ContentLength = memoryStream.Length;

                            return result;
                        }
                    }
                    else if (ImageFormat.Png.Equals(image.RawFormat))
                    {
                        // PNG
                        using (var memoryStream = new MemoryStream())
                        {
                            image.Save(memoryStream, ImageFormat.Png);

                            var result = new HttpResponseMessage(HttpStatusCode.OK)
                            {
                                Content = new ByteArrayContent(memoryStream.ToArray())
                            };

                            result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
                            result.Content.Headers.ContentLength = memoryStream.Length;

                            return result;
                        }
                    }
                    else if (ImageFormat.Gif.Equals(image.RawFormat))
                    {
                        // GIF
                        using (var memoryStream = new MemoryStream())
                        {
                            image.Save(memoryStream, ImageFormat.Gif);

                            var result = new HttpResponseMessage(HttpStatusCode.OK)
                            {
                                Content = new ByteArrayContent(memoryStream.ToArray())
                            };

                            result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/gif");
                            result.Content.Headers.ContentLength = memoryStream.Length;

                            return result;
                        }
                    }
                }

And then on the client:

                    var client = new HttpClient();
                    var imageName = product.ImageUrl.Replace("~/Uploads/", "");
                var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
                                        Properties.Settings.Default.DeviceMediaPath + "\\" + imageName);

                var response =
                    client.GetAsync(apiUrl + "/Image?apiLoginId=" + apiLoginId + "&authorizationToken=" + authToken +
                                    "&imageName=" + product.ImageUrl.Replace("~/Uploads/","")).Result;

                if (response.IsSuccessStatusCode)
                {
                    var data = response.Content.ReadAsByteArrayAsync().Result;
                    using (var ms = new MemoryStream(data))
                    {
                        using (var fs = File.Create(path))
                        {
                            ms.CopyTo(fs);
                        }
                    }

                    result = true;
                }
                else
                {
                    result = false;
                    break;
                }

Comments

0

This task is much easily achieved without using WebAPI. I would implement a custom HTTP handler for a unique extension, and return the binary response there. The plus is that you can also modify the HTTP Response headers and content type, so you have absolute control over what is returned.

You can devise a URL pattern (defining how you know what image to return based on its URL), and keep those URLs in your API resources. Once the URL is returned in the API response, it can be directly requested by the browser, and will reach your HTTP handler, returning the correct image.

Images are static content and have their own role in HTTP and HTML - no need to mix them with the JSON that is used when working with an API.

4 Comments

I think OP want to know how to do this with webapi instead of how to avoid webapi.
Correct, I'm aware of the HTTP Handler route and considered it but didn't want my code split up like that. Thanks for taking time to respond though.
Well, just my two cents. I've always found it easier with HTTP handlers.
Performance would be a factor too. Not sure of Handlers vs Web API, but if you're using a Http Module to perform a URL rewrite to a static file in IIS you'll get the performance benefits of the IIS static file handler.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.