为什么在 asp.net mvc 中先映射特殊路由,然后再映射普通路由?

2023-12-02

来自www:

...路由引擎将采用与所提供的 URL 匹配的第一个路由,并尝试使用该路由中的路由值。因此,应首先将不太常见或较专业的路由添加到表中,而应稍后添加更通用的路由......

为什么要先绘制专门的路线?有人可以给我一个例子,我可以在哪里看到“首先映射公共路线”的失败吗?


路由引擎将采用与所提供的 URL 匹配的第一个路由,并尝试使用该路由中的路由值。

出现这种情况的原因是因为RouteTable像 switch-case 语句一样使用。如下图所示:

int caseSwitch = 1;
switch (caseSwitch)
{
    case 1:
        Console.WriteLine("Case 1");
        break;
    case 1:
        Console.WriteLine("Second Case 1");
        break;
    default:
        Console.WriteLine("Default case");
        break;
}

If caseSwitch is 1,第二个块永远不会到达,因为第一个块捕获了它。

Route类遵循类似的模式(在GetRouteData and GetVirtualPath方法)。他们可以返回 2 种状态:

  1. 一组路由值(或VirtualPath对象的情况下GetVirtualPath)。这表明路由与请求匹配。
  2. null。这表明路由与请求不匹配。

在第一种情况下,MVC 使用路由生成的路由值来查找Action方法。在这种情况下,RouteTable不再进一步分析。

在第二种情况下,MVC 将检查下一个Route in the RouteTable查看它是否与请求匹配(内置行为与 URL 和约束匹配,但从技术上讲,您可以匹配 HTTP 请求中的任何内容)。再一次,该路由可以返回一组RouteValues or null取决于结果。

如果您尝试使用上面的 switch-case 语句,程序将无法编译。但是,如果您配置的路由never回报null或返回一个RouteValues在超过应有的情况下,程序可以编译,但会出现错误。

错误配置示例

这是我经常在 StackOverflow(或其某些变体)上看到的经典示例:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "CustomRoute",
            url: "{segment1}/{action}/{id}",
            defaults: new { controller = "MyController", action = "Index", id = UrlParameter.Optional }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

在这个例子中:

  1. CustomRoute将匹配长度为 1、2 或 3 段的任何 URL(请注意segment1是必需的,因为它没有默认值)。
  2. Default将匹配长度为 0、1、2 或 3 段的任何 URL。

因此,如果应用程序传递 URL\Home\About, the CustomRoute将匹配,并提供以下内容RouteValues to MVC:

  1. segment1 = "Home"
  2. controller = "MyController"
  3. action = "About"
  4. id = {}

这将使 MVC 寻找名为的操作About在名为的控制器上MyControllerController,如果不存在就会失败。这Default在这种情况下,route 是无法访问的执行路径,因为即使它将匹配 2 段 URL,框架也不会给它机会,因为第一个匹配获胜。

修复配置

有关如何继续修复配置的选项有多种。但所有这些都取决于行为第一场比赛获胜然后路由就不会再查找了。

选项 1:添加一个或多个文字段

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "CustomRoute",
            url: "Custom/{action}/{id}",

            // Note, leaving `action` and `id` out of the defaults
            // makes them required, so the URL will only match if 3
            // segments are supplied begining with Custom or custom.
            // Example: Custom/Details/343
            defaults: new { controller = "MyController" }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

选项 2:添加 1 个或多个正则表达式约束

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "CustomRoute",
            url: "{segment1}/{action}/{id}",
            defaults: new { controller = "MyController", action = "Index", id = UrlParameter.Optional },
            constraints: new { segment1 = @"house|car|bus" }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

选项 3:添加 1 个或多个自定义约束

public class CorrectDateConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        var year = values["year"] as string;
        var month = values["month"] as string;
        var day = values["day"] as string;

        DateTime theDate;
        return DateTime.TryParse(year + "-" + month + "-" + day, System.Globalization.CultureInfo.InvariantCulture, DateTimeStyles.None, out theDate);
    }
}

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "CustomRoute",
            url: "{year}/{month}/{day}/{article}",
            defaults: new { controller = "News", action = "ArticleDetails" },
            constraints: new { year = new CorrectDateConstraint() }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

选项 4:制作Required路段 + 使路段数量与现有路线不匹配

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "CustomRoute",
            url: "{segment1}/{segment2}/{action}/{id}",
            defaults: new { controller = "MyController" }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

在上述情况下,CustomRoute只会匹配具有 4 个段的 URL(注意这些可以是任何值)。这Default与之前一样,route 仅匹配具有 0、1、2 或 3 段的 URL。因此不存在不可达的执行路径。

