.NET 8 Clean架构Web API部署Azure时Swagger报错问题
我采用Clean Architecture构建ASP.NET Core 8 Web API,所有服务已完成注册,使用.NET 8与Visual Studio 2024,项目本地可正常编译,但发布至Azure时出现如下错误:
Microsoft.WebTools.Shared.Exceptions.WebToolsException: Be sure that the Startup.cs for your application is calling AddSwaggerGen from within ConfigureServices in order to generate swagger file.
at Microsoft.WebTools.Azure.Publish.ApiMApi.BaseApiMApiUpdater.EmitTerminatingError(String bucketName, String displayedErrorMessage, String loggedErrorMessage) at Microsoft.WebTools.Azure.Publish.ApiMApi.AppServiceApiMApiPublishHandler.AppServiceApiMApiUpdater.<GenerateSwaggerToBuildOutputDirAsync>d__12.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.WebTools.Azure.Publish.ApiMApi.AppServiceApiMApiPublishHandler.AppServiceApiMApiUpdater.<RunUpdateAsync>d__10.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.WebTools.Azure.Publish.ApiMApi.BaseApiMApiUpdater.<RunUpdateWithTelemetryAsync>d__9.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.WebTools.Azure.Publish.ApiMApi.AppServiceApiMApiPublishHandler.<UpdateApiMApiAsync>d__14.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.WebTools.Azure.Publish.NewFx.Profiles.BaseSwaggerPublishStep.<RunAsync>d__9.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Microsoft.Publish.Framework.Profiles.ProjectProfilesManager.<RunPublishStepsAsync>d__44.MoveNext()
我已在应用中注册Swagger UI,以下是我的Program.cs文件内容:
using Application.Abstractions; using Infrastructure; using Infrastructure.Context; using Infrastructure.Extensions; using Microsoft.EntityFrameworkCore; using Microsoft.OpenApi.Models; using WebAPI.Middleware; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddDbContext<BreaKonfusionContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("BreaKonfusionContext")) ); builder.Services.AddApplication(); builder.Services.AddApplicationCQRS(); builder.Services.AddProblemDetails(); builder.Services.AddInfrastructure(builder.Configuration); builder.Services.AddControllers(); builder.Services.AddTodoControllers(); builder.Services.AddSignalR(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Logging.AddAzureWebAppDiagnostics(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(option => { option.SwaggerDoc("v1", new OpenApiInfo { Title = "BreaKonfusion API", Version = "v1" }); option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { In = ParameterLocation.Header, Description = "Please enter a valid token", Name = "Authorization", Type = SecuritySchemeType.Http, BearerFormat = "JWT", Scheme = "Bearer" }); option.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type=ReferenceType.SecurityScheme, Id="Bearer" } }, new string[]{} } }); }); builder.Logging.ClearProviders(); builder.Logging.AddConsole(); builder.Logging.AddDebug(); builder.Services.AddScoped<ExceptionHandlingMiddleware>(); var app = builder.Build(); app.UseRouting(); // Configure the HTTP request pipeline. app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Breakonfusion API V1"); }); app.UseCors(CorsExtensions.MyAllowSpecificOrigins); // await app.Services.InitializeDbAsync(); app.UseHttpsRedirection(); app.UseAuthentication(); app.UseAuthorization(); app.UseMiddleware<ExceptionHandlingMiddleware>(); app.UseCurrentUser(); app.MapTodoHubs(); app.MapControllers(); app.Run();
检查发布配置的Swagger选项:打开Visual Studio发布配置界面,找到API文档相关设置,若勾选了“发布时生成Swagger文档”,尝试取消该选项。Azure发布工具在构建阶段生成Swagger文件时,可能因环境上下文问题无法识别Program.cs中的配置。
确保Swagger配置全局生效:确认
AddSwaggerGen和AddEndpointsApiExplorer没有被环境判断语句包裹(你的代码已满足此要求),保证Production环境下这些服务仍会被注册。启用XML文档并指定路径:在
AddSwaggerGen中添加XML注释配置,同时开启项目的XML文档生成功能:using System.Reflection; // 需添加此引用 builder.Services.AddSwaggerGen(option => { option.SwaggerDoc("v1", new OpenApiInfo { Title = "BreaKonfusion API", Version = "v1" }); // 添加XML注释配置 var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); option.IncludeXmlComments(xmlPath); // 其他Swagger配置... });右键项目→属性→生成→输出,勾选“XML文档文件”,保持默认路径即可。
改用Azure CLI发布:避免Visual Studio发布工具的兼容性问题,使用命令行完成发布:
# 先编译发布到本地文件夹 dotnet publish -c Release -o ./publish # 发布到Azure App Service az webapp up --sku B1 --name <你的AppService名称> --location <目标区域>确认中间件顺序:确保
UseSwagger和UseSwaggerUI位于UseRouting之后、UseAuthorization之前,你的代码顺序已符合要求,无需调整。
内容的提问来源于stack exchange,提问作者Awwal15

