在使用ASP.NET Core中的TemplateMatcher解决route template匹配字符串问题时,遇到的一个新问题:匹配时忽略类型约束。我们将通过分析源代码和查找相关线索,提供一种解决方案来解决这个问题。
引言
在使用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
注意
以上代码仅为示例,可能需要根据您的实际需求进行适当修改。
可以参考以下资料:文章来源地址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模板网!