选项 5:为自定义行为实现 RouteBase(或路由)

路由不支持开箱即用的任何操作(例如特定域或子域上的匹配)都可以通过以下方式完成实施你自己的RouteBase子类或路线子类。这也是了解路由如何/为何如此工作的最佳方式。

public class SubdomainRoute : Route
{
    public SubdomainRoute(string url) : base(url, new MvcRouteHandler()) {}

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var routeData = base.GetRouteData(httpContext);
        if (routeData == null) return null; // Only look at the subdomain if this route matches in the first place.
        string subdomain = httpContext.Request.Params["subdomain"]; // A subdomain specified as a query parameter takes precedence over the hostname.
        if (subdomain == null) {
            string host = httpContext.Request.Headers["Host"];
            int index = host.IndexOf('.');
            if (index >= 0)
                subdomain = host.Substring(0, index);
        }
        if (subdomain != null)
            routeData.Values["subdomain"] = subdomain;
        return routeData;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        object subdomainParam = requestContext.HttpContext.Request.Params["subdomain"];
        if (subdomainParam != null)
            values["subdomain"] = subdomainParam;
        return base.GetVirtualPath(requestContext, values);
    }
}

该类借用自:是否可以基于子域创建 ASP.NET MVC 路由?

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.Add(new SubdomainRoute(url: "somewhere/unique"));

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

NOTE:这里真正的问题是大多数人认为他们的路线都应该像Default路线。复制、粘贴,完成吧?错误的。

这种方法通常会出现两个问题:

  1. 几乎所有其他路线都应该至少有一个字面段(如果您喜欢这类事情,则应有一个约束)。
  2. 最合乎逻辑的行为通常是使其余路由具有required段。

另一个常见的误解是可选部分意味着您可以省略any段,但实际上您只能省略最右边的一个或多个段。

