Ocelot网关授权扩展报错:Sequence contains no matching element 求助
问题根源
你遇到的Sequence contains no matching element异常,核心原因是你自己定义了IClaimsAuthoriser接口,但Ocelot框架内部注册的是它自身命名空间(Ocelot.Authorization)下的同名接口。你的扩展方法在查找服务时,找的是自定义的接口,而服务集合里根本没有这个注册项,自然会报错。
修复方案
1. 删掉自定义接口,使用Ocelot官方接口
直接移除你自己写的IClaimsAuthoriser,在代码里引用Ocelot自带的接口:
using Ocelot.Authorization; using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.Responses;
2. 调整装饰器类实现
把装饰器的依赖改成Ocelot的IClaimsAuthoriser,不要直接依赖具体实现ClaimsAuthorizer,更符合依赖倒置原则:
public class ClaimAuthorizerDecorator : IClaimsAuthoriser { private readonly IClaimsAuthoriser _innerAuthorizer; public ClaimAuthorizerDecorator(IClaimsAuthoriser innerAuthorizer) { _innerAuthorizer = innerAuthorizer; } public Response<bool> Authorise(ClaimsPrincipal claimsPrincipal, Dictionary<string, string> routeClaimsRequirement, List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues) { var newRouteClaims = new Dictionary<string, string>(); foreach (var kvp in routeClaimsRequirement) { if (kvp.Key.StartsWith("http///")) { newRouteClaims.Add(kvp.Key.Replace("http///", "http://"), kvp.Value); } else { newRouteClaims.Add(kvp.Key, kvp.Value); } } return _innerAuthorizer.Authorise(claimsPrincipal, newRouteClaims, urlPathPlaceholderNameAndValues); } }
3. 修正服务扩展方法
修改扩展方法,确保查找的是Ocelot的IClaimsAuthoriser,同时增加空判断避免意外:
using Ocelot.Authorization; using Microsoft.Extensions.DependencyInjection; using System.Linq; public static class ServiceCollectionExtensions { public static IServiceCollection DecorateClaimAuthoriser(this IServiceCollection services) { // 查找Ocelot注册的官方IClaimsAuthoriser服务 var descriptor = services.FirstOrDefault(x => x.ServiceType == typeof(IClaimsAuthoriser)); if (descriptor == null) { throw new InvalidOperationException("未找到Ocelot的IClaimsAuthoriser服务,请确认已调用AddOcelot方法"); } services.Remove(descriptor); // 将原实现注册为自身类型,方便装饰器依赖 services.Add(new ServiceDescriptor(descriptor.ImplementationType, descriptor.ImplementationType, descriptor.Lifetime)); // 注册装饰器,替换IClaimsAuthoriser的实现 services.Add(new ServiceDescriptor(typeof(IClaimsAuthoriser), sp => new ClaimAuthorizerDecorator(sp.GetRequiredService(descriptor.ImplementationType) as IClaimsAuthoriser), descriptor.Lifetime)); return services; } }
4. 保持Program.cs的调用顺序
确保AddOcelot先执行,再调用装饰方法,同时不要忘记添加Ocelot中间件:
builder.Services.AddOcelot(builder.Configuration); builder.Services.DecorateClaimAuthoriser(); var app = builder.Build(); // 启用Ocelot网关中间件 await app.UseOcelot(); app.Run();
补充提示
- 不要重复定义框架已有的接口,很容易出现命名冲突导致的服务查找失败问题。
- 依赖抽象而非具体实现,后续如果Ocelot更换默认授权器实现,你的代码无需修改就能兼容。
内容的提问来源于stack exchange,提问作者Niranjan
相关产品推荐
相关产品推荐

