using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.AspNetCore;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Reflection;
namespace Yi.Framework.AspNetCore.Mvc
{
///
/// 自定义服务约定实现,用于处理API路由和HTTP方法约束
///
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
[ExposeServices(typeof(IAbpServiceConvention))]
public class YiServiceConvention : AbpServiceConvention
{
///
/// 初始化服务约定的新实例
///
/// ABP AspNetCore MVC 配置选项
/// 约定路由构建器
public YiServiceConvention(
IOptions options,
IConventionalRouteBuilder conventionalRouteBuilder)
: base(options, conventionalRouteBuilder)
{
}
///
/// 配置选择器,处理路由和HTTP方法约束
///
protected override void ConfigureSelector(
string rootPath,
string controllerName,
ActionModel action,
ConventionalControllerSetting? configuration)
{
// 移除空选择器
RemoveEmptySelectors(action.Selectors);
// 检查远程服务特性
var remoteServiceAttr = ReflectionHelper
.GetSingleAttributeOrDefault(action.ActionMethod);
if (remoteServiceAttr != null && !remoteServiceAttr.IsEnabledFor(action.ActionMethod))
{
return;
}
// 根据选择器是否存在执行不同的配置
if (!action.Selectors.Any())
{
AddAbpServiceSelector(rootPath, controllerName, action, configuration);
}
else
{
NormalizeSelectorRoutes(rootPath, controllerName, action, configuration);
}
}
///
/// 规范化选择器路由
///
protected override void NormalizeSelectorRoutes(
string rootPath,
string controllerName,
ActionModel action,
ConventionalControllerSetting? configuration)
{
foreach (var selector in action.Selectors)
{
// 获取HTTP方法约束
var httpMethod = GetOrCreateHttpMethod(selector, action, configuration);
// 处理路由模板
ConfigureRouteTemplate(selector, rootPath, controllerName, action, httpMethod, configuration);
// 确保HTTP方法约束存在
EnsureHttpMethodConstraint(selector, httpMethod);
}
}
///
/// 获取或创建HTTP方法
///
private string GetOrCreateHttpMethod(
SelectorModel selector,
ActionModel action,
ConventionalControllerSetting? configuration)
{
return selector.ActionConstraints
.OfType()
.FirstOrDefault()?
.HttpMethods?
.FirstOrDefault()
?? SelectHttpMethod(action, configuration);
}
///
/// 配置路由模板
///
private void ConfigureRouteTemplate(
SelectorModel selector,
string rootPath,
string controllerName,
ActionModel action,
string httpMethod,
ConventionalControllerSetting? configuration)
{
if (selector.AttributeRouteModel == null)
{
selector.AttributeRouteModel = CreateAbpServiceAttributeRouteModel(
rootPath,
controllerName,
action,
httpMethod,
configuration);
}
else
{
NormalizeAttributeRouteTemplate(selector, rootPath);
}
}
///
/// 规范化特性路由模板
///
private void NormalizeAttributeRouteTemplate(SelectorModel selector, string rootPath)
{
var template = selector.AttributeRouteModel.Template;
if (!template.StartsWith("/"))
{
selector.AttributeRouteModel.Template = $"{rootPath}/{template}";
}
}
///
/// 确保HTTP方法约束存在
///
private void EnsureHttpMethodConstraint(SelectorModel selector, string httpMethod)
{
if (!selector.ActionConstraints.OfType().Any())
{
selector.ActionConstraints.Add(
new HttpMethodActionConstraint(new[] { httpMethod }));
}
}
}
}