Microsoft 成功地使路由基于约定、可扩展且功能强大。他们未能使其直观易懂。几乎每个人第一次尝试都会失败(我知道我失败了!)。幸运的是,一旦你理解了它是如何工作的,这并不是很困难。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么在 asp.net mvc 中先映射特殊路由,然后再映射普通路由? 的相关文章

  • 从基本控制器继承 LINQ-to-SQL 数据上下文

    我的基本控制器类 BaseController 由面向公众的控制器继承 用于使用 LINQ to SQL 访问请求之间的共享数据上下文 我是否可以通过将数据存储在中来以高效且安全的方式访问我的数据上下文HttpContext Current
  • 当前上下文中不存在名称“DefaultAuthenticationTypes”

    我正在尝试在我的 Web 应用程序中实现基于角色的授权 如下所示 HttpPost ActionName Login public ActionResult Login LoginViewModel model if ModelState
  • Asp.net身份验证错误

    我想将 IdentityContext 与 mydbcontext 集成 但出现此错误 在模型生成过程中检测到一个或多个验证错误 Ivdb Dal Concrete EFCodeFirst IdentityUserLogin EntityT
  • 如何获取 ASP.NET MVC 中当前的虚拟路径?

    如何从 ASP NET MVC 视图中获取当前路径 URL 如果没有办法将其获取到视图中 那么如何将其获取到控制器中以便将其传递到视图呢 EDIT 我不需要 url 的协议和主机部分 这将为您返回视图中的 url
  • C# 查询两个数据库的数据

    我目前有一个查询 我正在从两个不同的数据库获取数据 这些数据被附加到一个名为 accountbuys 的列表中 我的第一个表有三个数据条目 3个想要购买股票的帐户 下一张表有 17 个数据点 购买 17 只股票 I am merging t
  • 多行有多个提交按钮,我应该为每个按钮制作一个表单吗?

    我列出了大约 20 行 每行代表一个订单 每行需要有 3 个按钮 每个按钮单击将执行不同的操作 我有 3 个操作来处 理每个按钮发布请求 我只是不确定如何为每个按钮设置 Html 表单 tr td td tr
  • SignalR 的浏览器兼容性如何?

    我在网上找到的最多的是 SignalR FAQ 其中指出 SignalR 在 IE6 7 中不起作用 但是 出于法律原因 我需要向客户提供受支持的浏览器列表 SignalR 有这样的经过测试的浏览器列表吗 Thanks 看起来微软已经发布了
  • MVC Html.Partial 或 Html.Action

    我是 ASP NET MVC 新手 所以请耐心等待 我需要构建一个在多个视图中重复的菜单 什么可以更好地服务于目的Html Action http msdn microsoft com en us library ee703423 aspx
  • Visual Studio 2015 - Web 项目上缺少共享项目参考选项卡

    我从 MSDN 订阅升级到 Visual Studio 2015 因为我非常兴奋地阅读有关共享项目的信息 当我们想要做的只是重用代码时 不再需要在依赖项中管理 21382 个 nuget 包 所以我构建了一个测试共享项目 其中包含一些代码
  • 如何分配Profile值?

    我不知道我缺少什么 但我在 Web config 文件中添加了 Profile 属性 但无法访问 Profile Item在代码中或创建一个新的配置文件 我今天也遇到了同样的问题 学到了很多东西 Visual Studio 中有两种项目 网
  • 如何在 MVC 3 中基于 XML 文件动态创建控件

    我有一个以 XML 格式存储在数据库中的 XML 文件 其中包含一些控件 例如下拉文本框 标签文本区域等 这些控件可能有也可能没有初始值 所以我的目标是读取 XML 文件 并根据控件类型 我需要动态创建该控件并关联初始值 如果有 并且页面的
  • 如何检查 MVC cshtml 页面中的调试模式

    如何检查 MVC cshtml 页面中的调试模式 此代码在 cshtml 页面中不起作用 bool isRelease false if DEBUG isRelease false else isRelease true endif if
  • ASP.NET MVC 视图引擎解析顺序

    我创建了一个简单的 ASP NET MVC 1 0 版应用程序 我有一个 ProductController 它有一个操作索引 在视图中 我在Product子文件夹下创建了相应的Index aspx 然后我引用了 Spark dll 并在同
  • MVC3 中定义路由的文件

    我有这个文件
  • .NET ServiceModel.Syndicate - 更改 RSS 源的编码

    我正在尝试解决我在以下位置生成的所有 RSS 源的错误http captainobvio us http captainobvio us在 Internet Explorer 版本 8 和 9 中产生以下错误 进给代码错误 从当前切换 编码
  • ASP.NET 视图中的区域?

    我正在使用 razor 引擎制作 ASP NET MVC 应用程序 我想知道是否可以使用Regions http msdn microsoft com en us library 9a1ybwek aspx在一个视图中 就像是 region
  • MVC4 - ContextDependentView - 是什么意思?

    我刚刚开始使用 MVC4 我看到的第一个操作方法有一些新内容 我查了一下互联网 找不到任何关于此的信息 public ActionResult LogOn return ContextDependentView 有谁知道 ContextDe
  • 从 AuthorizeAttribute 继承的属性不起作用

    我目前正在尝试根据用户角色在新的 ASP MVC 5 应用程序中实现安全性 目标是防止用户在没有特定角色 或更高角色 的情况下访问某些控制器或控制器方法 根据到目前为止我所读到的问题 我创建了一个继承 AuthorizeAttribute
  • 保护 ASP.NET MVC 应用程序中的 ajax 调用的安全

    我有一个基于 ASP NET MVC 的应用程序 它允许根据用户进行不同级别的访问 当前的工作方式是 当用户访问页面时 会根据数据库进行检查以确定用户拥有的权限 然后根据用户拥有的访问级别选择视图 有些用户比其他用户看到更多数据并拥有更多可
  • MVC ASP.NET 或 Razor

    我对 MVC 很陌生 我对 Silver light WPF 和 MVVM 有相当多的了解 但对 MVC 知之甚少 我正在按照 Microsoft 网站上的主要教程进行操作http www asp net mvc tutorials get

