Question

Important Update
Since the release of MVC 2.0 Preview 1 this feature has been implemented as the part of the actual framework itself in the form of Areas. More details available on Phil Haack's blog here

I have a controller called ListManagerController. This controller contain an ActionResult method called Index(). When I right cick on Index in Visual Studio and select Add View the new view is created in /Views/ListManager/Index.

However I want the Index view and all subsequent views to be created in /Views/Manage/ListManager/. How would I accomplish this?

Edit: It was pointed out that this question is a duplicate of the question posted here. It seems my searching skills failed me initially.

Was it helpful?

Solution

The location of views is tied to the ViewFactory you are using. AFAIK the web forms view engines does not support areas [Manage in your example].

Spark supports this and is very clean, you can also mix and match web forms and spark views so you don't have to recreate all your views.

UPDATE: Looks like Phil Haack has a blog post on how to achieve this. His code is for the RC, but I think that should compile fine against ASP.NET MVC RTM.

OTHER TIPS

I know you already accepted an answer but here's what I came up with while experimenting with the same idea, with the help of Phil Haack's post.

First you need to have your own ViewEngine to look for folders under View folder. Something like this : (You'll notice that it looks a lot like Phil Haack's areas code)

public class TestViewEngine : WebFormViewEngine
{
    public TestViewEngine()
        : base()
    {
        MasterLocationFormats = new[] {
            "~/Views/{1}/{0}.master",
            "~/Views/Shared/{0}.master"
        };

        ViewLocationFormats = new[] {
            "~/{0}.aspx",
            "~/{0}.ascx",
            "~/Views/{1}/{0}.aspx",
            "~/Views/{1}/{0}.ascx",
            "~/Views/Shared/{0}.aspx",
            "~/Views/Shared/{0}.ascx"
        };

        PartialViewLocationFormats = ViewLocationFormats;
    }
    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
        ViewEngineResult rootResult = null;

        //if the route data has a root value defined when mapping routes in global.asax
        if (controllerContext.RouteData.Values.ContainsKey("root")) {
            //then try to find the view in the folder name defined in that route
            string rootViewName = FormatViewName(controllerContext, viewName);
            rootResult = base.FindView(controllerContext, rootViewName, masterName, useCache);
            if (rootResult != null && rootResult.View != null) {
                return rootResult;
            }
            //same if it's a shared view
            string sharedRootViewName = FormatSharedViewName(controllerContext, viewName);
            rootResult = base.FindView(controllerContext, sharedRootViewName, masterName, useCache);
            if (rootResult != null && rootResult.View != null) {
                return rootResult;
            }
        }
        //if not let the base handle it
        return base.FindView(controllerContext, viewName, masterName, useCache);
    }

    private static string FormatViewName(ControllerContext controllerContext, string viewName) {
        string controllerName = controllerContext.RouteData.GetRequiredString("controller");

        string root = controllerContext.RouteData.Values["root"].ToString();
        return "Views/" + root + "/" + controllerName + "/" + viewName;
    }

    private static string FormatSharedViewName(ControllerContext controllerContext, string viewName) {
        string root = controllerContext.RouteData.Values["root"].ToString();
        return "Views/" + root + "/Shared/" + viewName;
    }
}

Then in your Global.asax replace the default ViewEngine with your custom one, on Application_Start :

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new TestViewEngine());

Now when you are defining routes in Global.asax, you need to set a root value indicating the folder to look for under the View folders like so :

routes.MapRoute(
    "ListManager",
    "ListManager/{action}/{id}",
    new { controller = "ListManager", action = "Index", id = "", root = "Manage" }
 );

This question is VERY much a repeat of this question

so I'll quote my answer to that one here.

I came up with a different solution that didn't require me to roll my own view engine.

Basically, I wanted to keep MVC as "Convention" driven as possible, but I still wanted to organize all of my "Admin" views under the ~/Views/Admin folder.

Example:

  • ~/Views/Admin/User/
  • ~/Views/Admin/News/
  • ~/Views/Admin/Blog/

My solution was to create a new base class for my specific admin controllers and "force" the path to the view for that controller.

I have a blog post and sample code here: Organize your views in ASP.Net MVC

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top