.NET 8 Lambda Annotations集成NSwag生成Swagger文档求助
.NET 8 + Lambda Annotations 生成适配Redoc/NSwag的Swagger文档方案
Lambda Annotations依赖LambdaFunctionAttribute定义路由和HTTP方法,而非传统的HttpGet/HttpPost特性,导致常规NSwag自动扫描的方式失效,以下是两种可行的解决方案:
方案一:手动构建OpenAPI规范
直接基于OpenAPI标准手动定义API的路由、请求响应模型,再序列化为JSON/YML格式供Redoc/NSwag使用:
引入Swashbuckle相关NuGet包(用于OpenAPI对象模型和序列化):
Install-Package Swashbuckle.AspNetCore.Swagger Install-Package Swashbuckle.AspNetCore.SwaggerGen编写代码生成OpenAPI文档:
using Microsoft.OpenApi.Models; using Newtonsoft.Json; public OpenApiDocument BuildSwaggerDocument() { var doc = new OpenApiDocument { Info = new OpenApiInfo { Title = "Lambda Annotations API", Version = "v1", Description = "基于.NET 8 Lambda Annotations构建的API文档" }, Paths = new OpenApiPaths { ["/api/users/{id}"] = new OpenApiPathItem { Get = new OpenApiOperation { Summary = "根据ID获取用户详情", Parameters = new List<OpenApiParameter> { new OpenApiParameter { Name = "id", In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { Type = "string" } } }, Responses = new OpenApiResponses { ["200"] = new OpenApiResponse { Description = "成功返回用户信息", Content = new Dictionary<string, OpenApiMediaType> { ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "User" } } } } }, ["404"] = new OpenApiResponse { Description = "用户不存在" } } } } }, Components = new OpenApiComponents { Schemas = new Dictionary<string, OpenApiSchema> { ["User"] = new OpenApiSchema { Type = "object", Properties = new Dictionary<string, OpenApiSchema> { ["Id"] = new OpenApiSchema { Type = "string" }, ["UserName"] = new OpenApiSchema { Type = "string" }, ["Email"] = new OpenApiSchema { Type = "string", Format = "email" } }, Required = new List<string> { "Id", "UserName" } } } } }; return doc; } // 序列化为JSON public string GetSwaggerJson() { var doc = BuildSwaggerDocument(); return JsonConvert.SerializeObject(doc, Formatting.Indented); }添加Lambda函数暴露Swagger文档端点:
using Amazon.Lambda.Annotations; using Amazon.Lambda.Annotations.APIGateway; [LambdaFunction(Route = "swagger/json", Method = "GET")] public IHttpResult ReturnSwaggerJson() { var swaggerJson = GetSwaggerJson(); return HttpResults.Ok(swaggerJson).WithContentType("application/json"); }
方案二:反射自动生成规范
通过反射扫描项目中所有LambdaFunctionAttribute标记的方法,自动提取路由、HTTP方法、参数和返回类型,结合Swashbuckle的SchemaGenerator生成完整的OpenAPI文档:
同样先引入Swashbuckle相关NuGet包,然后编写反射扫描逻辑:
using System.Reflection; using Amazon.Lambda.Annotations; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; public OpenApiDocument GenerateSwaggerFromLambdaAnnotations() { var doc = new OpenApiDocument { Info = new OpenApiInfo { Title = "Auto-Generated Lambda API", Version = "v1" }, Paths = new OpenApiPaths(), Components = new OpenApiComponents { Schemas = new Dictionary<string, OpenApiSchema>() } }; var schemaGenerator = new SchemaGenerator(new SchemaGeneratorOptions()); var schemaRepo = new SchemaRepository(); // 扫描当前程序集中所有带LambdaFunctionAttribute的方法 var lambdaMethods = Assembly.GetExecutingAssembly().GetTypes() .SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) .Where(m => m.GetCustomAttribute<LambdaFunctionAttribute>() != null); foreach (var method in lambdaMethods) { var lambdaAttr = method.GetCustomAttribute<LambdaFunctionAttribute>(); var route = lambdaAttr.Route ?? $"/{method.Name}"; var httpMethod = lambdaAttr.Method?.ToUpper() ?? "POST"; // 初始化PathItem if (!doc.Paths.ContainsKey(route)) { doc.Paths[route] = new OpenApiPathItem(); } // 创建OpenApiOperation var operation = new OpenApiOperation { Summary = $"执行{method.Name}方法" }; // 处理方法参数(作为查询参数或请求体) foreach (var param in method.GetParameters()) { if (param.ParameterType.IsPrimitive || param.ParameterType == typeof(string)) { // 简单类型作为查询参数 operation.Parameters.Add(new OpenApiParameter { Name = param.Name, In = ParameterLocation.Query, Required = !param.IsOptional, Schema = schemaGenerator.GenerateSchema(param.ParameterType, schemaRepo) }); } else { // 复杂类型作为请求体 operation.RequestBody = new OpenApiRequestBody { Content = new Dictionary<string, OpenApiMediaType> { ["application/json"] = new OpenApiMediaType { Schema = schemaGenerator.GenerateSchema(param.ParameterType, schemaRepo) } } }; } } // 处理返回类型 var returnType = method.ReturnType; if (returnType != typeof(void)) { // 处理Task<T>的情况 if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>)) { returnType = returnType.GetGenericArguments()[0]; } operation.Responses["200"] = new OpenApiResponse { Description = "请求成功", Content = new Dictionary<string, OpenApiMediaType> { ["application/json"] = new OpenApiMediaType { Schema = schemaGenerator.GenerateSchema(returnType, schemaRepo) } } }; } // 将Operation绑定到对应的HTTP方法 switch (httpMethod) { case "GET": doc.Paths[route].Get = operation; break; case "POST": doc.Paths[route].Post = operation; break; case "PUT": doc.Paths[route].Put = operation; break; case "DELETE": doc.Paths[route].Delete = operation; break; } // 将生成的Schema添加到Components中 foreach (var schema in schemaRepo.Schemas) { if (!doc.Components.Schemas.ContainsKey(schema.Key)) { doc.Components.Schemas.Add(schema.Key, schema.Value); } } } return doc; }同样添加Lambda函数返回生成的Swagger文档,后续即可将这个JSON/YML地址配置到Redoc或NSwag中使用。
注意事项
- 反射方案需要处理复杂的参数/返回类型场景(比如泛型、嵌套对象),可以根据实际项目需求调整逻辑。
- 生成的Swagger文档需要定期更新,或者在构建时自动生成并打包部署。
内容的提问来源于stack exchange,提问作者user24871458
相关产品推荐
相关产品推荐

