I have a controller in an area (/Areas/Admin/Controller/JackpotController.cs) with the following code
public ActionResult Index()
{
return View();
}
I have a Razor view here: /Areas/Admin/Views/Jackpot/Index.cshtml.
I have a Web Forms view (which is not in an area) here: /Views/Jackpot/Index.aspx.
The controller returns the Web forms view and not the Razor view!
I removed both views to force this exception, which explains why the wrong view is returned:
The view 'Index' or its master was not found. The following locations were searched:
~/Areas/Admin/Views/Jackpot/Index.aspx
~/Areas/Admin/Views/Jackpot/Index.ascx
~/Areas/Admin/Views/Shared/Index.aspx
~/Areas/Admin/Views/Shared/Index.ascx
~/Views/Jackpot/Index.aspx
~/Views/Jackpot/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx
~/Areas/Admin/Views/Jackpot/Index.cshtml
~/Areas/Admin/Views/Jackpot/Index.vbhtml
~/Areas/Admin/Views/Shared/Index.cshtml
~/Areas/Admin/Views/Shared/Index.vbhtml
~/Views/Jackpot/Index.cshtml
~/Views/Jackpot/Index.vbhtml
~/Views/Shared/Index.cshtml
~/Views/Shared/Index.vbhtml
As you can see, MVC incorrectly searches the root aspx views before the area cshtml views. Correct behavior should be to always search areas first, regardless of view engine.
As you can see, MVC incorrectly searches the root aspx views before the area cshtml views. Correct behavior should be to always search areas first, regardless of view engine.
If you see the MVC source you will find that MVC pick the top most view engine in the view engines stack then start matching the view. If no matching view is found then pick the next view engine and so on. I think this is much feasible that you select a
view engine one by one and match it with your view rather then selecting all the regestered view engines only for area concern first and then selecting all the regestered view engines for all non-area concern.
For your particular case you can either prioritize razor view engine or use the IView overload of View method.
"And whoever is removed away from the Fire and admitted to Paradise, he indeed is successful." (The Holy Quran)
Excellent Windows VPS Hosting Imran Baloch MVP, MVB, MCP, MCTS, MCPD
Thank you for explaining why it chooses the web forms engine before the razor one. I understand that it might have been easier to implement it like that. But you still haven't convinced me that this behavior is better.
I think it should first look in Areas, then the root and then Shared, like this:
Area
Web forms
Razor
...
Non-area
Web forms
Razor
...
Shared
Web forms
Razor
...
But I might be missing something, so please describe a scenario where the current implementation (view engine by view engine) would be better then the order above.
The current algorithm is better for most developers and better for the MVC framework maintainability. Most applications don't use more than one view engine. Some use 3 or more view engines. In reality this isn't a problem as you probably shouldn't have the
same named view for different view engines.
The views will often be named the same regardless of view engine right (Index, Create, Details etc.)?
The problem was not that I had Index.aspx and Index.cshtml in the same view folder. I understand that it will pick Index.aspx first if I would do that. The problem was that I had Index.cshtml in an Area view folder and Index.aspx in the root view folder
and MVC picks Index.aspx from the root even though the controller with return View("Index") was in the area.
If you do return View("Index") in /Areas/Admin/Controllers/HomeController.cs wouldn't it be more logical and intuitive if it used /Areas/Admin/Views/Home/Index.cshtml rather than /Views/Home/Index.aspx?
Sorry if I'm nagging, I'm just surprised that I'm the only one that thinks this is weird:)
Sorry if I'm nagging, I'm just surprised that I'm the only one that thinks this is weird:)
</div>
No problem. It's unfortunate that the current design does not work in your particular scenario. However, you should understand that the concept of Areas is not something that is inherent to MVC as a whole. Rather (though i'm simplifying a bit), it's a convention
that is implemented in the WebFormViewEngine (and RazorViewEngine in MVC 3).
The general contract for view engines in MVC is that there is a collection of them and when a view lookup occurs they are asked in turn to provide a view. The first one wins and any view engine after is not 'questioned'. It's up to the individual view engines
to have any fallbacks, such as the Areas pattern fallback. There might exist view engines out there that don't implement areas at all.
Unfortunately we cannot change this contract at this point because that would likely result in breaking changes in existing applications. However, you can always implement you own IViewEngine that follows your preferred lookup patterns.
It's up to the individual view engines to have any fallbacks, such as the Areas pattern fallback. There might exist view engines out there that don't implement areas at all.
Thank you for taking the time clearing this up for me! I understand why it has to behave the way it does now.
dillenmeiste...
Member
1 Points
6 Posts
Locate view bug in MVC3 RC
Nov 13, 2010 09:13 PM|LINK
Hi,
I have a controller in an area (/Areas/Admin/Controller/JackpotController.cs) with the following code
public ActionResult Index() { return View(); }I have a Razor view here: /Areas/Admin/Views/Jackpot/Index.cshtml.
I have a Web Forms view (which is not in an area) here: /Views/Jackpot/Index.aspx.
The controller returns the Web forms view and not the Razor view!
I removed both views to force this exception, which explains why the wrong view is returned:
The view 'Index' or its master was not found. The following locations were searched:
~/Areas/Admin/Views/Jackpot/Index.aspx
~/Areas/Admin/Views/Jackpot/Index.ascx
~/Areas/Admin/Views/Shared/Index.aspx
~/Areas/Admin/Views/Shared/Index.ascx
~/Views/Jackpot/Index.aspx
~/Views/Jackpot/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx
~/Areas/Admin/Views/Jackpot/Index.cshtml
~/Areas/Admin/Views/Jackpot/Index.vbhtml
~/Areas/Admin/Views/Shared/Index.cshtml
~/Areas/Admin/Views/Shared/Index.vbhtml
~/Views/Jackpot/Index.cshtml
~/Views/Jackpot/Index.vbhtml
~/Views/Shared/Index.cshtml
~/Views/Shared/Index.vbhtml
As you can see, MVC incorrectly searches the root aspx views before the area cshtml views. Correct behavior should be to always search areas first, regardless of view engine.
/ Oskar
imran_ku07
All-Star
45815 Points
7698 Posts
MVP
Re: Locate view bug in MVC3 RC
Nov 14, 2010 02:33 AM|LINK
If you see the MVC source you will find that MVC pick the top most view engine in the view engines stack then start matching the view. If no matching view is found then pick the next view engine and so on. I think this is much feasible that you select a view engine one by one and match it with your view rather then selecting all the regestered view engines only for area concern first and then selecting all the regestered view engines for all non-area concern.
For your particular case you can either prioritize razor view engine or use the IView overload of View method.
return View(new RazorView("~/Areas/SomeArea/Views/List/Index.cshtml"));
http://forums.asp.net/p/1593209/4041505.aspx
Excellent Windows VPS Hosting
Imran Baloch MVP, MVB, MCP, MCTS, MCPD
dillenmeiste...
Member
1 Points
6 Posts
Re: Locate view bug in MVC3 RC
Nov 14, 2010 07:02 PM|LINK
Thank you for explaining why it chooses the web forms engine before the razor one. I understand that it might have been easier to implement it like that. But you still haven't convinced me that this behavior is better.
I think it should first look in Areas, then the root and then Shared, like this:
But I might be missing something, so please describe a scenario where the current implementation (view engine by view engine) would be better then the order above.
ricka6
All-Star
15070 Points
2272 Posts
Microsoft
Moderator
Re: Locate view bug in MVC3 RC
Nov 14, 2010 07:12 PM|LINK
Just remove the webForms view engine.
protected void Application_Start() { ViewEngines.Engines.RemoveAt(0);ricka6
All-Star
15070 Points
2272 Posts
Microsoft
Moderator
Re: Locate view bug in MVC3 RC
Nov 14, 2010 07:15 PM|LINK
The order is view engines. You will get the expected behavior if you change the order of view engines using the code snippet I provided.
protected void Application_Start() { ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new RazorViewEngine()); ViewEngines.Engines.Add(new WebFormViewEngine()); AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); }dillenmeiste...
Member
1 Points
6 Posts
Re: Locate view bug in MVC3 RC
Nov 14, 2010 07:30 PM|LINK
Thanks! That is the best way for me to work around the problem.
May I ask if you think the current behavior (view engine by view engine) is better than what I suggested (area, non-area, shared)?
</div>ricka6
All-Star
15070 Points
2272 Posts
Microsoft
Moderator
Re: Locate view bug in MVC3 RC
Nov 14, 2010 07:39 PM|LINK
The current algorithm is better for most developers and better for the MVC framework maintainability. Most applications don't use more than one view engine. Some use 3 or more view engines. In reality this isn't a problem as you probably shouldn't have the same named view for different view engines.
dillenmeiste...
Member
1 Points
6 Posts
Re: Locate view bug in MVC3 RC
Nov 14, 2010 08:10 PM|LINK
The views will often be named the same regardless of view engine right (Index, Create, Details etc.)?
The problem was not that I had Index.aspx and Index.cshtml in the same view folder. I understand that it will pick Index.aspx first if I would do that. The problem was that I had Index.cshtml in an Area view folder and Index.aspx in the root view folder and MVC picks Index.aspx from the root even though the controller with return View("Index") was in the area.
If you do return View("Index") in /Areas/Admin/Controllers/HomeController.cs wouldn't it be more logical and intuitive if it used /Areas/Admin/Views/Home/Index.cshtml rather than /Views/Home/Index.aspx?
Sorry if I'm nagging, I'm just surprised that I'm the only one that thinks this is weird:)
</div>marcind
Contributor
3344 Points
609 Posts
Microsoft
Re: Locate view bug in MVC3 RC
Nov 14, 2010 08:41 PM|LINK
No problem. It's unfortunate that the current design does not work in your particular scenario. However, you should understand that the concept of Areas is not something that is inherent to MVC as a whole. Rather (though i'm simplifying a bit), it's a convention that is implemented in the WebFormViewEngine (and RazorViewEngine in MVC 3).
The general contract for view engines in MVC is that there is a collection of them and when a view lookup occurs they are asked in turn to provide a view. The first one wins and any view engine after is not 'questioned'. It's up to the individual view engines to have any fallbacks, such as the Areas pattern fallback. There might exist view engines out there that don't implement areas at all.
Unfortunately we cannot change this contract at this point because that would likely result in breaking changes in existing applications. However, you can always implement you own IViewEngine that follows your preferred lookup patterns.
ASP.NET Team
@marcind
Blog
dillenmeiste...
Member
1 Points
6 Posts
Re: Locate view bug in MVC3 RC
Nov 14, 2010 09:48 PM|LINK
Thank you for taking the time clearing this up for me! I understand why it has to behave the way it does now.