ASP.NET Core: TemplateMatcher 忽略类型约束问题的解决方法

18,017次阅读
没有评论

共计 5120 个字符,预计需要花费 13 分钟才能阅读完成。

在使用 ASP.NET Core 中的 TemplateMatcher 解决 route template 匹配字符串问题时,遇到的一个新问题:匹配时忽略类型约束。我们将通过分析源代码和查找相关线索,提供一种解决方案来解决这个问题。

ASP.NET Core

引言

在使用 ASP.NET Core 开发 Web 应用程序时,我们经常需要进行 URL 路由的匹配。ASP.NET Core 提供了 TemplateMatcher 类,它可以帮助我们实现 route template 与 URL 路径的匹配。然而,在使用 TemplateMatcher 解决一些基本的 route template 匹配问题后,我们发现了一个新的问题:当 route template 中包含类型约束(即 inline constraint)时,匹配过程会忽略这些类型约束。本文将介绍如何解决这个问题。

使用 TemplateMatcher 的实现代码如下:

var routeTemplate = TemplateParser.Parse(template);                
var values = new RouteValueDictionary();
var matcher = new TemplateMatcher(routeTemplate, values);
if (matcher.TryMatch(path, values))
{return new KeyValuePair(template, values);
}

分析

我们首先需要了解 TemplateMatcher 是如何进行路由匹配的。在 TemplateMatcher 的实现代码中,我们可以看到它使用了 TemplateParser 来解析 route template,并将解析结果传递给 TemplateMatcher 进行匹配。然而,在 TemplateParser.Parse 方法返回的解析结果中,并没有提供对类型约束的支持。

解决方案

通过查看 ASP.NET Core 的源代码,我们发现在 IntRouteConstraintsTests.cs#L22 和 ConstraintsTestHelper.cs#L8 中有一些重要的线索,我们可以利用这些线索来解决这个问题。

首先,我们可以使用下面的代码将 TemplateParser.Parse 方法返回结果中的 InlineConstraints 打印出来:

var routeTemplate = "/{blogApp}/{postType}/{id:int}/{**slug}";
var parsedTemplate = TemplateParser.Parse(routeTemplate);
var values = new RouteValueDictionary();
foreach (var parameter in parsedTemplate.Parameters)
{foreach (var inlineConstraint in parameter.InlineConstraints)
    {Console.WriteLine(parameter.Name + ":" + inlineContraint.Constraint);
    }
}

输出:

id:int

从输出结果中我们可以看到,InlineConstraints 中包含了类型约束的信息。接下来,我们需要创建一个 IRouteConstraint 的实例,并将解析出的类型约束传递给它。我们可以使用以下代码创建 IRouteConstraint 实例:

IServiceCollection services = new ServiceCollection();
services.AddOptions();
using ServiceProvider sp = services.BuildServiceProvider();
var routeOptions = sp.GetRequiredService>();
var constraintResolver = new DefaultInlineConstraintResolver(routeOptions, sp);

var routeConstraint = constraintResolver.ResolveConstraint(inlineContraint.Constraint);
Console.WriteLine(routeContraint);

输出:

Microsoft.AspNetCore.Routing.Constraints.IntRouteConstraint

通过以上代码,我们成功创建了一个 IntRouteConstraint 的实例。现在我们可以将这个实例用于匹配过程中。

接下来,我们可以使用以下代码演示如何使用 TemplateMatcher 进行 URL 路径的匹配,并考虑到类型约束:

using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Template;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

var routeTemplates = new[]
{"/{blogApp}/{postType}/{id:int}/{**slug}",
    "/{blogApp}/{postType}/{idOrSlug}.html"
};

var url = "https://www.toymoban.com/diary/problem/681.html";
var urlPath = new Uri(url).AbsolutePath;

IServiceCollection services = new ServiceCollection();
services.AddOptions();
using ServiceProvider sp = services.BuildServiceProvider();
var routeOptions = sp.GetRequiredService>();
var constraintResolver = new DefaultInlineConstraintResolver(routeOptions, sp);

foreach (string routeTemplate in routeTemplates)
{Console.WriteLine("routeTemplate:" + routeTemplate);
    var parsedTemplate = TemplateParser.Parse(routeTemplate);

    var values = new RouteValueDictionary();
    var matcher = new TemplateMatcher(parsedTemplate, values);
    if (matcher.TryMatch(urlPath, values))
    {Console.WriteLine("TemplateMatcher matched: true");
        foreach (var item in values)
        {Console.WriteLine("{0}: {1}", item.Key, item.Value);
        }

        foreach (var parameter in parsedTemplate.Parameters)
        {foreach (var inlineConstraint in parameter.InlineConstraints)
            {Console.WriteLine(parameter.Name + ":" + inlineConstraint.Constraint);

                var routeConstraint = constraintResolver.ResolveConstraint(inlineConstraint.Constraint);
                var routeDirection = RouteDirection.IncomingRequest;
                bool matched = routeConstraint!.Match(httpContext: null, route: null, parameter.Name!, values, routeDirection);

                Console.WriteLine($"{routeConstraint.GetType().Name} matched: {matched}");
                Console.WriteLine();}
        }
    }
}

输出:

routeTemplate: /{blogApp}/{postType}/{id:int}/{**slug}
TemplateMatcher matched: true
blogApp: diary
postType: problem
id: 681.html
slug:
id:int
IntRouteConstraint matched: False

routeTemplate: /{blogApp}/{postType}/{idOrSlug}.html
TemplateMatcher matched: true
blogApp: diary
postType: problem
idOrSlug: 681.html

通过以上代码,我们可以看到 TemplateMatcher 成功匹配了 URL 路径,并正确应用了类型约束。在第一个匹配的例子中,我们使用了 ”/{blogApp}/{postType}/{id:int}/{**slug}” 的 route template,其中 id 参数被指定为整数类型约束。在匹配过程中,我们可以看到 IntRouteConstraint 成功被应用,并返回了匹配结果。

结论

通过分析源代码和查找相关线索,我们成功解决了 TemplateMatcher 忽略类型约束的问题。我们使用 DefaultInlineConstraintResolver 创建了一个 IRouteConstraint 的实例,并将解析出的类型约束传递给它。这样,在进行 URL 路径匹配时,TemplateMatcher 会正确应用类型约束,从而得到准确的匹配结果。

ASP.NET Core 的 TemplateMatcher 是一个强大的工具,可以帮助我们处理 URL 路由的匹配。然而,在使用它时,我们需要注意到一些潜在的问题,比如忽略类型约束。通过本文提供的解决方案,我们能够充分利用 TemplateMatcher 的功能,并确保类型约束得到正确应用。

注意

以上代码仅为示例,可能需要根据您的实际需求进行适当修改。

可以参考以下资料: 文章来源地址 https://www.toymoban.com/diary/problem/681.html

[Stack Overflow](stackoverflow.com)
[Microsoft Documentation](docs.microsoft.com/en-us/aspnet/core/?view=aspnetcore-5.0)

到此这篇关于 ASP.NET Core: TemplateMatcher 忽略类型约束问题的解决方法的文章就介绍到这了, 更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持 TOY 模板网!

原文地址:https://www.toymoban.com/diary/problem/681.html

如若转载,请注明出处:如若内容造成侵权 / 违法违规 / 事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于1970-01-01发表,共计5120字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)