Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web Api 2 or Generic Handler to serve images?

I want to create an image handler, but i am torn between using Web API 2 or just a normal Generic Handler (ashx)

I have implemented both in the past, but which one is the most correct one. I found an old SO post LINK but is it still really relevant?

like image 659
R4nc1d Avatar asked Jun 17 '15 13:06

R4nc1d


3 Answers

WebApi is fully capable and I prefer it. The other answer is right that JSON and XML are default, but you can add your own MediaFormatter and serve any content type for any model. This allows you to perform content negotiation and provide different content based on the Accept header or file extension. Let's pretend our model is a "User". Imagine asking for a "User" as json, xml, jpg, pdf. With WebApi, we can use file extensions or the Accept header and ask for /Users/1 or Users/1.json for JSON, Users/1.jpg for jpg, Users/1.xml for xml, /Users/1.pdf for pdf, etc. All of these could also just be /Users/1 with different Accept headers with quality so your clients could ask for Users/1 with an Accept header asking for jpg first, but fall back to png.

Here is an example of how to create a formatter for .jpg.

public class JpegFormatter : MediaTypeFormatter
{
    public JpegFormatter()
    {
        //this allows a route with extensions like /Users/1.jpg
        this.AddUriPathExtensionMapping(".jpg", "image/jpeg");

        //this allows a normal route like /Users/1 and an Accept header of image/jpeg
        this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/jpeg"));
    }

    public override bool CanReadType(Type type)
    {
        //Can this formatter read binary jpg data?
        //answer true or false here
        return false;
    }

    public override bool CanWriteType(Type type)
    {
        //Can this formatter write jpg binary if for the given type?
        //Check the type and answer. You could use the same formatter for many different types.
        return type == typeof(User);
    }

    public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content,
        TransportContext transportContext)
    {
        //value will be whatever model was returned from your controller
        //you may need to check data here to know what jpg to get

        var user = value as User;
        if (null == user)
        {
            throw new NotFoundException();
        }

        var stream = SomeMethodToGetYourStream(user);

        await stream.CopyToAsync(writeStream);
    }
}

Now we need to register our formatter (typically App_Start/WebApiConfig.cs)

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        ...

        //typical route configs to allow file extensions
        config.Routes.MapHttpRoute("ext", "{controller}/{id}.{ext}");
        config.Routes.MapHttpRoute("default", "{controller}/{id}", new { id = RouteParameter.Optional });

        //remove any default formatters such as xml
        config.Formatters.Clear();

        //order of formatters matter!
        //let's put JSON in as the default first
        config.Formatters.Add(new JsonMediaTypeFormatter());

        //now we add our custom formatter
        config.Formatters.Add(new JpegFormatter());
    }
}

And finally, our controller

public class UsersController : ApiController
{
    public IHttpActionResult Get(int id)
    {
        var user = SomeMethodToGetUsersById(id);

        return this.Ok(user);
    }
}

Your controller will not have to change as you add different formatters. It simply returns your model and then formatters kick in later in the pipeline. I love formatters as it provides such a rich api. You can read more about formatters on the WebApi website.

like image 180
ManOVision Avatar answered Oct 29 '22 11:10

ManOVision


The correct one is ashx the reason is the content type. If you use Web Api the content type a.k.a media formatter(format) of your response is the one defined for all your services meaning JSON, XML or oData.

//Global Asax, Web Api register methods is used to defined WebApi formatters

config.Formatters.Insert(0, new System.Net.Http.Formatting.JsonMediaTypeFormatter());

However an image is a binary therefore you need to send the image in its original format and not as JSON or XML

response.AddHeader("content-type", "image/png");

 response.BinaryWrite(imageContent);
 response.Flush();

That is why the ashx is the right tool for that job.

One additional advantage is that you have more control over your output without the need to code a new "formatter"(the way to make WebApi to resolve this issue) for each image type that you want to return by doing something like in Ashx file:

var png = Image.FromFile("some.png");
png.Save("a.gif", var png = Image.FromFile("some.png");
png.Save("a.gif", ImageFormat.Gif); //Note you can save the new image into a MemoryStream to return it later in the same method.

And you have wide variety of types to play with:

https://msdn.microsoft.com/en-us/library/system.drawing.imaging.imageformat(v=vs.110).aspx

Important: It is clear for all of us that both WebApi and Ashx can return images. I am not saying in any way that you can't achieve this with WebApi all I am saying is why I believe Ashx is the right choice.

like image 20
Dalorzo Avatar answered Oct 29 '22 13:10

Dalorzo


I am a big fan of flexibility and customization. I personally would go for httpHandler. So to answer your question, it really depends on your requirements.

First thing WebAPI is the result of evolution all the way from http (GET/POST) calls to web services and the need of being able to transfer data in less cost as opposed to web services. HttpHandlers utilized same concept long time before web apis. Basically web apis are nothing but a http page without its user interface (if you want to).

Few things need to know before choosing HttpHandler or Web Api

  1. development time - whether you know both very well and what will take less time for you to implement
  2. As ManOVision mentioned in his answer, the routing user/1 you can still implement with simple code and httphandler so you don't really need Web API for that. only you may have to right the code manually adding up a little time in development
  3. Flexibility, I personally like this part since I will be able to control the response content type as I want depending upon the data user provides. I don't need to perform session checks and redirect to any page. I can still control this behavior to whatever I want. web API also you can do but mostly things are taken at run time by itself to the configuration we put in place at the development.
  4. rendering web page is the same for both. Although httphandler being easy so why to use Web API?

There might more comparison (As a manager I think from management side as well and not completely technical perspective) so you may have to weigh your options and decide what to do. Since handler file is anyway foundation of web API, I would say it gives more power to developer than web api does. just like a http socket would do more than httphandler.

like image 20
Rahul Avatar answered Oct 29 '22 12:10

Rahul