在使用ASP.NET Core中的TemplateMatcher解決route template匹配字符串問題時(shí),遇到的一個(gè)新問題:匹配時(shí)忽略類型約束。我們將通過分析源代碼和查找相關(guān)線索,提供一種解決方案來解決這個(gè)問題。
引言
在使用ASP.NET Core開發(fā)Web應(yīng)用程序時(shí),我們經(jīng)常需要進(jìn)行URL路由的匹配。ASP.NET Core提供了TemplateMatcher類,它可以幫助我們實(shí)現(xiàn)route template與URL路徑的匹配。然而,在使用TemplateMatcher解決一些基本的route template匹配問題后,我們發(fā)現(xiàn)了一個(gè)新的問題:當(dāng)route template中包含類型約束(即inline constraint)時(shí),匹配過程會(huì)忽略這些類型約束。本文將介紹如何解決這個(gè)問題。
使用 TemplateMatcher 的實(shí)現(xiàn)代碼如下:
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是如何進(jìn)行路由匹配的。在TemplateMatcher的實(shí)現(xiàn)代碼中,我們可以看到它使用了TemplateParser來解析route template,并將解析結(jié)果傳遞給TemplateMatcher進(jìn)行匹配。然而,在TemplateParser.Parse方法返回的解析結(jié)果中,并沒有提供對類型約束的支持。
解決方案
通過查看ASP.NET Core的源代碼,我們發(fā)現(xiàn)在IntRouteConstraintsTests.cs#L22和ConstraintsTestHelper.cs#L8中有一些重要的線索,我們可以利用這些線索來解決這個(gè)問題。
首先,我們可以使用下面的代碼將TemplateParser.Parse方法返回結(jié)果中的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
從輸出結(jié)果中我們可以看到,InlineConstraints中包含了類型約束的信息。接下來,我們需要?jiǎng)?chuàng)建一個(gè)IRouteConstraint的實(shí)例,并將解析出的類型約束傳遞給它。我們可以使用以下代碼創(chuàng)建IRouteConstraint實(shí)例:
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
通過以上代碼,我們成功創(chuàng)建了一個(gè)IntRouteConstraint的實(shí)例。現(xiàn)在我們可以將這個(gè)實(shí)例用于匹配過程中。
接下來,我們可以使用以下代碼演示如何使用TemplateMatcher進(jìn)行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 = "http://www.zghlxwxcb.cn/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路徑,并正確應(yīng)用了類型約束。在第一個(gè)匹配的例子中,我們使用了"/{blogApp}/{postType}/{id:int}/{**slug}"的route template,其中id參數(shù)被指定為整數(shù)類型約束。在匹配過程中,我們可以看到IntRouteConstraint成功被應(yīng)用,并返回了匹配結(jié)果。
結(jié)論
通過分析源代碼和查找相關(guān)線索,我們成功解決了TemplateMatcher忽略類型約束的問題。我們使用DefaultInlineConstraintResolver創(chuàng)建了一個(gè)IRouteConstraint的實(shí)例,并將解析出的類型約束傳遞給它。這樣,在進(jìn)行URL路徑匹配時(shí),TemplateMatcher會(huì)正確應(yīng)用類型約束,從而得到準(zhǔn)確的匹配結(jié)果。
ASP.NET Core的TemplateMatcher是一個(gè)強(qiáng)大的工具,可以幫助我們處理URL路由的匹配。然而,在使用它時(shí),我們需要注意到一些潛在的問題,比如忽略類型約束。通過本文提供的解決方案,我們能夠充分利用TemplateMatcher的功能,并確保類型約束得到正確應(yīng)用。文章來源:http://www.zghlxwxcb.cn/article/681.html
注意
以上代碼僅為示例,可能需要根據(jù)您的實(shí)際需求進(jìn)行適當(dāng)修改。
可以參考以下資料:文章來源地址http://www.zghlxwxcb.cn/article/681.html
[Stack Overflow](stackoverflow.com) [Microsoft Documentation](docs.microsoft.com/en-us/aspnet/core/?view=aspnetcore-5.0)
到此這篇關(guān)于ASP.NET Core: TemplateMatcher 忽略類型約束問題的解決方法的文章就介紹到這了,更多相關(guān)內(nèi)容可以在右上角搜索或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!