我想在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")
返回我想要的视图。但这显然不是一个好的解决方案,我不想这样做。
我的问题是,处理这种情况的最佳方法是什么,网址必须是这样的?
创建一个自定义控制器类来覆盖视图方法(或为此目的需要覆盖的任何其他方法),并确保返回正确的视图?
创建一个也考虑文件夹的自定义视图引擎?
我倾向于自定义视图引擎的想法,在返回视图时会考虑文件夹,但就像我说的那样,我不知道该怎么做。
有什么建议吗?
答案 0 :(得分:2)
为你的MVC项目试用Phil Haack的/ Areas /:http://haacked.com/archive/2008/11/04/areas-in-aspnetmvc.aspx
你的普通内容有正常的Root,你的所有管理员都有特殊的/ Areas / Admin /部分(而url将是/ admin /)。
(来源: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;
}
}