We have a web site based on MonoRail with some aspx pages. This article is about using ASP.NET routing to redirect all urls of the form /controller to /controller/index.castle.
1. IIS configuration.
IIS will not let you route urls that aren’t mapped to a handler, so we need to use a wildcard handler.
However, we don’t want to use a handler for static content, e.g. images.
- Use adsutil.vbs to add the wildcard “*,…/aspnet_isapi.dll,0,All” to the ScriptMaps for your site.
Presumably you are setting the ScriptMaps anyway to map the .castle extension to aspnet_isapi.dll.
However, it is important that the flags be 0 for the wildcard. - Then use adsutil.vbs to set /…/dir/ScriptMaps to the empty string, where dir is an IIsWebDirectory that exists in your site and contains static content.
2. For the routing, you will need the assemblies System.Web.Routing and System.Web.Abstractions from the directory Program Files/Reference Assemblies/Microsoft/Framework/v3.5
a. In your web.config, add the following at the top of the httpHandlers section:
add name=”urlRoutingModule” type=”System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35″
b. Add the following to the top of your Global.asax
<%@ Import Namespace="System.Web.Routing" %>
c. Add the routes to your Global.asax.cs file as follows:
protected void Application_Start(object sender, EventArgs e)
{
…
RegisterRoutes(RouteTable.Routes);
}
private static void RegisterRoutes(RouteCollection routes)
{
routes.Add(new Route(”{prefix}/{*rest}”, new MyRouteHandler()));
}
d. Create the class MyRouteHandler as follows:
public class MyRouteHandler : MonoRailHttpHandlerFactory, IRouteHandler
{
private const string RailsContextKey = “rails.context”;
private const string IsMonorailRequestKey = “is.mr.request”;
public IHttpHandler GetHttpHandler(RequestContext context)
{
string path = RouteTable.Routes.GetVirtualPath(context, new RouteValueDictionary {}).VirtualPath;
string last = path.Split(’/').Last();
HttpContext httpContext = HttpContext.Current;
if(!last.Contains(”.”))
{
path = string.Format(”{0}/index.castle”, path);
httpContext.RewritePath(path);
Initialize(httpContext.ApplicationInstance);
}
if(path.EndsWith(”.castle”))
{
return GetHandler(httpContext, httpContext.Request.RequestType, httpContext.Request.RawUrl,
httpContext.Request.PhysicalApplicationPath);
}
return (IHttpHandler) BuildManager.CreateInstanceFromVirtualPath(path, typeof (Page));
}
private static void Initialize(HttpApplication app)
{
// Create the IRailsEngineContext
HttpContext context = app.Context;
IServiceContainer container = ServiceContainerAccessor.ServiceContainer;
IUrlTokenizer urlTokenizer = (IUrlTokenizer)container.GetService(typeof(IUrlTokenizer));
HttpRequest request = context.Request;
UrlInfo urlInfo = urlTokenizer.TokenizeUrl(request.FilePath, request.Url, request.IsLocal, request.ApplicationPath);
IServiceProvider userServiceProvider = ServiceProviderLocator.Instance.LocateProvider();
DefaultRailsEngineContext newContext = new DefaultRailsEngineContext(ServiceContainerAccessor.ServiceContainer, urlInfo, context, userServiceProvider);
context.Items[RailsContextKey] = newContext;
context.Items[IsMonorailRequestKey] = true;
newContext.AddService(typeof (IRailsEngineContext), newContext);
// Create the controller
UrlInfo info = newContext.UrlInfo;
IControllerFactory controllerFactory = (IControllerFactory)newContext.GetService(typeof(IControllerFactory));
Controller controller = controllerFactory.CreateController(info);
// Create the executor
IControllerLifecycleExecutorFactory factory =
(IControllerLifecycleExecutorFactory)newContext.GetService(typeof(IControllerLifecycleExecutorFactory));
IControllerLifecycleExecutor executor = factory.CreateExecutor(controller, newContext);
context.Items[ControllerLifecycleExecutor.ExecutorEntry] = executor;
// Initialize
executor.InitializeController(info.Area, info.Controller, info.Action);
// Validate
if (!executor.SelectAction(info.Action, info.Controller))
{
return;
}
if (!executor.RunStartRequestFilters())
{
newContext.UnderlyingContext.Response.End();
executor.Dispose();
}
}
}
At this point, you’re done.