在ASP.Net MVC中处理手册式页面

时间:2013-02-18 21:32:43

标签: asp.net-mvc razor routing asp.net-mvc-routing

我已经建立了许多ASP.Net MVC网站,每个网站都有很多适合MVC控制器和动作的页面,还有一些页面实际上只是宣传册页面 - /为什么,/为什么/ ouradvantage,/ about等 - 没有真正功能的页面,只是一个视图,可能是一个布局,就是这样。

对于这些宣传册式的页面,我真的更喜欢只有View和一个很好的路线来找到它,所以我可以将/ why放在/Brochure/Why.cshtml或/Brochure/Why/Index.cshtml无论哪种方式,它都会被接受。我想避免使用愚蠢的控制器和动作(就像我过去一样)来处理这组URL和页面。

我如何在ASP.Net MVC项目中解决这个问题?这必须是一个普遍需要。

编辑:我如何以冗长的方式做到这一点的一个例子:

我可以使用标准MVC路由({controller} / {action} / {id})并向一堆无用的控制器发送垃圾邮件以获取我想要的URL和页面集。每次我想添加一个宣传册式(没有功能,只是一个View)页面时,我会添加一个Controller或Action,如下所示:

为什么选择控制器:

public class WhyController : Controller
{
    public ViewResult Index()
    {
        return View();
    }

    public ViewResult OurAdvantage()
    {
        return View();
    }
}

这会将View放在/ why和/ why / ouradvantage - 清除URL。如果我想要一个/ about页面,我可以添加另一个Controller,除了返回名为AboutController的View之外什么都不做。如果它有5个子页面,我可以向该控制器添加5个动作,所有这些动作除了返回视图外什么都不做。

如果MVC网站上的这些宣传册式的页面总共有100页,我会有相当多的不必要的控制器和动作都没有做任何事情。不是很干。我有兴趣将一个方法放在我的项目的一个文件夹中,并让它们可以访问(通过约定配置),干净的URL,如/ why和/ why / ouradvantage。

有几种让我接近的方法:

我可以放入一堆.cshtml页面并直接访问它们 - 但是我必须在URL中包含文件扩展名,而View文件本身必须位于根目录中。

我可以使用ASP.Net区域为这些区域定义区域,但是所有宣传册样式的页面必须至少包含一个URL段,我仍然存在URL中文件扩展名的上述问题。

我可以定义疯狂的路线。

我怀疑这种情况经常出现在拥有少量或大量这些宣传册式页面的MVC项目中 - 似乎应该有一个干净的方法来做到这一点。

编辑:一种破坏路由引擎的糟糕解决方案。

创建一个映射路径的类:

public static void MapRoutes(RouteCollection routes, string appRoot, string path)
{
    if (!path.Contains("~/"))
        throw new NotSupportedException("Pages path must be virtual (use ~/ syntax).");

    var physicalPath = appRoot + path.Substring(2).Replace("/", "\\");

    var dir = new DirectoryInfo(physicalPath);
    var pages = dir.GetFiles("*.cshtml", SearchOption.AllDirectories);

    int rootLength = appRoot.Length;
    var rootParsed = pages.Select(p => "~/" + p.FullName.Substring(rootLength).Replace("\\", "/"));
    int folderPathLength = path.Length + 1;

    var mapped = rootParsed.Select(p => new {
        Url = p.Substring(folderPathLength, p.Length - 7 - folderPathLength),
        File = p
    });

    var routedPages = mapped.Select(m => routes.MapRoute(
        name: m.Url,
        url: "{*url}",
        defaults: new { path = m.File, Controller = "Brochure", Action = "Catchall" },
        constraints: new { url = m.Url }
    )).ToArray();
}

你可以在RouteConfig中调用它,如:

BrochureRoute.MapRoutes(routes, Server.MapPath("~/"), "~/Brochure");

这显然将所有这些页面都映射到了一个您需要的BrochureController:

public class BrochureController : Controller
{
    public ViewResult Catchall(string path)
    {
        return View(path);
    }
}

2个问题:

  1. 如上所述,它会阻止路由引擎 - 如果你有100个页面就有100条路由。
  2. 如上所述传递路径似乎扰乱了正常的Razor管道 - 以这种方式访问​​页面会出现如下错误:
  3.   

    '〜/ Brochure / About.cshtml'的视图必须来自WebViewPage

2 个答案:

答案 0 :(得分:1)

要映射单个页面RouteCollection.MapPageRoute方法,可以使用。

routes.MapPageRoute("", "why", "~/Brochure/Why.aspx");

当然,您可以使用Razor视图引擎(.cshtml)而不是WebForms。

<德尔> Check MSDN documentation for some more details.


更新2

你是对的,你将无法将其用于.cshtml页面。但是,您不需要使用路由来访问网页(.cshtml文件)。它足以创建文件,并省略URL中的扩展名。要实现所需的结构,您可以这样做:

  • 您的网络项目必须允许网页呈现。要启用此功能,请转至web.config并将webpages.Enabled设置为true。 (<add key="webpages:Enabled" value="true" />
  • 在您的Web应用程序根目录中创建文件夹why
  • 添加名为Index.cshtml的MVC ViewPage。这可以从http://yoursite.com/why
  • 访问
  • 添加名为ouradvantages.cshtml的MVC ViewPage。这可以从http://yoursite.com/why/ouradvantages
  • 访问
  • 您还可以使用@UrlData集合
  • 访问网址数据

查看有关此here的详情。有关网页的更多信息is also available on asp.net website

如果由于某种原因您确实需要使用路由,则需要自定义RouteHandler。你可以find one implemented on Nuget。此程序包的用法示例为here


<强>更新

如果您想避免手动添加每条路线,则几乎没有选择。

1)创建一个公约以识别宣传册页

您可以通过默认将网址设为宣传页,并将“非宣传册”页面隔离到特定部分来实现此目的:

routes.MapPageRoute("Default", "{brochurepage}", "~/Brochure/{brochurepage}.aspx");
// isolate non-brochure pages to "site" section
routes.MapRoute(
    "",
    "site/{controller}/{action}/{id}",                      // URL with parameters
    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
);

2)在一个集合中保留宣传册页面名称

List<string> brochurePages = new List<string>()
{ "about", "why", "contact" }; // add more pages here
....
foreach (var brochurePage in brochurePages)
    routes.MapPageRoute("", brochurePage, "~/Brochure/" + brochurePage + ".aspx");

我必须非常具体地说明您在问题中提到的两个网址。要实现“/ why”和“/ why / ouradvantage”的路由,您将无法编写优雅的代码。这需要特殊处理。

答案 1 :(得分:0)

如果您的问题是您不希望为所有这些“愚蠢”的页面设置单独的控制器,我是否可以建议您创建一种逻辑方式将它们路由到单个控制器,然后基于正确的数据/视图呈现在路线上?

例如,您的网址可以显示为“/ Pages / Why / About”,您可以将其路由到您的网页控制器,它会收到“为什么”和“关于”作为参数,您可以相应地呈现您的内容。这有意义吗?