控制器和视图中的子文件夹

时间:2009-04-10 00:22:01

标签: asp.net-mvc model-view-controller

我想在asp.net mvc中拥有多个控制器和相同对象/模型的视图,但结果比我想象的要复杂一点。

基本上我想做的是这样的事情:

site.com/product
    ->  will show product details to visitors.

site.com/admin/product
    ->  will show some extra information together with product details.
        and some commands like delete, edit etc.

目标是为访问者和管理员分隔网址。

我的第一个方法是在控制器和视图文件夹中创建一个子文件夹,所以事情会这样:

> Controllers
    > Admin
        ProductController.cs
    ProductController.cs
> Views
    > Admin
        > Product
            Index.aspx
    > Product
        Index.aspx

我可以毫无问题地将网址映射到正确的控制器(前提是我指定了它们的名称空间,因为类名相同)。 但是,当我从管理员文件夹下的Controller返回视图时,它不会显示Views / Admin / Product文件夹下的Index视图,而是显示Views / Product下的Index视图。

我知道我可以说return View("Full path here")返回我想要的视图。但这显然不是一个好的解决方案,我不想这样做。

我的问题是,处理这种情况的最佳方法是什么,网址必须是这样的?

  • 创建一个自定义控制器类来覆盖视图方法(或为此目的需要覆盖的任何其他方法),并确保返回正确的视图?

    • 这个是一个丑陋的黑客,但会起作用。
  • 创建一个也考虑文件夹的自定义视图引擎?

    • 我不知道如何做到这一点,但据我了解,这也应该解决问题
  • 使用Areas PrototypePhil Haack

    • 这个实际上对文件夹使用不同的布局,但理论上这也应该有效。但我仍然不确定这是否是最好的方法,因为有不同的控制器和放大器。查看网站不同部分下的文件夹并不是我想要的。

我倾向于自定义视图引擎的想法,在返回视图时会考虑文件夹,但就像我说的那样,我不知道该怎么做。

有什么建议吗?

2 个答案:

答案 0 :(得分:2)

为你的MVC项目试用Phil Haack的/ Areas /:http://haacked.com/archive/2008/11/04/areas-in-aspnetmvc.aspx

你的普通内容有正常的Root,你的所有管理员都有特殊的/ Areas / Admin /部分(而url将是/ admin /)。

alt text
(来源:haacked.com

答案 1 :(得分:1)

ASP.Net MVC默认使用平面视图文件夹结构。区域可以在一定程度上提供帮助,尽管它们只会给你一个级别!

这可以使深层嵌套控制器层次结构的视图难以管理。您真正想要的是您的Views文件夹层次结构与控制器的命名空间层次结构相匹配。

好消息是,您可以轻松地编写自定义ViewEngine来完成此操作 - 请参阅我的ControllerPathViewEngine project on GitHub了解详细信息。

我已经包含了一个ControllerPathRazorViewEngine类的片段来概述它是如何工作的。通过拦截FindView / FindPartialView方法并用文件夹路径替换控制器名称(基于控制器命名空间和名称),我们可以让它从主视图文件夹中的嵌套文件夹加载视图。

    public class ControllerPathRazorViewEngine : RazorViewEngine
    {
        //... constructors etc.

        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            return FindUsingControllerPath(controllerContext, () => base.FindView(controllerContext, viewName, masterName, useCache));
        }

        public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        {
            return FindUsingControllerPath(controllerContext, () => base.FindPartialView(controllerContext, partialViewName, useCache));
        }

        private ViewEngineResult FindUsingControllerPath(ControllerContext controllerContext, Func<ViewEngineResult> func)
        {
            string controllerName = controllerContext.RouteData.GetRequiredString("controller");
            string controllerPath = controllerPathResolver.GetPath(controllerContext.Controller.GetType());
            controllerContext.RouteData.Values["controller"] = controllerPath;
            var result = func();
            controllerContext.RouteData.Values["controller"] = controllerName;
            return result;
        }
    }