I have written a test ViewEngine which responds to requests with a view name of “About”, and added the following to the Application_Start method in Global.asax.
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new RazorViewEngine());
ViewEngines.Engines.Add(new MyViewEngine());
The FindView method of MyViewEngine is as follows:
if (viewName == "About")
return new ViewEngineResult(new MyView(), this);
return new ViewEngineResult(new List<string>{"Some arbitrary search location"});
As the Home controller responds to the action About, I would have expected the RazorViewEngine to handle a request for ~/Home/About (as it was added to the Engines collection first) but it’s not… MyViewEngine is handling calls to that URL instead.
Calls which result in views not named “About” are handled correctly by Razor.
Even if I reverse the order of the two Add statements above, I get the exact same behavior. If I comment out the code which registers my view engine, Razor does pick up ~/Home/About as I would expect.
Any ideas why MyViewEngine is creating views ahead of Razor when it shouldn’t be?
ASP.NET MVC asks the registered
ViewEnginesin their registration order as expected. However there is one catch. It’s in theViewEngineCollectionFindViewmethod:This method iterates through the available
ViewEnginesasking for a view but it does it twice. Once with calling theFindViewmethod withuseCache=trueand if none of theViewEnginesprovided a result it iterates over them another time withuseCache=false.So in your case when it asks the
RazorViewEnginewithuseCache=trueit does not return a view because there is no chached one. But your view engine will always provideView. So you need to handle theuseCache=truecase in your implementation: