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.
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 aIEnumerable<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:And here is how I use it:
One problem now is that inside
RouteConfig.RegisterRoutes(route)
I cannot callroutes.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 themapMvcAttributeRoutesMethod
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.Well, it's really ugly and I'm not sure if it'll be worth the test complexity, but here's how you can do it without modifying your RouteConfig.Register code:
Mapping attribute routes needs to find all the controllers you're using to get their attributes, which requires accessing the build manager, which only apparently works in app domains created for ASP.NET.
What are you testing here? Looks like you are testing a 3rd party extension method. You shouldn't be using your unit tests to test 3rd party code.
In ASP.NET MVC 5.1 this functionality was moved into its own class called
AttributeRoutingMapper
.(This is why one shouldn't rely on code hacking around in internal classes)
But this is the workaround for 5.1 (and up?):