It’s great that some of the innovations from ASP.NET MVC 1.0 were moved into the ASP.NET 4.0 platform. One of those was the RouteTable. I hadn’t written a custom RouteHandler before, so I thought I’d do a simple one as a demo for myself (and any others who are interested).
This is just an example of how to build one – it’s not secure.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Security; using System.Web.SessionState; using System.Web.Routing; using System.IO; namespace TestWebApplication1 { public class Global : System.Web.HttpApplication { void Application_Start(object sender, EventArgs e) { RouteTable.Routes.Add(new Route("Assets/{locale}/{assetID}", new CustomRouteHandler())); } } public class CustomRouteHandler : IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { return new SimpleFileHttpHandler(requestContext); } } public class SimpleFileHttpHandler : IHttpHandler { private RequestContext _requestContext; private HttpContext _httpContext; public RequestContext RequestContext { get; private set; } public SimpleFileHttpHandler(RequestContext requestContext) { _requestContext = requestContext; } public bool IsReusable { get { return false; } } public void ProcessRequest(HttpContext context) { _httpContext = context; string assetID = _requestContext.RouteData.Values["assetID"].ToString(); string locale = _requestContext.RouteData.Values["locale"].ToString(); if (string.IsNullOrWhiteSpace(assetID) || string.IsNullOrWhiteSpace(locale)) { throw new ArgumentException(); } // this is not adaquate and definitely not secure as it would allow any file to be selected and downloaded // needs to prevent any sort of hack attempts using encoded paths, etc. should just be a relative path within the // folder that contains the content and no more. string path = _httpContext.Request.MapPath("~/Content/" + assetID, "", false); if (File.Exists(path)) { // hard coded to the image/jpg type (obviously needs to adjust) context.Response.AddHeader("Content-Type", "image/jpg"); context.Response.AddHeader("Content-Length", new FileInfo(path).Length.ToString()); context.Response.WriteFile(path); } } } }
To use it, I created a folder called Content and copied one of the sample photos included with Windows into the folder, and then modified Default.aspx:
<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="TestWebApplication1._Default" %> <asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent"> </asp:Content> <asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent"> <h2> Welcome to the Route Table Demonstrator </h2> <h3>This one should work as it's using the not-so-magical route table and a custom iroutehandler.</h3> <p> <img src="/Assets/en-us/Penguins.jpg" width="320" height="200" /> </p> <p> <img src="/Assets/en-us/Penguins.jpg" width="320" height="200" /> </p> <h3>THis one shouldn't work due to security in web.config for the folder</h3> <p><img src="/Content/Penguins.jpg" /></p> <p> <img src="/Content/Penguins.jpg" /> </p> </asp:Content>
In the Content Folder, I added a web.config file to prevent direct access to the content within the folder:
<?xml version="1.0"?> <configuration> <system.web> <authorization> <deny users="*"/> </authorization> </system.web> <system.webServer> <modules runAllManagedModulesForAllRequests="true"/> </system.webServer> </configuration>
This should work without modification on IIS7+ and Visual Studio 2010.








