How do I route images using ASP.Net MVC routing?

18,229

Solution 1

You can't do this "out of the box" with the MVC framework. Remember that there is a difference between Routing and URL-rewriting. Routing is mapping every request to a resource, and the expected resource is a piece of code.

However - the flexibility of the MVC framework allows you to do this with no real problem. By default, when you call routes.MapRoute(), it's handling the request with an instance of MvcRouteHandler(). You can build a custom handler to handle your image urls.

  1. Create a class, maybe called ImageRouteHandler, that implements IRouteHandler.

  2. Add the mapping to your app like this:

    routes.Add("ImagesRoute", new Route("graphics/{filename}",
    new ImageRouteHandler()));

  3. That's it.

Here's what your IRouteHandler class looks like:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Compilation;
using System.Web.Routing;
using System.Web.UI;

namespace MvcApplication1
{
    public class ImageRouteHandler : IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            string filename = requestContext.RouteData.Values["filename"] as string;

            if (string.IsNullOrEmpty(filename))
            {
                // return a 404 HttpHandler here
            }
            else
            {
                requestContext.HttpContext.Response.Clear();
                requestContext.HttpContext.Response.ContentType = GetContentType(requestContext.HttpContext.Request.Url.ToString());

                // find physical path to image here.  
                string filepath = requestContext.HttpContext.Server.MapPath("~/test.jpg");

                requestContext.HttpContext.Response.WriteFile(filepath);
                requestContext.HttpContext.Response.End();

            }
            return null;
        }

        private static string GetContentType(String path)
        {
            switch (Path.GetExtension(path))
            {
                case ".bmp": return "Image/bmp";
                case ".gif": return "Image/gif";
                case ".jpg": return "Image/jpeg";
                case ".png": return "Image/png";
                default: break;
            }
            return "";
        }
    }
}

Solution 2

If you were to do this using ASP.NET 3.5 Sp1 WebForms you would have to create a seperate ImageHTTPHandler that implements IHttpHandler to handle the response. Essentially all you would have to do is put the code that is currently in the GetHttpHandler method into your ImageHttpHandler's ProcessRequest method. I also would move the GetContentType method into the ImageHTTPHandler class. Also add a variable to hold the name of the file.

Then your ImageRouteHanlder class looks like:

public class ImageRouteHandler:IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            string filename = requestContext.RouteData.Values["filename"] as string;

            return new ImageHttpHandler(filename);

        }
    } 

and you ImageHttpHandler class would look like:

 public class ImageHttpHandler:IHttpHandler
    {
        private string _fileName;

        public ImageHttpHandler(string filename)
        {
            _fileName = filename;
        }

        #region IHttpHandler Members

        public bool IsReusable
        {
            get { throw new NotImplementedException(); }
        }

        public void ProcessRequest(HttpContext context)
        {
            if (string.IsNullOrEmpty(_fileName))
            {
                context.Response.Clear();
                context.Response.StatusCode = 404;
                context.Response.End();
            }
            else
            {
                context.Response.Clear();
                context.Response.ContentType = GetContentType(context.Request.Url.ToString());

                // find physical path to image here.  
                string filepath = context.Server.MapPath("~/images/" + _fileName);

                context.Response.WriteFile(filepath);
                context.Response.End();
            }

        }

        private static string GetContentType(String path)
        {
            switch (Path.GetExtension(path))
            {
                case ".bmp": return "Image/bmp";
                case ".gif": return "Image/gif";
                case ".jpg": return "Image/jpeg";
                case ".png": return "Image/png";
                default: break;
            }
            return "";
        }

        #endregion
    }
Share:
18,229
The Matt
Author by

The Matt

Open Source Projects: CruiseControlNET Plugin to publish build results to Amazon S3: http://code.google.com/p/ccnet-s3-publisher/

Updated on June 04, 2022

Comments

  • The Matt
    The Matt almost 2 years

    I upgraded my site to use ASP.Net MVC from traditional ASP.Net webforms. I'm using the MVC routing to redirect requests for old .aspx pages to their new Controller/Action equivalent:

            routes.MapRoute(
                "OldPage",
                "oldpage.aspx",
                new { controller = "NewController", action = "NewAction", id = "" }
            );
    

    This is working great for pages because they map directly to a controller and action. However, my problem is requests for images - I'm not sure how to redirect those incoming requests.

    I need to redirect incoming requests for http://www.domain.com/graphics/image.png to http://www.domain.com/content/images/image.png.

    What is the correct syntax when using the .MapRoute() method?

  • Kamarey
    Kamarey almost 15 years
    Can this work without Response.End method? Just think that throw an exception (from Response.End) on every image request is not the best way...
  • GibboK
    GibboK almost 13 years
    I read your article... good job. It works great and it is really easy to set up less that 15 minutes
  • SpaceBison
    SpaceBison over 12 years
    +1 from me - worked without very many tweaks and helped me round an issue I thought might take days...in just an hour.
  • Bibhu
    Bibhu over 11 years
    @womp - I am newbie to MVC, just wanted to clarify one thing, can't we ignore the .png files using IgnoreRoute(), so that the request is handled by ASP.NET routing engine, instead of handling the request and then routing to the files in the physical location.
  • jaminto
    jaminto over 9 years
    This didn't work for me with MVC 5 until i added a UrlRoutingHandler as seen here: stackoverflow.com/a/13082446/140449. It seems MVC didn't like the period in the filename until this UrlRoutingHandler was added.