Search code examples
c#azureswagger.net-6.0swashbuckle.aspnetcore

Azure API deployment issue - Swashbuckle SwaggenGen Error


I've got a problem when trying to deploy my App Service to Azure from VS 2022. Each time I'm getting this error:

Deployment error

I'm using .NET 6 as my target framework and I've got the Swashbuckle.AspNetCore package updated to the newest version. The app service is published with success, but the error pops up when trying to update the API.

In my version of the project there is no Startup.cs but Program.cs, and the way I'm implementing the Swagger generation is:

builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();

I've browsed through similar posts and based on them I can add that I am not fetching any environment variables too.

I've also tried using UseSwaggerUI() like this but I get the same error anyway:

app.UseSwaggerUI(options =>
{
    options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
    options.RoutePrefix = string.Empty;
});

Weird thing is that the deployment works for my colleague and it worked for me until last week when it stopped when nothing in the Program.cs was changed on the way.

My Program.cs:

var builder = WebApplication.CreateBuilder(args);
var azureKeyVaultUrl = builder.Configuration[AppConfigurationConst.AzureKeyVaultUrl];
var logAnalyticsWorkspaceId = AzureKeyVaultHelper.GetAzureKeyVault(azureKeyVaultUrl, AppConfigurationConst.LogAnalyticsWorkspaceId);
var logAnaliticsAuthenticationId = AzureKeyVaultHelper.GetAzureKeyVault(azureKeyVaultUrl, AppConfigurationConst.LogAnaliticsAuthenticationId);
var CrmConnectionString = AzureKeyVaultHelper.GetAzureKeyVault(azureKeyVaultUrl, AppConfigurationConst.OneCrmConnectionString);

var logger = new LoggerConfiguration()
               .WriteTo.AzureAnalytics(logAnalyticsWorkspaceId, logAnaliticsAuthenticationId)
               .Enrich.FromLogContext()
               .CreateLogger();

var serviceClient = new ServiceClient(CrmConnectionString);


builder.Logging.AddSerilog(logger);

logger.Information("Start ALGOI App Service");

builder.Services.AddControllers().AddNewtonsoftJson();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddSingleton<IAuthenticationService, AuthenticationService>();
builder.Services.AddSingleton<IWebClientService, WebClientService>();

builder.Services.AddScoped<ICreateSessionService, CreateSessionService>();
builder.Services.AddScoped<ICreateFolderService, CreateFolderService>();
builder.Services.AddScoped<IDeleteFolderService, DeleteFolderService>();

builder.Services.AddScoped<IVerifyFolderService, VerifyFolderService>();
builder.Services.AddScoped<IUndoFolderService, UndoFolderService>();

builder.Services.AddSingleton(serviceClient);
builder.Services.AddApplicationInsightsTelemetry(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]);

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();


app.Run();

And my .csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UserSecretsId>{usersecretsid}</UserSecretsId>
    <GenerateRuntimeConfigurationFiles>True</GenerateRuntimeConfigurationFiles>
  </PropertyGroup>

  <ItemGroup>
    <Compile Remove="Connected Services\**" />
    <Content Remove="Connected Services\**" />
    <EmbeddedResource Remove="Connected Services\**" />
    <None Remove="Connected Services\**" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="FluentAssertions" Version="6.7.0" />
    <PackageReference Include="JsonSubTypes" Version="1.9.0" />
    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.15.0" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.6" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.6" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.7" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.6">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.Graph" Version="4.34.0" />
    <PackageReference Include="Microsoft.Identity.Client" Version="4.48.1" />
    <PackageReference Include="Microsoft.Identity.Web" Version="1.16.0" />
    <PackageReference Include="Microsoft.Identity.Web.MicrosoftGraph" Version="1.16.0" />
    <PackageReference Include="Microsoft.PowerPlatform.Dataverse.Client" Version="1.0.9" />
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.6" />
    <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
    <PackageReference Include="Polly" Version="7.2.3" />
    <PackageReference Include="RestSharp" Version="106.13.0" />
    <PackageReference Include="Serilog" Version="2.11.0" />
    <PackageReference Include="Serilog.Extensions.Hosting" Version="5.0.0" />
    <PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
    <PackageReference Include="Serilog.Sinks.AzureAnalytics" Version="4.8.0" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
    <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
    <PackageReference Include="System.Net.Http" Version="4.3.4" />
    <PackageReference Include="TypeSafe.Http.Net.HttpClient" Version="2.2.16" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="someprojectpath" />
    <ProjectReference Include="someprojectpath" />
    <ProjectReference Include="someprojectpath" />
  </ItemGroup>

  <ItemGroup>
    <Content Update="local.settings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Update="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

</Project>

appsettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "domain",
    "TenantId": "tenantid",
    "ClientId": "clientid",
    "Scopes": "access_as_user",
    "CallbackPath": "/signin-oidc",
    "ClientSecret": "Client secret from app-registration. Check user secrets/azure portal.",
    "ClientCertificates": []
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AzureKeyVaultUrl": "keyvaulturl",
  "AllowedHosts": "*",
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com/v1.0",
    "Scopes": "user.read"
  },
  "ApplicationInsights": {
    "ConnectionString": "appinsightsconnectionstring"
  }
}

EDIT: I've found out that the cause of the error are those lines:

var azureKeyVaultUrl = builder.Configuration[AppConfigurationConst.AzureKeyVaultUrl];
var logAnalyticsWorkspaceId = AzureKeyVaultHelper.GetAzureKeyVault(azureKeyVaultUrl, AppConfigurationConst.LogAnalyticsWorkspaceId);
var logAnaliticsAuthenticationId = AzureKeyVaultHelper.GetAzureKeyVault(azureKeyVaultUrl, AppConfigurationConst.LogAnaliticsAuthenticationId);
var CrmConnectionString = AzureKeyVaultHelper.GetAzureKeyVault(azureKeyVaultUrl, AppConfigurationConst.OneCrmConnectionString);

I've since changed them to get values directly from configuration instead of keyvault:

var azureKeyVaultUrl = builder.Configuration.GetValue<string>(AppConfigurationConst.AzureKeyVaultUrl);
var logAnalyticsWorkspaceId = builder.Configuration.GetValue<string>(AppConfigurationConst.LogAnalyticsWorkspaceId);
var logAnaliticsAuthenticationId = builder.Configuration.GetValue<string>(AppConfigurationConst.LogAnaliticsAuthenticationId);
var CrmConnectionString = builder.Configuration.GetValue<string>(AppConfigurationConst.OneCrmConnectionString);

When running locally, it takes the values correctly and assignes them to the variables. But it seems that when deploying it encounters a problem with that. In line var serviceClient = new ServiceClient(CrmConnectionString); when I change the variable to static string it works correctly, but when using the variable the startup.cs error pops up (only when deploying). Same thing with initializing logger which uses the log analitycs values. Again, locally runs with no problems, only the deployment crashes.


Solution

  • I have created a sample ASP.NET Core 6.0 Web API and able to deploy the Application to Azure App Service without any errors.

    Generally, this type of error occurs when there is any error in the code or Configuration issues.

    In my version of the project there is no Startup.cs but Program.cs

    .Net6 Core Folder Structure:

    enter image description here

    Yes, we need to Configure the code related to Swagger in Program.cs itself.

    Check the below steps and make sure you are following the same to deploy without any issues.

    • Select the ASP.NET Core Web API template. enter image description here

    • Select Enable openAPI support. enter image description here

    My .csproj file :

    <Project Sdk="Microsoft.NET.Sdk.Web">
      <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
      </ItemGroup>
    </Project>
    

    My Program.cs file :

    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddControllers();
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();
    
    var app = builder.Build();
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    else
    {
        app.UseSwagger();
        app.UseSwaggerUI(options =>
        {
            options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
            options.RoutePrefix = string.Empty;
        });
    }
    
    app.UseHttpsRedirection();
    app.UseAuthorization();
    app.MapControllers();
    app.Run();
    

    Output of Deployed Azure App Service:

    enter image description here

    enter image description here