CONFIRMED: Orchard has *No* support per-request Route switching

Topics: Core, Customizing Orchard, General, Writing themes
Apr 12, 2012 at 9:17 PM

I *think* that Orchard doesn't support per-request theme switching. I haven't confirmed it yet. It is the theoretical impact from this issue I found; http://orchard.codeplex.com/discussions/350393

 

SCENARIO

  • I have a theme called 'ThemeA' that registers a route for '\accounts\list' to a controller in 'ThemeA'
  • I have a theme called 'ThemeB' that registers a route for '\accounts\list' to a controller in 'ThemeB'
  • I have a theme switcher that picks either 'ThemeA' or 'ThemeB' for each HTTP request based on the type of request or origin of the request.

The first request to the webserver will trigger the Orchard Setup process and build the RouteTable for the selected theme.

If the next HTTP request selects the other theme, it will not resetup Orchard and the RouteTable will not change. Result: it will be redirect to the controller in the wrong theme.

 

Is this correct? Looks like this isn't a limitation of Orchard. Its a symptom of ASP.NET Routing; you can't change the RouteTable while requests are processing.

Will be great to know if it is true and get some details from the Orchard community. Is there another way we can approach this type of scenario without theme switching?

Apr 16, 2012 at 4:28 AM
Edited Apr 16, 2012 at 4:30 AM

CONFIRMED. But the behaviour isn't exactly as I predicted. And this isn't a flaw/problem with Orchard really. You can't change the RouteTable at runtime if you want to process more than one http request at a time.

Behaviour

  1. On Orchard Setup all themes and modules register their routes with Orchard
    1. Even if they are dis-enabled; http://orchard.codeplex.com/discussions/350393
  2. Orchard prioritizes all the routes
  3. Orchard registers all the routes with System.Web.Routing.RouteTable in the prioritized order
  4. The RouteTable never changes, unless the process is recycled and Orchard is pushed through its Setup again

 

Given the scenario in the original post above:

  • ThemeA registers its url with a priority of 10
  • ThemeB registers its url with a priority of 20
  • The RouteTable is constructed with ThemeB's route before ThemeA's
  • Every http request to '\accounts\list' will hit ThemeB's route and controller
    • Even if the selected theme is ThemeA

This is the behaviour I observe.

Can someone in the Orchard Community confirm/deny this?

Coordinator
Apr 16, 2012 at 4:52 AM

You don't need to modify the routes at runtime to enable that kind of scenario (and unless I'm mistaken, having the route table set-up when the app starts is an MVC thing, not Orchard, as it needs to have that table ready extremely early in the request lifecycle). Thats why you have wildcards, and that's why you have route constraints. Not sure what you mean by "process more than one request at a time".

Apr 16, 2012 at 5:31 AM

I was looking for confirmation of this behaviour. Thank you for replying.

"route table set-up when the app starts is an MVC thing, not Orchard"

Yes it is an MVC/Routing thing.

"you have wildcards, and that's why you have route constraints"

True. We would have a url per "theme";

  •  
    • 'ThemeA\accounts\list'
    • 'ThemeB\accounts\list'

i.e. "{theme}/{area}/{controller}/{Action}"


Apr 16, 2012 at 6:09 AM
Edited Apr 16, 2012 at 7:14 AM

Based on those URL's, it looks like you could set up different Routes for each theme, and each route would point to different controllers. They would never match the same URL (given that the theme name is part of the URL, you could ensure this by setting up the route accordingly). Theme switching could work independently of how the routes are set up (I have no idea how theme switching works; never had to use it, but I understand you can switch it on the fly with IThemeSelector).

Edit: Can you post the possible inputs that go into deciding which theme/controller to use? Is there anything other than URL? If not then above should be true. If other stuff, then the above is still valid (probably :) but you may have to do a custom route class (for example if you need to vary based on HTTP headers) or something.

Developer
Apr 16, 2012 at 3:06 PM

Without digging into depths I think you could change the theme based in the url in (i.e. the theme UrlData value) in an action filter through IThemeSelector.

Apr 17, 2012 at 10:32 PM

@TheMonarch, Piedone:

I need to switch themes based on the request origin.

The theme switcher isn't the problem, I have written a theme switcher that works.

The problem is the behaviour when the theme is switched at runtime (while other requests are being processed).

Orchard will render the correct shapes for the selected theme.

Orchard will not change the routes/controllers/dependencies. These are loaded during Orchard Setup which only happens once.

 

Using urls per theme is the only want to solve this problem. We wanted all client to have the same urls and have Orchard switch behaviour under the hood.

Apr 17, 2012 at 11:08 PM

It seems like you didn't read my post because I made suggestions about how you might achieve routing based on origin without having to have separate URL's per theme. 

Apr 19, 2012 at 1:57 AM

@TheMonarch; Sorry.

We have solution we are going to try. Keen to hear what you guys thing.

 

We would modify ShellRoute.GetRouteData:

  • When ShellRoute.GetRouteData is called
  • If the route is from a theme
  • And, it is not the selected theme
  • Return Null

If two themes have registered the same Url, this extra check will ensure that only the selected theme's route is matched.