随机推荐

  • python中的零填充右移

    function e t return e lt lt t e gt gt gt 32 t 我在js中有这个方法 我对移位操作不太了解 我想用 python 写这个 我如何在 python 中编写等效代码 因为它不支持JS 中的零填充右移运
  • 使用具有非标准端口的远程存储库

    我正在为远程存储库设置本地 git 项目 远程存储库正在非标准端口 4019 上提供服务 但这不起作用 相反 我收到以下错误消息 ssh connect to host git host de 4019 port 22 Connection
  • Whatsapp 和 Viber 使用哪些机制进行聊天和消息传递

    我正在搜索有关 Whatsapp 和 Viber 的一些信息 他们通过 VOIP 提供免费通话 短信和聊天功能 任何人都可以确定这两个应用程序使用哪种机制 意味着聊天使用了哪种协议以及其他详细信息 以及任何其他可能有助于创建此类聊天应用程序
  • 更改带有选项卡的接受按钮

    我有一个用 C 编写的 Windows 窗体应用程序 它有三个选项卡 我希望接受按钮随活动选项卡一起更改 就像当我在选项卡 1 中时 我希望按钮 1 成为接受按钮 但当我在选项卡 3 中时 我希望按钮 3 成为我的接受按钮 我不知道如何做到
  • 如何为networkD3的sankeyNetwork中的组着色?

    我的节点由名称和组组成 但我似乎无法在桑基图中为组实现不同的颜色 默认颜色为全蓝色 或者使用下面的代码为全黑色 这是我使用的代码 sankeyNetwork Links data links Nodes data nodes Source
  • Android Java UTF-8 JSON

    我的应用程序的一部分在 mysql 数据库上执行查询 通过 php 我在数据库中使用 UTF 8 因为我有像 这样的字母需要出现 我通读了这个问题 因为这看起来几乎是一样的 Android Java UTF 8 HttpClient 问题
  • RMarkdown 自动锚定部分

    嗯 我使用 Markdown 已经一年了 今天突然在标题旁边自动添加了一个 a 标签 有人会知道为什么这些锚点是自动生成的以及我如何删除它们 Pd 解决这个问题的一种方法是使用h1 h2等 但是随着pdf输出 索引被消除 所以它并不能真正解
  • 检查字符串中是否包含对象值的任何部分

    我有一个看起来像这样的字符串 link to page foo bar test 1 另外我有一个看起来像这样的对象 key foo bar test false mock data 我想要实现的事情相当简单 我认为 但也许我在这里错过了显
  • 在 IIS 7.5 中部署 MVC3 - 不断收到 CS1009: 无法识别的转义序列错误消息

    我不断得到 Line 43 public override void Execute Line 44 WriteLiteral Line 45 Line 46 Source File c Windows Microsoft NET Fram
  • 如何在 Spring 中使用列表作为模型属性?

    我的家庭控制器是这样的 RequestMapping public ModelAndView welcome ModelAttribute myValuesInRows List
  • FolderItem.InvokeVerb("Delete") 无需确认

    我正在尝试编写一个工具 该工具将自动存档服务器上的旧日志文件并从存档中删除太旧的文件 并且有问题 我需要使用 powershell 从 ZIP 存档中删除单个文件 所以我这样做 testFile C test logs FirstEntry
  • Avaje - EBean - 部分对象查询禁用延迟加载

    我正在使用 Play 开发一个应用程序 框架 2 1 3 使用 EBean 作为模型层我希望能够执行部分对象查询 并且当我序列化为 JSON 准备将结果发送回用户时 不要按需延迟加载未选择的属性 我尝试将 AutoFetch 设置为 fal
  • 无法在 Rmarkdown 报告中生成交互式绘图

    我有一个 Rmarkdown 文档 其中包含用plotly绘制的图 并且想生成一个html文件 当我点击时它起作用编织为 HTML在 Rstudio 中 但当我在命令行上运行以下命令时则不然 Rscript e require knitr
  • 为什么这个 Less 表达式根据数学运算而成为语法错误?

    我有以下 Less 片段 Foo 50px someClass width calc 100 Foo 5px 这很好用 但是 如果我将其更改为 Foo 50px someClass width calc 100 Foo 5px 我们现在有一
  • 如何测试是否已获得管理员同意

    我们正在开发一个 Office 加载项 可使用 Azure AD 的组织帐户进行身份验证 该加载项需要管理同意 因此 如果管理员登录 应引导他表达管理同意 我们使用 OAuth 进行身份验证 https login microsoftonl
  • Mysql事务:提交和回滚

    我将 PhpMyAdmin 数据库引擎从 MyISAM 更新为 INNODB 以允许回滚 这是我的 SQL 查询 START TRANSACTION UPDATE jkm content SET state 0 WHERE title IN
  • 在 Android 中动态加载 .dex 文件时出现“ClassNotFound”异常

    我正在尝试学习在 Android 中动态加载类 dex jar 我从教程和 Stack Overflow 问题中收集了基本想法 tutorial this and this 但我未能实现动态加载类文件并不断给出的目的ClassNotFoun
  • 我应该设置什么 COLLATE 才能使用所有可能的语言?

    我有一个专栏叫username 我希望用户能够插入日语 罗马语 阿拉伯语 韩语以及所有可能的文本 包括特殊字符 https en wiktionary org wiki Index All languages what COLLATE我应该
  • 在 Lua 中使用 32 位按位运算比较有符号的 64 位数字

    我在 Redis 上使用 Lua 想要比较两个有符号的 64 位数字 它们存储在两个 8 字节 字符的字符串中 如何使用 Redis 中可用的库来比较它们 http redis io commands EVAL available libr
  • 为什么在 asp.net mvc 中先映射特殊路由,然后再映射普通路由?

    来自www 路由引擎将采用与所提供的 URL 匹配的第一个路由 并尝试使用该路由中的路由值 因此 应首先将不太常见或较专业的路由添加到表中 而应稍后添加更通用的路由 为什么要先绘制专门的路线 有人可以给我一个例子 我可以在哪里看到 首先映射