.net MVC proper way to link to views within an area - asp.net-mvc

I have a .Net MVC app with a couple areas, one of which is called Admin. When I execute /Admin/Home/Index, the Index() method in the Admin area Home controller executes and the correct Index.cshtml is returned. So far, so good.
My issue is related to _Layout.cshtml. I want the layout to be different for each area and for the main site. To that end I have added _ViewStart.cshtml to my Admin area's Views folder, and within that _ViewStart I have the following:
#{
Layout = "/Areas/Admin/Views/Shared/_Layout.cshtml";
}
Again, so far, so good, but using a fully qualified path seems inelegant and I have to think there is a better way.
A similar question was asked here:
Area doesn't use the right view
The one answer that was given says that the fully qualified path is the way to go, though it was not marked as the answer by the OP.
So my question is this. Is it necessary to use a fully qualified path to reference views within an area? Is it not possible to do this in an area:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
Based on the controller that is executing, is the view engine not capable of resolving that I want the view from the area's shared folder and not the view from the main site's shared folder?
Thanks,
Chris

Your Views inside of the Areas will automatically look to the Views folder in that area for a _ViewStart.cshtml or a _ViewImports.cshtml file. My advice in your case would be to put a _ViewStart.cshtml file into your Area's View folders (Not in their Shared folders!) and have it reference the _Layout file of your choice such as:
_ViewStart.cshtml
#{
Layout = "_Layout";
}

Related

How to make ASP.NET invalid partialview paths strongly typed, not compile or give/warning?

I make use of ASP.NET 5 Areas.
In the default ASP.NET 5 project you have _ValidationScriptsPartial.cshtml in the Views\Shared folder
I can refer to it in my Areas\AreaName\Views\controllername\MyView.cshtml
as
#{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
Questions:
Why can I refer to its path directly and not be forced to use
#{await Html.RenderPartialAsync("~/Views/Shared/_ValidationScriptsPartial.cshtml"}
I ask because it is sometimes confusing where it comes from as it is not an relative path.
Is there a setting somewhere to enable/disable this behavior.
I have various of my own scripts in location in Views\Shared as well as in my area's view folder Areas\MyArea\Views\MyControllerName\. If I have the same partial view name as in the Views\Shared folder will it take precendence?
Is there a way to make the location strongly typed (i.e. give build error if not exist) or is using C# constants the best way around this?
e.g.
#{ await Html.RenderPartialAsync("_ValidationScriptsPartialNotExist"); }
does not give an error or warning or red line underneath

Finding Razor partial views in the area EditorTemplates folder

I am starting to use EditorFor helper method to render my razor partial views, but I couldn't get the partials in the Areas folder to work.
Here is the path to the partial:
~\Areas\Products\Views\Shared\EditorTemplates\_Edit.cshtml
The partial is really simple with only one "div" tag to do the testing.
Try to use in my page view (~\Areas\Products\Views\EditPage.cshtml) as
#Html.EditorFor(m => m.ProductEditModel, "_Edit")
Visual studio tells me that "Cannot resolve template '_Edit'".
Now, if I move the partial to the root view folder:
~\Views\Shared\EditorTemplates\_Edit.cshtml
It works, Visual studio has no problems to resolve the template, and the div is renderred correctly in my browser.
I also tried to customize the RazorViewEngine, did not work either
namespace MySite.Web
{
public class RazorViewEngine : System.Web.Mvc.RazorViewEngine
{
public RazorViewEngine()
: this(null)
{
}
public RazorViewEngine(IViewPageActivator viewPageActivator)
: base(viewPageActivator)
{
AreaPartialViewLocationFormats = new[]
{
"~/Areas/{2}/Views/Shared/EditorTemplates/{0}.cshtml"
}.Union(AreaPartialViewLocationFormats).ToArray();
}
}
}
Just wondering what did I do wrong? BTW, I am using MVC3 at the moment, can't upgrate to MVC4 due to some old components.
When calling a partial view or view from a different area in MVC, specify the full path of the partial view or view. Since MVC is based on convention, by convention it will look in the same area the calling code in the view (or controller) resides for any partial views or views referenced, unless a specific path is used. Try using the full path to reference the partial view when it is located in the products area:
#Html.EditorFor(m => m.ProductEditModel, "~/Areas/Products/Views/Shared/EditorTemplates/_Edit.cshtml")
Since the view referenced is a shared view it doesn't matter if you specify the full path if you are in the same area. However, if you are trying to access a view within a different directory than the view trying to reference it and this directory is not named shared you will need to specify the full path regardless of area. It is similar when the controller calls the view; if a controller from the same area as the referenced view specifies the short name for the view and this view is from a parent directory named different than its own (ignoring the "controller" suffix) the view engine will not find your view. Unless of course the parent directory for the view is in the shared folder.
Whether it's in the controller or a view you can't use the "short name" across areas because the view engine has a convention for where to look when the path isn't used. Areas are meant to do this to keep your code separated, or decoupled if you will, at a high level by default. So any decision to "cross the barrier" should be thought about mindfully, but certainly not discouraged. It's all about convention.
I am answering my own question now.. My page view path was not correct. Since my area is Products, controller is ProductController, my page view should be placed in ~\Areas\Products\Views\Product\EditPage.cshtml, that way, it matches what the view engine expects, and the partial will be corrected resolved.

