MapMvcAttributeRoutes: This method cannot be called during the application's pre-start initialization phase
asp.net-mvc, asp.net-mvc-5, attributerouting, unit-testing
Solution
I recently upgraded my project to ASP.NET MVC 5 and experienced the exact same issue. When using dotPeek to investigate it, I discovered that there is an internal `MapMvcAttributeRoutes` extension method that has a `IEnumerable<Type>` as a parameter which expects a list of controller types. I created a new extension method that uses reflection and allows me to test my attribute-based routes:
public static class RouteCollectionExtensions
{
public static void MapMvcAttributeRoutesForTesting(this RouteCollection routes)
{
var controllers = (from t in typeof(HomeController).Assembly.GetExportedTypes()
where
t != null &&
t.IsPublic &&
t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) &&
!t.IsAbstract &&
typeof(IController).IsAssignableFrom(t)
select t).ToList();
var mapMvcAttributeRoutesMethod = typeof(RouteCollectionAttributeRoutingExtensions)
.GetMethod(
"MapMvcAttributeRoutes",
BindingFlags.NonPublic | BindingFlags.Static,
null,
new Type[] { typeof(RouteCollection), typeof(IEnumerable<Type>) },
null);
mapMvcAttributeRoutesMethod.Invoke(null, new object[] { routes, controllers });
}
}
And here is how I use it:
public class HomeControllerRouteTests
{
[Fact]
public void RequestTo_Root_ShouldMapTo_HomeIndex()
{
// Arrange
var routes = new RouteCollection();
// Act - registers traditional routes and the new attribute-defined routes
RouteConfig.RegisterRoutes(routes);
routes.MapMvcAttributeRoutesForTesting();
// Assert - uses MvcRouteTester to test specific routes
routes.ShouldMap("~/").To<HomeController>(x => x.Index());
}
}
One problem now is that inside `RouteConfig.RegisterRoutes(route)` I cannot call `routes.MapMvcAttributeRoutes()` so I moved that call to my Global.asax file instead.
Another concern is that this solution is potentially fragile since the above method in `RouteCollectionAttributeRoutingExtensions` is internal and could be removed at any time. A proactive approach would be to check to see if the `mapMvcAttributeRoutesMethod` variable is null and provide an appropriate error/exceptionmessage if it is.
NOTE: This only works with ASP.NET MVC 5.0. There were significant changes to attribute routing in ASP.NET MVC 5.1 and the `mapMvcAttributeRoutesMethod` method was moved to an internal class.
Problem
I have a very simple test in a test project in a solution using ASP MVC V5 and attribute routing. Attribute routing and the `MapMvcAttributeRoutes` method are part of ASP MVC 5. ``` [Test] public void HasRoutesInTable() { var routes = new RouteCollection(); routes.MapMvcAttributeRoutes(); Assert.That(routes.Count, Is.GreaterThan(0)); } ``` This results in: ``` System.InvalidOperationException : This method cannot be called during the applications pre-start initialization phase. ``` Most of the answers to this error message involve configuring membership providers in the `web.config` file. This project has neither membership providers or a `web.config` file so the error seems be be occurring for some other reason. How do I move the code out of this "pre-start" state so that the tests can run? The equivalent code for attributes on `ApiController` works fine after `HttpConfiguration.EnsureInitialized()` is called.