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
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!