ASP.NET MVC: Multiple View Folders and _ViewStart.cshtml file

I have an MVC project that requires there to be 2 different View folders. One is at ~/Views/ and one at ~/Framework/Views/. This is done by creating a custom view engine based on the razor view engine like this:
public class MyViewEngine : RazorViewEngine
{
private static string[] AdditionalViewLocations = new[]{
"~/Framework/Views/{1}/{0}.cshtml",
"~/Framework/Views/{1}/{0}.vbhtml",
"~/Framework/Views/Shared/{0}.cshtml",
"~/Framework/Views/Shared/{0}.vbhtml"
};
public MyViewEngine()
{
base.PartialViewLocationFormats = base.PartialViewLocationFormats.Union(AdditionalViewLocations).ToArray();
base.ViewLocationFormats = base.ViewLocationFormats.Union(AdditionalViewLocations).ToArray();
base.MasterLocationFormats = base.MasterLocationFormats.Union(AdditionalViewLocations).ToArray();
}
}
The problem is that I want to use a different _ViewStart.cshtml file in each of the 2 Views folder (i.e. ~/Views/_ViewStart.cshtml for views found in the ~/Views/ folder and ~/Framework/Views/_ViewStart.cshtml for views found in the ~/Framework/Views/ Folder), however the View Engine just uses the first one it finds which is the original one in ~/Views/.
Is this possible to do?
Thank you
This is definitely possible, I think you just missed something.
I have tested this myself using the view engine you supplied (copied and pasted verbatim). I am not seeing the same behavior as you. I have two _ViewStart.cshtml files, one at ~/Framework/Views/_ViewStart.cshtml, and one at ~/Views/_ViewStart.cshtml.
When I run a view within ~/Framework/Views/, it uses the _ViewStart.cshtml in the Framework folder. When I run a view within ~/Views/, it uses the _ViewStart.cshtml in the Views folder.
Double checking the code in RazorViewEngine using DotPeek also confirms that this is exactly how it should behave. The view engine starts checking in for a file named _ViewStart.cshtml within the same folder as the view being rendered, and then walks up the directory tree until it gets to the root of the application.
The selection of _ViewStart is hierarchical, but you've added ~/Framework/Views parallel to ~/Views. I don't think Razor is set up to actually do what you want (i.e. two completely parallel view locations). If you were to put Framework into the main Views folder, your _ViewStarts would load properly, though.

Finding my View in asp.net mvc

My Views folder has gotten crazy big! I would like to reorganize it so that the Views folder contains a list of Modules, and then each Module folder contains its share of the View (Controller) folders that currently appear under Views folder.
But of course this means going into each of my controllers and editing every view-returning method the explicit location of its view.
So instead of Controller Orders.Index method just having this:
return View();
I have to edit it to return this:
return View("~/Views/Orders/Index.cshtml");
You can imagine the suck level that this exercise attains over 50 or so controllers.
Is there some way that I can setup a routing or something per controller that will tell that controller's methods to go find their views in a defined subfolder of the Views folder?
It can be done with the help of CustomViewEngine
Follow this post and i hope you can provide your own locations to locate the view template.
MVC provide way where we can easily provide list of path to be searched
Locate view
Once you add CustomViewEngine, register it in Application_Start() event and then you are done :)
Happy coding
You could fix that by implementing a custom RazorViewEngine, where you can specify the search path for the views per request, per controller and so on.

MVC 4 solution structure Partial View

Well since most of the tutorials and demos chooses to put the partial view in shared folder im asking for a better way to do this.
My problem:
I want to use partial views in order to create a dynamic interface with reusable views. As i can with usercontrols. Since there might be a lot of partial views i want to put them in a seperate folder than the shared folder.
example:
How it looks today:
[View]
[View.Home]
index.cshtml
[View.Shared]
_layout.cshtml
A better way
[View]
[View.Home]
index.cshtml
[View.Shared]
_layout.cshtml
[View.Shared.Partial]
partial1.cshtml
etc
Or should i rethink my approach enirely? if so how? if not what should i think about?
Here is an example of something I do,
Application Wide used partial views - I put them in my Shared directory.
Partial Views for a specific Controller - I put them in the Views/[ControllerName] Directory.

Resources