修改User模块,同步原始代码

This commit is contained in:
chfei committed 2026-10-23 15:42:37 +08:00
1 parent 4a5fada435
commit 78b0c2bb2e
47 files changed
+2939 -193

No files matched your search

@@ -0,0 +1,55 @@
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;
}
}
@@ -0,0 +1,28 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Routing;
namespace MAX.Framework.Conventions;
/// <summary>
/// 控制器内未声明 HTTP 方法的操作默认只接受 GET,供各模块复用。
/// 显式 HTTP 方法声明优先;同时补充路由约束和端点元数据,保证接口文档一致。
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public sealed class DefaultHttpGetAttribute : Attribute, IControllerModelConvention
{
public void Apply(ControllerModel controller)
{
foreach (var action in controller.Actions)
foreach (var selector in action.Selectors)
{
if (selector.ActionConstraints.OfType<HttpMethodActionConstraint>().Any()
|| selector.EndpointMetadata.OfType<IHttpMethodMetadata>().Any())
continue;
selector.ActionConstraints.Add(new HttpMethodActionConstraint([HttpMethods.Get]));
selector.EndpointMetadata.Add(new HttpMethodMetadata([HttpMethods.Get]));
}
}
}
@@ -0,0 +1,28 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Routing;
namespace MAX.Framework.Conventions;
/// <summary>
/// 控制器内未声明 HTTP 方法的操作默认只接受 POST。
/// 同时补充动作约束和端点元数据,使路由匹配与 OpenAPI 文档保持一致;显式方法声明优先。
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public sealed class DefaultHttpPostAttribute : Attribute, IControllerModelConvention
{
public void Apply(ControllerModel controller)
{
foreach (var action in controller.Actions)
foreach (var selector in action.Selectors)
{
if (selector.ActionConstraints.OfType<HttpMethodActionConstraint>().Any()
|| selector.EndpointMetadata.OfType<IHttpMethodMetadata>().Any())
continue;
selector.ActionConstraints.Add(new HttpMethodActionConstraint([HttpMethods.Post]));
selector.EndpointMetadata.Add(new HttpMethodMetadata([HttpMethods.Post]));
}
}
}