1

I am trying to update the route table after the application has started. I am doing this in a MVC Area called "Pages". The website has custom URLs for each customer: www.mydomain.com/Pages/CompanyName/

It works fine when you start the website. It picks up all the existing customers urls and you can navigate to them:

    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        List<Customer> custs = new CustBLL().getActiveCustomers();

        string urlList = string.Join("|", custs.Select(c => c.UrlIdentifier).ToArray());

        context.MapRoute(
            "Pages_CUSTURL", // Route name
            "Pages/{CUSTURL}/{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
            constraints: new { CUSTURL = urlList }
        );


        context.MapRoute(
            "Pages_default",
            "Pages/{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            constraints: new { controller = new ControllerConstraint() }
        );

    }

But, when a new customer is created, you can not get to the url for that customer, "www.mydomain.com/Pages/NewCompany/", because a 404 would happen.

So I tried to add a new function "UpdateRouteRegistration()" that is called after a new customer is created.

    public static void UpdateRouteRegistration()
    {
        RouteCollection routes = RouteTable.Routes;
        using (routes.GetWriteLock())
        {
            routes.Remove(RouteTable.Routes["Pages_CUSTURL"]);

            List<Customer> custs = new CustBLL().getActiveCustomers();

            string urlList = string.Join("|", custs.Select(c => c.UrlIdentifier).ToArray());

            routes.MapRoute(
                "Pages_CUSTURL", // Route name
                "Pages/{CUSTURL}/{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
                constraints: new { CUSTURL = urlList }
            );

        }
    }

The new function does not work. There are no errors when it is run but, afterwards I cannot navigate anywhere. I get a BlankView error. It seems like I corrupt the routing table.

Server Error in '/' Application.

The view 'BlankView' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/Home/BlankView.aspx
~/Views/Home/BlankView.ascx
~/Views/Shared/BlankView.aspx
~/Views/Shared/BlankView.ascx
~/Views/Home/BlankView.cshtml
~/Views/Home/BlankView.vbhtml
~/Views/Shared/BlankView.cshtml
~/Views/Shared/BlankView.vbhtml
~/__MVCSITEMAPPROVIDER/BlankView.ascx

I am using MVC 5.2.3. Any help is much appreciated.

Edit: I wonder if I need to use the AreaRegistraitionContext. But from this post, I can only access it using reflection? Get Areas associated with an MVC project

sean
  • 1,187
  • 17
  • 25

1 Answers1

2

I got this working and wanted to share with anyone who may be doing the same thing or similar. I am not sure if this is the best way but I am happy it works.

I did two things. One, I saved the AreaRegistrationContext to a static member for later use. Two, I did not try to add/remove the existing mapping. Instead, I just added a new one.

In my case, a new customer is not added too often so there will not be too many mappings for this area.

Here is my final class.

public class PagesAreaRegistration : AreaRegistration 
{
    public override string AreaName 
    {
        get 
        {
            return "Pages";
        }
    }

    public static AreaRegistrationContext AreaContext { get; set; }

    public override void RegisterArea(AreaRegistrationContext context)
    {

        context.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        // save context to static for later use
        AreaContext = context;

        // get customers
        List<Customer> custs = new CustBLL().getActiveCustomers();

        // get list of domain urls
        string urlList = string.Join("|", custs.Select(c => c.UrlIdentifier).ToArray());

        // map customer URLs
        context.MapRoute(
            "Pages_CUSTURL", // Route name
            "Pages/{CUSTURL}/{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
            constraints: new { CUSTURL = urlList }
        );

        // general area mapping
        context.MapRoute(
            "Pages_default",
            "Pages/{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            constraints: new { controller = new ControllerConstraint() }
        );

    }

    public static void UpdateRouteRegistration(string newURLID)
    {
        // get context from static member
        RouteCollection routes = AreaContext.Routes;

        // get write lock to avoid threading issues
        using (routes.GetWriteLock())
        {

            // add new company url to route table 
            AreaContext.MapRoute(
                "Pages_CUSTURL_" + newURLID,                                      // Route name
                "Pages/{CUSTURL}/{controller}/{action}/{id}",                       // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional },  // Parameter defaults
                constraints: new { CUSTURL = newURLID }
            );

        }

    }


}

Good luck if you are trying to accomplish something like this with MVC area routing!

sean
  • 1,187
  • 17
  • 25