C# – Castle MonoRail Routing with IIS 7

asp.net-mvcccastle-monorailmodel-view-controllernet

I’m trying to make the routing module works with default action or controller, but it doesn’t. I always face with 404 page not found. Did I forget to do something? I really like routing in ASP.NET MVC feature, but I’m not sure I could do the same in MR. I’m using IIS7 with the build from castle trunk for .NET 3.5.

Best Answer

If you're on IIS7, you need the routing module registration in the system.webServer/httpModules node.

The system.web/httpHandlers and httpModules are AFAIK ignored by IIS7.

MonoRail routing definitely works; we have it up and running happily. Here're config and global.asax.cs snippets:

    <system.web>
    <authentication mode="None" />

    <compilation debug="true" />

    <!-- IIS6 / integrated dev server handler/module config -->
    <httpHandlers>
        <clear />
        <add path="favicon.ico" verb="*" type="System.Web.StaticFileHandler"/>
        <add path="Trace.axd" verb="*" type="System.Web.Handlers.TraceHandler"/>
        <add path="*.config" verb="*" type="System.Web.HttpForbiddenHandler" />
        <add path="*.spark" verb="*" type="System.Web.HttpForbiddenHandler" />
        <add path="*.sparkjs" verb="*" type="System.Web.HttpForbiddenHandler" />
        <add path="/content/**/*.*" verb="*" type="System.Web.StaticFileHandler" />
  <add path="/content/**/**/*.*" verb="*" type="System.Web.StaticFileHandler" />
  <add path="/content/**/**/**/*.*" verb="*" type="System.Web.StaticFileHandler" />
  <add path="/content/**/**/**/**/*.*" verb="*" type="System.Web.StaticFileHandler" />
  <add path="*" verb="*" type="Castle.MonoRail.Framework.MonoRailHttpHandlerFactory, Castle.MonoRail.Framework" />
        <add verb="*" path="*.castle" type="Castle.MonoRail.Framework.MonoRailHttpHandlerFactory, Castle.MonoRail.Framework"/>
    </httpHandlers>

    <httpModules>
        <add name="routing" type="Castle.MonoRail.Framework.Routing.RoutingModuleEx, Castle.MonoRail.Framework" />
        <add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.MicroKernel" />
    </httpModules>

    <trace enabled="true"/>

</system.web>

<!-- IIS 7 handler/module config -->
<system.webServer>
    <handlers>
        <clear />
        <add name="FavIcon" path="favicon.ico" verb="*" type="System.Web.StaticFileHandler"/>
        <add name="Trace" path="Trace.axd" verb="*" preCondition="integratedMode" type="System.Web.Handlers.TraceHandler"/>
        <add name="BlockConfig" path="*.config" verb="*" preCondition="integratedMode" type="System.Web.HttpForbiddenHandler" />
        <add name="BlockSpark" path="*.spark" verb="*" preCondition="integratedMode" type="System.Web.HttpForbiddenHandler" />
        <add name="BlockSparkJs" path="*.sparkjs" verb="*" preCondition="integratedMode" type="System.Web.HttpForbiddenHandler" />
        <add name="content" path="/content/**/*.*" verb="*" preCondition="integratedMode" type="System.Web.StaticFileHandler" />
        <add name="content2" path="/content/**/**/*.*" verb="*" preCondition="integratedMode" type="System.Web.StaticFileHandler" />
        <add name="content3" path="/content/**/**/**/*.*" verb="*" preCondition="integratedMode" type="System.Web.StaticFileHandler" />
        <add name="content4" path="/content/**/**/**/**/*.*" verb="*" preCondition="integratedMode" type="System.Web.StaticFileHandler" />
        <add name="castle" path="*" verb="*" type="Castle.MonoRail.Framework.MonoRailHttpHandlerFactory, Castle.MonoRail.Framework" modules="ManagedPipelineHandler" scriptProcessor="" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode,runtimeVersionv2.0" />
    </handlers>

    <modules>
        <add name="routing" type="Castle.MonoRail.Framework.Routing.RoutingModuleEx, Castle.MonoRail.Framework" />
        <add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.MicroKernel" />
    </modules>

    <validation validateIntegratedModeConfiguration="false" />

</system.webServer>

(In fact, we never got this working on IIS6, but did on the web-dev server - we've got support since then and were told it would work with a * mapping at the IIS6 level to the aspnet_isapi.dll - but by then, the dev running Win2003 updated to something with IIS7 on it, so we haven't tried that)

        protected virtual void RegisterRoutes(IRoutingRuleContainer engine)
    {
        engine.Add
            (
            new PatternRoute(ThorController.CtlrHome, "/[controller]")
                .DefaultForController().Is(ThorController.CtlrHome)
                .DefaultForArea().Is(ThorController.AreaPublic)
                .DefaultForAction().Is(ThorController.ActionIndex)
            );

        engine.Add
            (
            new PatternRoute(ThorController.KeyDefault, "/<area>/<controller>/[action]/[id]")
                .DefaultForArea().Is(ThorController.AreaPublic)
                .DefaultForAction().Is(ThorController.ActionIndex)
                .DefaultFor(ThorController.KeyId).IsEmpty
            );
    }

(the first route handles our application root)

(the values are consts on our ThorController base class to try to cut down on string literals)

As an aside, anyone know if there exists syntax to do what we're doing with static file handling in one line? There's surely gotta be a better way than our "solution" ;-)