如何在AspNetCore Web API中为每个端点提供可覆盖配置?
Asp.Net Core 中间件通过appsettings.json配置端点规则
问题描述
我有一个Asp.Net Core API中间件,原本通过特性(Attribute)获取配置,代码如下:
public class MyMiddleware: IMiddleware { public async Task InvokeAsync(HttpContext context, RequestDelegate next) { // 原本从特性获取配置,现在想改成从appsettings.json读取 var attribute = context.GetEndpoint()?.Metadata.GetMetadata<MyAttribute>(); if (attribute is not null) { // 执行对应逻辑 } await next(context); } }
特性模式的优势是可将特性置于动作方法、控制器类或基类上,中间件会自动选用最具体的配置,但缺点是修改配置必须重新构建并部署应用。
我希望将配置选项存储在appsettings.json中,通过通配规则匹配路径,示例配置如下:
{ "ConfigurationRules": [ { "Match": "/foo/**/bar", "Option1": "..." }, { "Match": "/foo", "Option1": "..." }, { "Match": "/**", "Option1": "..." } ] }
请问有没有内置或合理的方式,将这些配置映射到对应的端点?
实现方案
1. 定义配置模型
创建对应配置的实体类,用于绑定appsettings中的规则:
public class EndpointRule { public string Match { get; set; } public string Option1 { get; set; } // 可根据需求添加更多配置项 } public class MiddlewareConfig { public List<EndpointRule> ConfigurationRules { get; set; } = new(); }
2. 加载配置到依赖注入
在Program.cs中绑定配置并注入到DI容器:
var builder = WebApplication.CreateBuilder(args); // 绑定appsettings中的ConfigurationRules节点到模型 builder.Services.Configure<MiddlewareConfig>(builder.Configuration.GetSection("ConfigurationRules")); // 注册自定义中间件 builder.Services.AddTransient<MyMiddleware>(); // ...其他服务配置代码
3. 实现路径匹配与优先级处理
利用Asp.Net Core内置的RoutePattern和RouteMatcher实现路径匹配,同时封装一个匹配服务处理规则优先级(确保最具体的规则优先匹配):
public interface IEndpointRuleMatcher { EndpointRule? Match(HttpContext context); } public class EndpointRuleMatcher : IEndpointRuleMatcher { private readonly List<EndpointRule> _orderedRules; public EndpointRuleMatcher(IOptions<MiddlewareConfig> config) { // 按规则具体程度降序排序,确保精确匹配优先 _orderedRules = config.Value.ConfigurationRules .OrderByDescending(CalculateRuleSpecificity) .ToList(); } // 计算规则的具体程度,值越高优先级越高 private int CalculateRuleSpecificity(EndpointRule rule) { var segments = rule.Match.Split('/', StringSplitOptions.RemoveEmptyEntries); int specificity = 0; foreach (var segment in segments) { if (segment == "**") { // 全局通配符权重最低 specificity += 0; } else if (segment.Contains('*')) { // 部分通配符权重次之 specificity += 1; } else { // 精确路径段权重最高 specificity += 2; } } return specificity; } public EndpointRule? Match(HttpContext context) { var requestPath = context.Request.Path; foreach (var rule in _orderedRules) { var routePattern = RoutePatternFactory.Parse(rule.Match); var matcher = new RouteMatcher(routePattern); if (matcher.TryMatch(requestPath, out _)) { return rule; } } return null; } }
将匹配服务注册到DI:
builder.Services.AddSingleton<IEndpointRuleMatcher, EndpointRuleMatcher>();
4. 修改中间件使用配置
更新中间件,注入匹配服务获取对应规则:
public class MyMiddleware: IMiddleware { private readonly IEndpointRuleMatcher _ruleMatcher; public MyMiddleware(IEndpointRuleMatcher ruleMatcher) { _ruleMatcher = ruleMatcher; } public async Task InvokeAsync(HttpContext context, RequestDelegate next) { var matchedRule = _ruleMatcher.Match(context); if (matchedRule is not null) { // 使用matchedRule.Option1执行对应业务逻辑 } await next(context); } }
额外说明
- 动态配置重载:如果需要修改appsettings.json后无需重启应用生效,可以通过
IConfiguration.GetReloadToken()监听配置变化,重新加载规则列表。 - 匹配逻辑扩展:如果需要更复杂的匹配规则(如HTTP方法、主机头匹配),可以在
EndpointRule模型中添加对应属性,并在匹配方法中增加判断逻辑。
内容的提问来源于stack exchange,提问作者Bill Barry
相关产品推荐
相关产品推荐

