46

Questions

  1. What are the different ways to POST/GET images to my service? I think I can either use Base-64 text in JSON or stay native as binary. My understanding is that by converting the image into text, there is a significant increase is package size.

  2. If I send the image (from a web form, from a native client, from another service), should I add a Image Controller/Handler or use a Formatter? Is this even an either/or question?

I have researched and found many competing examples but I am not sure which direction I should be heading.

Is there a site/blog article that lays out the pros and cons for this?

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
Jamie Dixon
  • 4,204
  • 4
  • 25
  • 47
  • I think all of the approaches you've outlined are valid, but as your question stands, it's too open-ended. The approach you want will depend, at least, on what kinds of clients you support (form POSTs and AJAX clients will limit formats, support for compression, etc.) as well as what you want to do with the images on the server. I think you'll only want a MediaTypeFormatter if you actually want to load and manipulate them in your Web API methods, for example, and even then, you shouldn't *need* one. If all you want to do is save them to file, you definitely don't need one. – anton.burger Sep 27 '13 at 08:55
  • 1
    TL;DR I think you should narrow down your requirements to make the question more answerable. As it is, it's either going to languish unanswered or get put on hold as too broad or subjective. – anton.burger Sep 27 '13 at 08:56

2 Answers2

29

I did some research and you can see the implementation I came up with here: http://jamessdixon.wordpress.com/2013/10/01/handling-images-in-webapi/

Jamie Dixon
  • 4,204
  • 4
  • 25
  • 47
  • Jamie, can you fix the link? – Konstantin Chernov Jul 23 '15 at 16:49
  • Great link, I look forward to seeing the azure storage implementation. – Zapnologica Nov 08 '15 at 19:30
  • 1
    The code has a mistake, this code would not allow two images to be read at the same time. It should be something like this: FileStream s2 = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.Read); – ganjan Feb 24 '16 at 14:09
  • 11
    This answer is useless once the link is down. – Kai Hartmann Apr 30 '16 at 07:51
  • Firstly, you are a lifesaver. I got this to work with no issues whatsoever. Just one thing, don't forget to close your FileStream. The second time the file is requested, it will not come through as it is being used by a "process". Other than that, great post. – codeshinobi Jul 07 '16 at 07:38
  • What if I want to return a list of objects (Person) with the images? – Nick Nov 07 '19 at 17:40
29

For preservation's sake - here's the outline of what Jamie's blog said:

Use a Controller:

Get:

public HttpResponseMessage Get(int id)
{
    var result = new HttpResponseMessage(HttpStatusCode.OK);
    String filePath = HostingEnvironment.MapPath("~/Images/HT.jpg");
    FileStream fileStream = new FileStream(filePath, FileMode.Open);
    Image image = Image.FromStream(fileStream);
    MemoryStream memoryStream = new MemoryStream();
    image.Save(memoryStream, ImageFormat.Jpeg);
    result.Content = new ByteArrayContent(memoryStream.ToArray());
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");

    return result;
}

Delete:

public void Delete(int id)
{
    String filePath = HostingEnvironment.MapPath("~/Images/HT.jpg");
    File.Delete(filePath);
}

Post:

public HttpResponseMessage Post()
{
    var result = new HttpResponseMessage(HttpStatusCode.OK);
    if (Request.Content.IsMimeMultipartContent())
    {
        //For larger files, this might need to be added:
        //Request.Content.LoadIntoBufferAsync().Wait();
        Request.Content.ReadAsMultipartAsync<MultipartMemoryStreamProvider>(
                new MultipartMemoryStreamProvider()).ContinueWith((task) =>
        {
            MultipartMemoryStreamProvider provider = task.Result;
            foreach (HttpContent content in provider.Contents)
            {
                Stream stream = content.ReadAsStreamAsync().Result;
                Image image = Image.FromStream(stream);
                var testName = content.Headers.ContentDisposition.Name;
                String filePath = HostingEnvironment.MapPath("~/Images/");
                //Note that the ID is pushed to the request header,
                //not the content header:
                String[] headerValues = (String[])Request.Headers.GetValues("UniqueId");
                String fileName = headerValues[0] + ".jpg";
                String fullPath = Path.Combine(filePath, fileName);
                image.Save(fullPath);
            }
        });
        return result;
    }
    else
    {
        throw new HttpResponseException(Request.CreateResponse(
                HttpStatusCode.NotAcceptable,
                "This request is not properly formatted"));
    } 
}
Aske B.
  • 6,419
  • 8
  • 35
  • 62