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;
spaceagestereo
  • 554
  • 1
  • 8
  • 19
  • I think this article asks a similar question http://stackoverflow.com/questions/8340247/returning-an-image-from-a-restful-wcf-service – Glenn Ferrie May 08 '12 at 02:46

4 Answers4

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);
Mike Wasson
  • 6,572
  • 2
  • 24
  • 20
  • 2
    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! – spaceagestereo Jun 26 '12 at 01:13
  • For solution on how to return a file from the Web API, take a look at the very end of his own answer at http://stackoverflow.com/a/14819168/179138 – Caio Cunha Jan 17 '14 at 02:40
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.

vbullinger
  • 4,016
  • 3
  • 27
  • 32
  • In my case, I needed the Web API version. – Caio Cunha Jan 17 '14 at 02:39
  • 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. – jessewolfe May 03 '16 at 23:02
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;
                }
Serj-Tm
  • 16,581
  • 4
  • 54
  • 61
aBetterGamer
  • 5,119
  • 2
  • 18
  • 19
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.

Community
  • 1
  • 1
Slavo
  • 15,255
  • 11
  • 47
  • 60
  • 12
    I think OP want to know how to do this **with webapi** instead of how to avoid webapi. – EBarr May 09 '12 at 01:52
  • 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. – spaceagestereo May 10 '12 at 02:27
  • Well, just my two cents. I've always found it easier with HTTP handlers. – Slavo May 10 '12 at 14:44
  • 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. – Snixtor Nov 27 '12 at 05:18