1

我已经建立了许多 ASP.Net MVC 站点,每个站点中都有许多适合 MVC 控制器和操作的页面,以及一些实际上只是小册子页面的页面 - /why、/why/ouradvantage、 /about 等 - 没有真正功能的页面,只是一个视图,也许是一个布局,仅此而已。

对于这些小册子风格的页面,我真的更喜欢只有 View 和一个很好的 Route 来找到它,所以我可以把 /why 放在 /Brochure/Why.cshtml 或 /Brochure/Why/Index.cshtml 或者任何一种方式它会被捡起来的。我想避免制作愚蠢的控制器和动作(就像我过去所做的那样)来处理这组 URL 和页面。

如何在 ASP.Net MVC 项目中解决这个问题?这一定是一个共同的需求。

编辑:我如何以详细方式执行此操作的示例:

我可以使用标准的 MVC 路由 ({controller}/{action}/{id}) 并发送一堆无用的控制器来获取我想要的 URL 和页面集。每次我想添加一个小册子样式(没有功能,只是一个视图)页面时,我都会添加一个控制器或操作,如下所示:

为什么控制器:

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

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

这会在 /why 和 /why/ouradvantage 放置一个视图 - 干净的 URL。如果我想要一个 /about 页面,我可以添加另一个控制器,它只返回一个名为 AboutController 的视图。如果它有 5 个子页面,我可以向该控制器添加 5 个动作,所有这些动作都只返回一个视图。

如果 MVC 站点中这些小册子式的页面总计 100 页,那么我将有相当多的无用的控制器和动作,它们实际上什么都不做。不是很干。我对一种将视图放在我的项目中的文件夹中并让它们访问的方法很感兴趣(通过约定配置),在干净的 URL 上,如 /why 和 /why/ouradvantage。

有几种方法可以让我接近:

我可以放入一堆 .cshtml 页面并直接访问它们——但是我必须在 URL 中有文件扩展名,并且视图文件本身必须位于根目录中。

我可以使用 ASP.Net 区域为这些定义一个区域,但是所有小册子样式的页面都必须至少位于一个 URL 段深处,并且我仍然遇到上述 URL 中文件扩展名的问题。

我可以定义一些疯狂的路线。

我怀疑这经常出现在具有少量或大量这些 Brochure 样式页面的 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 管道 - 以这种方式访问​​页面会导致错误,例如:

'~/Brochure/About.cshtml' 的视图必须从 WebViewPage 派生

4

2 回答 2

1

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

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

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

查看 MSDN 文档以获取更多详细信息。


更新 2

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

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

在这里查看更多信息。更多关于一般网页的信息也可以在 asp.net 网站上找到

如果出于某种原因您确实需要使用路由,则需要自定义 RouteHandler。您可以找到在 Nuget 上实现的一个。这个包的使用例子在这里


更新

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

1)创建一个约定来识别小册子页面

您可以通过默认情况下将 URL 视为小册子页面并将“非小册子”页面隔离到特定部分来做到这一点:

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");

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

于 2013-02-18T21:40:39.580 回答
0

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

例如,您的 URL 可以读取“/Pages/Why/About”,您可以将其路由到您的页面控制器,它会接收“Why”和“About”作为参数,您可以相应地呈现您的内容。那有意义吗?

于 2013-02-18T21:52:24.437 回答