1、问题
最近将一个.net framework api 项目迁移到net core 3.1。其中有两个action是重载的,方法参数个数不一样。在.net framework下会自动根据请求参数个数进行路由匹配,但是在.net core3.1 下会报【The request matched multiple endpoints】异常。
2、问题查找
异常的原因在于匹配的多个节点路由。遇到此问题我的第一反映,我重写匹配endpoints相关方法不就行了。带着这个思路我开始看相关的源码,看其是如何进行endpoints注册和匹配的。
相关注册源码地址:
https://github.com/aspnet/Routing/blob/master/src/Microsoft.AspNetCore.Routing/Builder/EndpointRoutingApplicationBuilderExtensions.cs
https://github.com/dotnet/aspnetcore/blob/c925f99cddac0df90ed0bc4a07ecda6b054a0b02/src/Mvc/Mvc.Core/src/Builder/ControllerEndpointRouteBuilderExtensions.cs
https://github.com/dotnet/aspnetcore/blob/c925f99cddac0df90ed0bc4a07ecda6b054a0b02/src/Mvc/Mvc.Core/src/Routing/ControllerActionEndpointDataSourceFactory.cs#L10
顺着代码看下GetRequiredService中都是实体类已经类是internal。这注册相关的代码好像不太好重写。
那只能看匹配的相关代码试试。
匹配相关源码地址:
https://github.com/aspnet/Routing/blob/c28c7dea4e866ec5a0d33f0e290bc49baadb1c85/src/Microsoft.AspNetCore.Routing/EndpointRoutingMiddleware.cs
https://github.com/aspnet/Routing/blob/c28c7dea4e866ec5a0d33f0e290bc49baadb1c85/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcherFactory.cs#L9
在DfaMatcherFactory中有一段代码:
1 public override Matcher CreateMatcher(EndpointDataSource dataSource) 2 { 3 if (dataSource == null) 4 { 5 throw new ArgumentNullException(nameof(dataSource)); 6 } 7 8 return new DataSourceDependentMatcher(dataSource, () => 9 { 10 return _services.GetRequiredService<DfaMatcherBuilder>(); 11 }); 12 }
看着可以重写MatcherFactory对应的实现来达到目的。但是写完不知道对默认实现有没有影响,需要大量测试,有点耗时间。准备找另外一种解决方法。
3、另一种思路
既然重写有点耗时,那如果把已经注册好的endpoints中影响匹配的endpoint删掉不就行了。在源码中可以看到,endpoint都是放在EndpointDataSource中。
4、问题解决
在app.UseEndpoints(endpoints => 中的endpoints 有一个DataSources属性,类型是ICollection<EndpointDataSource>实际类型是List。遍历DataSource中Endpoints,找到需要删除的endpoint,然后将其删除即可。然后使用MapWhen单独注册这连个action路由即可。
5、net 5 下问题再现
在将.net core 3.1 发布到线上后。准备将项目升级到.net 5。在升级到.net 5后,那两个接口再请求时候再次报【The request matched multiple endpoints】。翻看官方.net core 升级.net 5 文档,上面也没有提endpoint相关逻辑修改。我只能进行调试,看看Startup.Configure中UseEndpoints有什么变化。经过仔细对比发现MapWhen中endpoints.DataSources有变化。只能再次修改MapWhen中endpoints.DataSources将问题解决
6、最后
上面的解决方法不怎么优雅,下面有空还是找找重写EndpointRoutingMiddleware中相关代码来进行实现。各位大神有什么好的方法也可以评论一下。