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

在使用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<string, RouteValueDictionary>(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<RouteOptions>();
using ServiceProvider sp = services.BuildServiceProvider();
var routeOptions = sp.GetRequiredService<IOptions<RouteOptions>>();
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<RouteOptions>();
using ServiceProvider sp = services.BuildServiceProvider();
var routeOptions = sp.GetRequiredService<IOptions<RouteOptions>>();
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/article/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/article/681.html

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

领支付宝红包赞助服务器费用

相关文章

    系统发生错误

    系统发生错误

    您可以选择 [ 重试 ] [ 返回 ] 或者 [ 回到首页 ]

    [ 错误信息 ]

    页面错误!请稍后再试~

    Tob