Routing Issues with Dynamic Compilation

Topics: Core, Writing modules
Oct 18, 2012 at 3:43 PM

Hi,

I believe I'm suffering an issue with routing and dynamic compilation. I have several routes defined through IRouteProvider and INavigationProvider, examples of which are below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.Localization;
using Orchard.UI.Navigation;

namespace MySite.BankingServiceAdmin.Providers
{
    public class GRMSAdminNavigationProvider : INavigationProvider
    {
        private Localizer T { get; set; }

        public string MenuName
        {
            get { return "admin"; }
        }

        public GRMSAdminNavigationProvider()
        {
            T = NullLocalizer.Instance;
        }

        public void GetNavigation(NavigationBuilder builder)
        {
            builder
                // Image set
                .AddImageSet("grmsadmin")

                // "Webshop"
                .Add(item => item

                    .Caption(T("GRMS Admin"))
                    .Position("2")

                    // Banking Service
                    .Add(subItem => subItem
                        .Caption(T("Banking Service"))
                        .Position("2.1")
                        .Action("Index", "BankingAdmin", new { area = "GRMS.Orchard.Banking" })
                    )
                );
        }
    }
}

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.Mvc.Routes;

namespace GRMS.Orchard.Security.Providers
{
    public class SecurityRoutesProvider : IRouteProvider
    {
        public IEnumerable<RouteDescriptor> GetRoutes()
        {
            return new[] {
                             new RouteDescriptor {   Priority = 1,
                                                     Route = new Route(
                                                         "Users/Account/{action}",
                                                         new RouteValueDictionary {
                                                                                      {"area", "GRMS.Orchard.Security"},
                                                                                      {"controller", "Account"}
                                                         },
                                                         new RouteValueDictionary(),
                                                         new RouteValueDictionary {
                                                                                      {"area", "GRMS.Orchard.Security"}
                                                         },
                                                         new MvcRouteHandler())
                             }
                         };
        }

        public void GetRoutes(ICollection<RouteDescriptor> routes)
        {
            foreach (var routeDescriptor in GetRoutes())
                routes.Add(routeDescriptor);
        }
    }
}

The second of these is used to override the normal AccountController from Orchard.Users. These have always worked perfectly while using a full source code enlistment, and adding new modules directly to the project. We have recently removed the source code enlistment, and now have our modules in a standalone solution, with a copy of Orchard running in web matrix. We now have the problem that reasonably regularly Orchard completely screws up the routes (e.g the /Users/Account route is overridden, but there is no new value for the route and it fails (kinda bad as it is the login....). This also happens with INavigationProvider routes, which sometimes just disappear. 

In each case the following workaround resolves the issue

  1. Comment out the class doing the routing
  2. restart webmatrix/IISexpress Orchard site
  3. uncomment the code
  4. restart webmatrix/IISexpress Orchard site

which is why I'm reasonably sure that this is a problem with dynamic compilation (When in visual studio, it understands how to build the dlls and put them in the right places, it also understands.....project references!).

I must admit to the number of issues with dlls, referencing and dynamic compilation being quite tough to deal with for a product development life-cycle. I'm not sure if we are doing something fundamentally wrong in our process, or does Orchard development just consist of dealing with these problems.

My problem seems to be related to http://stackoverflow.com/questions/12588280/orchard-cms-routing-not-working-on-localhost,  but I can't see a bug filed for that, though it is recent.

Should I be raising this as a bug? It's causing us some pretty serious hassle.

 

Oct 18, 2012 at 4:21 PM

Some more information. If I do not rebuild my solution (in visual studio), and instead only refresh the browser after code changes then it appears to work. If I rebuild, the problem occurs. So summary of reproduction:

  1. setup vs solution with several modules. These modules are naturally sitting at the correct location for a local Orchard installation to see
  2. Have a working site with route defined by IRouteProvider 
  3. use VS "rebuild" option
  4. route no longer works
  5. comment out class inheriting IRouteProvider
  6. refresh browser (orchard detects configuration change), site works
  7. uncomment code, refresh browser (orchard detects configuration change) , route now works again
  8. Rebuild solution, this causes the route to break once more.

 

Oct 18, 2012 at 4:47 PM

As a thought - is there any way to turn off dynamic compilation/always use (visual studio) pre-compiled assemblies? We really have no need of ad-hoc changing (in fact quite the opposite we'd rather not even deploy code files to the server (which would not happen with an average MVC project for example). Just a thought.

Paul

Coordinator
Oct 18, 2012 at 5:24 PM

Yes: http://docs.orchardproject.net/Documentation/Orchard-module-loader-and-dynamic-compilation#Disablingthe"DynamicModule"loader

Oct 18, 2012 at 6:03 PM

I somehow missed that section of that doc. I'll give that a try. thanks

Oct 19, 2012 at 11:06 AM

Ok, when I disable dynamic compilation the route never works. If I re-enable dynamic compilation, and make any change to the class implementing IRouteProvider (like even adding a new line or space) then the rout works. No warnings or errors are raised in the log files. all the required files seem to be in the dependencies folder.

I see entries for the module dll/project file in  both dependencies.xml and dependencies.compiled.xml. (I presume the .deleted extension is applied to a dependency when dynamic compilation identifies it should replace a precompiled version).

Unless there are any amazing suggestions I'm going to raise this as a bug.

For clarity:

  1. Disable dynamic compilation
  2. Restart site. Route does not work
  3. re-enable dynamic compilation
  4. restart site. Route does not work
  5. make any change to class implementing IRouteProvider.
  6. restart site. Route works.
Developer
Nov 4, 2012 at 3:07 AM

So if you precompile your module and deploy it, your routes don't work? As a sanity check, also implement a test action method, on a controller and see if you can invoke it after building and deploying.