Files
StoreWeb/Core/MAX.Framework/Conventions/ApiRoutePrefixConvention.cs

56 lines
2.1 KiB
C#

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Infrastructure;
namespace MAX.Framework.Conventions;
/// <summary>为 API 控制器的属性路由统一添加 api 前缀,已含前缀的路由保持不变。</summary>
public sealed class ApiRoutePrefixConvention : IApplicationModelConvention
{
public void Apply(ApplicationModel application)
{
foreach (var controller in application.Controllers)
{
if (!controller.Attributes.OfType<IApiBehaviorMetadata>().Any()
&& !controller.ControllerType.Assembly.IsDefined(typeof(ApiControllerAttribute), true))
{
continue;
}
var hasControllerRoute = controller.Selectors.Any(selector => selector.AttributeRouteModel != null);
foreach (var selector in controller.Selectors)
{
if (selector.AttributeRouteModel is { } route)
{
AddPrefix(route);
}
}
foreach (var action in controller.Actions)
foreach (var selector in action.Selectors)
{
// 绝对动作路由会覆盖控制器路由,因此需要单独添加前缀。
if (selector.AttributeRouteModel is { } route
&& (!hasControllerRoute || route.IsAbsoluteTemplate))
{
AddPrefix(route);
}
}
}
}
private static void AddPrefix(AttributeRouteModel route)
{
var template = route.Template ?? "";
var absolute = route.IsAbsoluteTemplate;
template = template.StartsWith("~/", StringComparison.Ordinal) ? template[2..] : template.TrimStart('/');
if (!template.Equals("api", StringComparison.OrdinalIgnoreCase)
&& !template.StartsWith("api/", StringComparison.OrdinalIgnoreCase))
{
template = string.IsNullOrEmpty(template) ? "api" : $"api/{template}";
}
route.Template = absolute ? $"~/{template}" : template;
}
}