代码之家  ›  专栏  ›  技术社区  ›  Çağdaş Tekin

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

  •  2
  • Çağdaş Tekin  · 技术社区  · 16 年前

    我想在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.
    

    目标是为访问者和管理员分离URL。

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

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

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

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

    我的问题是,处理这种情况的最佳方法是什么,而URL的条件必须是这样的?

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

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

      • 我不知道该怎么做,但据我所知,这也能解决问题。
    • 使用 Areas Prototype 属于 Phil Haack ?

      • 这个文件夹实际上使用了不同的布局,但理论上这也应该有效。但我仍然不确定这是否是最好的方法,因为在站点的不同部分拥有不同的控制器和视图文件夹并不是我想要的。

    我倾向于自定义视图引擎的想法,在返回视图时考虑文件夹,但是就像我说的,我不知道如何做。

    有什么建议吗?

    2 回复  |  直到 11 年前
        1
  •  2
  •   eduncan911    16 年前

    尝试Phil Haack的/地区/为您的MVC项目: http://haacked.com/archive/2008/11/04/areas-in-aspnetmvc.aspx

    您将拥有普通内容的普通根目录,以及所有管理内容的特殊/areas/admin/section(URL将是/admin/)。

    alt text http://haacked.com/images/haacked_com/WindowsLiveWriter/36ef165d4ea4_ED92/areas-folder-structure_6.png

        2
  •  1
  •   Dan Malcolm    11 年前

    默认情况下,ASP.NET MVC使用平面视图文件夹结构。区域可以在一定程度上有所帮助,尽管它们只会给你多一个层次!

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

    好消息是,您可以编写一个自定义的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;
            }
        }