FileShare/FileShare-Services/Core/ServiceEndpointPatternMatcher.cs

93 lines
3.5 KiB
C#
Raw Normal View History

2026-05-22 14:29:22 +08:00
namespace FileShare_Services.Core
{
/// <summary>
/// Matches unified endpoint patterns and extracts simple route values.
/// </summary>
internal static class ServiceEndpointPatternMatcher
{
/// <summary>
/// Match literal segments and single-segment route parameters such as {id} or {id:int}.
/// </summary>
public static bool TryMatch(
string pattern,
string path,
out Dictionary<string, string> routeValues)
{
routeValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var patternSegments = SplitSegments(pattern);
var pathSegments = SplitSegments(path);
if (patternSegments.Length != pathSegments.Length)
{
return false;
}
for (var index = 0; index < patternSegments.Length; index++)
{
var patternSegment = patternSegments[index];
var pathSegment = pathSegments[index];
if (TryGetParameterName(patternSegment, out var parameterName))
{
if (!MatchesConstraint(patternSegment, pathSegment))
{
return false;
}
routeValues[parameterName] = Uri.UnescapeDataString(pathSegment);
continue;
}
if (!string.Equals(patternSegment, pathSegment, StringComparison.OrdinalIgnoreCase))
{
return false;
}
}
return true;
}
/// <summary>
/// 将路径按 <c>/</c> 拆分为非空片段数组。
/// </summary>
/// <param name="value">路径字符串。</param>
/// <returns>过滤空条目后的片段数组。</returns>
private static string[] SplitSegments(string value)
{
return value.Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
}
/// <summary>
/// 尝试从 <c>{name}</c> 或 <c>{name:constraint}</c> 格式的片段中提取参数名称。
/// </summary>
/// <param name="segment">模式片段。</param>
/// <param name="parameterName">提取出的参数名称。</param>
/// <returns>该片段是路由参数时返回 true否则 false。</returns>
private static bool TryGetParameterName(string segment, out string parameterName)
{
parameterName = string.Empty;
if (segment.Length < 3 || segment[0] != '{' || segment[^1] != '}')
{
return false;
}
var token = segment[1..^1];
var constraintIndex = token.IndexOf(':');
parameterName = constraintIndex >= 0 ? token[..constraintIndex] : token;
return !string.IsNullOrWhiteSpace(parameterName);
}
/// <summary>
/// 检查路由值是否满足片段中的类型约束(目前仅支持 <c>:int</c>)。
/// </summary>
/// <param name="segment">包含约束的模式片段。</param>
/// <param name="value">实际路径值。</param>
/// <returns>满足约束时返回 true。</returns>
private static bool MatchesConstraint(string segment, string value)
{
return !segment.EndsWith(":int}", StringComparison.OrdinalIgnoreCase)
|| int.TryParse(value, out _);
}
}
}