using Microsoft.AspNetCore.Mvc.ActionConstraints; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Store.Users.Controllers; internal static class UserRoutingChecks { public static void Run() { // 经真实 MVC 模型构建流程验证约定,不只是检查特性或直接调用 Apply。 var services = new ServiceCollection(); services.AddLogging(); services.AddControllers().AddApplicationPart(typeof(UserController).Assembly); using var provider = services.BuildServiceProvider(); var actions = provider.GetRequiredService().ActionDescriptors.Items .OfType().Where(a => a.ControllerTypeInfo.AsType() == typeof(UserController)).ToArray(); if (actions.Length != 19) throw new Exception("用户控制器操作发现数量错误"); foreach (var action in actions) { var method = "POST"; var constraint = action.ActionConstraints!.OfType().Single(); var metadata = action.EndpointMetadata.OfType().Single(); if (!constraint.HttpMethods.SequenceEqual([method]) || !metadata.HttpMethods.SequenceEqual([method])) throw new Exception($"{action.ActionName} 的方法约束或端点元数据错误"); } var descriptions = provider.GetRequiredService().ApiDescriptionGroups.Items .SelectMany(g => g.Items).Where(d => d.ActionDescriptor is ControllerActionDescriptor a && a.ControllerTypeInfo.AsType() == typeof(UserController)).ToArray(); if (descriptions.Length != actions.Length || descriptions.Any(d => d.HttpMethod != "POST")) throw new Exception("用户接口文档的 HTTP 方法错误"); Console.WriteLine("PASS: User 统一 POST、路由约束、端点元数据和接口文档验证通过。"); } }