From 9b12562ac75789332f10563d1476aa95e9ae9537 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Thu, 20 Apr 2023 14:50:19 -0700 Subject: [PATCH 01/17] Add launchSettings.json for all BenchmarksApps projects --- .../DistributedCache/Properties/launchSettings.json | 12 ++++++++++++ .../Server/Properties/launchSettings.json | 12 ++++++++++++ .../Properties/launchSettings.json | 12 ++++++++++++ .../HelloWorldMvc/Properties/launchSettings.json | 12 ++++++++++++ .../MapAction/Properties/launchSettings.json | 12 ++++++++++++ .../Mvc/Properties/launchSettings.json | 12 ++++++++++++ .../SignalR/Properties/launchSettings.json | 12 ++++++++++++ .../StaticFiles/Properties/launchSettings.json | 12 ++++++++++++ .../TcpEcho/Properties/launchSettings.json | 12 ++++++++++++ .../BlazorUnited/Properties/launchSettings.json | 12 ++++++++++++ .../Minimal/Properties/launchSettings.json | 12 ++++++++++++ .../TechEmpower/Mvc/Properties/launchSettings.json | 12 ++++++++++++ .../Properties/launchSettings.json | 12 ++++++++++++ .../Websocket/Properties/launchSettings.json | 12 ++++++++++++ 14 files changed, 168 insertions(+) create mode 100644 src/BenchmarksApps/DistributedCache/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/Grpc/GrpcHttpApiServer/Server/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/HelloWorldMiddleware/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/HelloWorldMvc/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/MapAction/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/Mvc/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/SignalR/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/StaticFiles/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/TcpEcho/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/TechEmpower/BlazorUnited/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/TechEmpower/Minimal/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/TechEmpower/Mvc/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/TechEmpower/PlatformBenchmarks/Properties/launchSettings.json create mode 100644 src/BenchmarksApps/Websocket/Properties/launchSettings.json diff --git a/src/BenchmarksApps/DistributedCache/Properties/launchSettings.json b/src/BenchmarksApps/DistributedCache/Properties/launchSettings.json new file mode 100644 index 000000000..b2e6e410c --- /dev/null +++ b/src/BenchmarksApps/DistributedCache/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "DistributedCache": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53684;http://localhost:53687" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/Grpc/GrpcHttpApiServer/Server/Properties/launchSettings.json b/src/BenchmarksApps/Grpc/GrpcHttpApiServer/Server/Properties/launchSettings.json new file mode 100644 index 000000000..04544aa1a --- /dev/null +++ b/src/BenchmarksApps/Grpc/GrpcHttpApiServer/Server/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Server": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53695;http://localhost:53696" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/HelloWorldMiddleware/Properties/launchSettings.json b/src/BenchmarksApps/HelloWorldMiddleware/Properties/launchSettings.json new file mode 100644 index 000000000..1d5b541e3 --- /dev/null +++ b/src/BenchmarksApps/HelloWorldMiddleware/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "HelloWorldMiddleware": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53681;http://localhost:53682" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/HelloWorldMvc/Properties/launchSettings.json b/src/BenchmarksApps/HelloWorldMvc/Properties/launchSettings.json new file mode 100644 index 000000000..7b66d8e49 --- /dev/null +++ b/src/BenchmarksApps/HelloWorldMvc/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "HelloWorldMvc": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53675;http://localhost:53678" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/MapAction/Properties/launchSettings.json b/src/BenchmarksApps/MapAction/Properties/launchSettings.json new file mode 100644 index 000000000..d9733efd6 --- /dev/null +++ b/src/BenchmarksApps/MapAction/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "MapAction": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53676;http://localhost:53679" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/Mvc/Properties/launchSettings.json b/src/BenchmarksApps/Mvc/Properties/launchSettings.json new file mode 100644 index 000000000..f120499c2 --- /dev/null +++ b/src/BenchmarksApps/Mvc/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Mvc": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53683;http://localhost:53685" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/SignalR/Properties/launchSettings.json b/src/BenchmarksApps/SignalR/Properties/launchSettings.json new file mode 100644 index 000000000..8e0e2e25f --- /dev/null +++ b/src/BenchmarksApps/SignalR/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "BenchmarkServer": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53697;http://localhost:53698" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/StaticFiles/Properties/launchSettings.json b/src/BenchmarksApps/StaticFiles/Properties/launchSettings.json new file mode 100644 index 000000000..078b08531 --- /dev/null +++ b/src/BenchmarksApps/StaticFiles/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "StaticFiles": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53686;http://localhost:53688" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/TcpEcho/Properties/launchSettings.json b/src/BenchmarksApps/TcpEcho/Properties/launchSettings.json new file mode 100644 index 000000000..c931de446 --- /dev/null +++ b/src/BenchmarksApps/TcpEcho/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "TcpEcho": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53701;http://localhost:53702" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/TechEmpower/BlazorUnited/Properties/launchSettings.json b/src/BenchmarksApps/TechEmpower/BlazorUnited/Properties/launchSettings.json new file mode 100644 index 000000000..45311c8b0 --- /dev/null +++ b/src/BenchmarksApps/TechEmpower/BlazorUnited/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "BlazorUnited": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53703;http://localhost:53704" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/TechEmpower/Minimal/Properties/launchSettings.json b/src/BenchmarksApps/TechEmpower/Minimal/Properties/launchSettings.json new file mode 100644 index 000000000..6e44cd548 --- /dev/null +++ b/src/BenchmarksApps/TechEmpower/Minimal/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Minimal": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53691;http://localhost:53692" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/TechEmpower/Mvc/Properties/launchSettings.json b/src/BenchmarksApps/TechEmpower/Mvc/Properties/launchSettings.json new file mode 100644 index 000000000..34462f12c --- /dev/null +++ b/src/BenchmarksApps/TechEmpower/Mvc/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Mvc": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53693;http://localhost:53694" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/TechEmpower/PlatformBenchmarks/Properties/launchSettings.json b/src/BenchmarksApps/TechEmpower/PlatformBenchmarks/Properties/launchSettings.json new file mode 100644 index 000000000..d6ea99634 --- /dev/null +++ b/src/BenchmarksApps/TechEmpower/PlatformBenchmarks/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "PlatformBenchmarks": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53705;http://localhost:53706" + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/Websocket/Properties/launchSettings.json b/src/BenchmarksApps/Websocket/Properties/launchSettings.json new file mode 100644 index 000000000..742327a86 --- /dev/null +++ b/src/BenchmarksApps/Websocket/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "BenchmarkServer": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53699;http://localhost:53700" + } + } +} \ No newline at end of file From 1a5dbdb1098b5f762c5d41db728ae667443c7f3a Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Thu, 20 Apr 2023 17:54:08 -0700 Subject: [PATCH 02/17] WIP: TodosApi: Bind AppSettings from configuration --- src/BenchmarksApps/TodosApi/AppSettings.cs | 41 ++++++++++++++++++ .../TodosApi/JwtConfiguration.cs | 42 ++++++++++--------- src/BenchmarksApps/TodosApi/Program.cs | 20 ++++----- src/BenchmarksApps/TodosApi/TodosApi.csproj | 2 + 4 files changed, 75 insertions(+), 30 deletions(-) create mode 100644 src/BenchmarksApps/TodosApi/AppSettings.cs diff --git a/src/BenchmarksApps/TodosApi/AppSettings.cs b/src/BenchmarksApps/TodosApi/AppSettings.cs new file mode 100644 index 000000000..328a2dc28 --- /dev/null +++ b/src/BenchmarksApps/TodosApi/AppSettings.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.Options; + +namespace TodosApi; + +internal class AppSettings +{ + public required string ConnectionString { get; set; } + public string? JwtSigningKey { get; set; } +} + +internal class AppSettingsValidator : IValidateOptions +{ + public ValidateOptionsResult Validate(string? name, AppSettings options) + { + if (!string.IsNullOrEmpty(options.ConnectionString)) + { + return ValidateOptionsResult.Fail(""" + Connection string not found. + If running locally, set the connection string in user secrets for key 'AppSettings:ConnectionString'. + If running after deployment, set the connection string via the environment variable 'APPSETTINGS__CONNECTIONSTRING'. + """); + } + + return ValidateOptionsResult.Success; + } +} + +internal static class AppSettingsExtensions +{ + public static IServiceCollection ConfigureAppSettings(this IServiceCollection services, IConfigurationRoot configurationRoot) + { + services.Configure(configurationRoot.GetSection(nameof(AppSettings))) + .AddSingleton, AppSettingsValidator>() + .AddOptions() + // TODO: The following methods aren't currently supported by the config binder source generator + //.BindConfiguration(nameof(AppSettings)) + //.Configure(appSettings => builder.Configuration.Bind(nameof(AppSettings), appSettings)) + .ValidateOnStart(); + return services; + } +} diff --git a/src/BenchmarksApps/TodosApi/JwtConfiguration.cs b/src/BenchmarksApps/TodosApi/JwtConfiguration.cs index 8b6df4cd7..b54f03672 100644 --- a/src/BenchmarksApps/TodosApi/JwtConfiguration.cs +++ b/src/BenchmarksApps/TodosApi/JwtConfiguration.cs @@ -1,32 +1,34 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; +using TodosApi; namespace Microsoft.AspNetCore.Builder; -internal static class JwtConfiguration +internal class JwtConfiguration : IConfigureOptions { - /// - /// Configures JWT Bearer to load the signing key from an environment variable when not running in Development. - /// - /// - /// - /// Thrown when the signing key is not found in non-Development environments. - public static Action ConfigureJwtBearer(WebApplicationBuilder builder) + private readonly IHostEnvironment _hostEnvironment; + private readonly AppSettings _appSettings; + + public JwtConfiguration(IHostEnvironment hostEnvironment, IOptions appSettings) + { + _hostEnvironment = hostEnvironment; + _appSettings = appSettings.Value; + } + + public void Configure(JwtBearerOptions options) { - return options => + if (!_hostEnvironment.IsDevelopment()) { - if (!builder.Environment.IsDevelopment()) - { - // When not running in development configure the JWT signing key from environment variable - var jwtKeyMaterialValue = builder.Configuration["JWT_SIGNING_KEY"]; + // When not running in development configure the JWT signing key from environment variable + var jwtKeyMaterialValue = _appSettings.JwtSigningKey; - if (!string.IsNullOrEmpty(jwtKeyMaterialValue)) - { - var jwtKeyMaterial = Convert.FromBase64String(jwtKeyMaterialValue); - var jwtSigningKey = new SymmetricSecurityKey(jwtKeyMaterial); - options.TokenValidationParameters.IssuerSigningKey = jwtSigningKey; - } + if (!string.IsNullOrEmpty(jwtKeyMaterialValue)) + { + var jwtKeyMaterial = Convert.FromBase64String(jwtKeyMaterialValue); + var jwtSigningKey = new SymmetricSecurityKey(jwtKeyMaterial); + options.TokenValidationParameters.IssuerSigningKey = jwtSigningKey; } - }; + } } } diff --git a/src/BenchmarksApps/TodosApi/Program.cs b/src/BenchmarksApps/TodosApi/Program.cs index a2ba94f12..cf2587eea 100644 --- a/src/BenchmarksApps/TodosApi/Program.cs +++ b/src/BenchmarksApps/TodosApi/Program.cs @@ -7,20 +7,20 @@ builder.Logging.ClearProviders(); #endif -// Configure authentication & authorization -builder.Services.AddAuthentication() - .AddJwtBearer(JwtConfiguration.ConfigureJwtBearer(builder)); +// Bind app settings from configuration & validate +builder.Services.ConfigureAppSettings(builder.Configuration); +// Configure authentication & authorization +builder.Services.AddAuthentication().AddJwtBearer(); +builder.Services.ConfigureOptions(); builder.Services.AddAuthorization(); // Configure data access -var connectionString = builder.Configuration.GetConnectionString("TodoDb") - ?? throw new InvalidOperationException(""" - Connection string not found. - If running locally, set the connection string in user secrets for key 'ConnectionStrings:TodoDb'. - If running after deployment, set the connection string via the environment variable 'CONNECTIONSTRINGS__TODODB'. - """); -builder.Services.AddSingleton(_ => new NpgsqlSlimDataSourceBuilder(connectionString).Build()); +builder.Services.AddSingleton(sp => +{ + var appSettings = sp.GetRequiredService>().Value; + return new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); +}); // Configure JSON serialization builder.Services.ConfigureHttpJsonOptions(options => diff --git a/src/BenchmarksApps/TodosApi/TodosApi.csproj b/src/BenchmarksApps/TodosApi/TodosApi.csproj index 4c928434d..ac7afa629 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.csproj +++ b/src/BenchmarksApps/TodosApi/TodosApi.csproj @@ -9,12 +9,14 @@ preview b8ffb8d3-b768-460b-ac1f-ef267c954c85 true + true true $(DefineConstants);ENABLE_LOGGING + From 2b125e6bf93e79750c39589a5d3d7313edca872d Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Fri, 21 Apr 2023 12:33:38 -0700 Subject: [PATCH 03/17] TodosApi: Update yml scenarios for AppSettings --- scenarios/goldilocks.benchmarks.yml | 6 +++--- src/BenchmarksApps/TodosApi/AppSettings.cs | 20 +++++++++++++++---- src/BenchmarksApps/TodosApi/DataExtensions.cs | 2 ++ src/BenchmarksApps/TodosApi/TodosApi.csproj | 2 +- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/scenarios/goldilocks.benchmarks.yml b/scenarios/goldilocks.benchmarks.yml index 55f9a16c5..2ac1cf3fc 100644 --- a/scenarios/goldilocks.benchmarks.yml +++ b/scenarios/goldilocks.benchmarks.yml @@ -111,7 +111,7 @@ scenarios: - "/p:PublishAot=true" - "/p:StripSymbols=true" environmentVariables: - CONNECTIONSTRINGS__TODODB: Server={{databaseServer}};Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4 + APPSETTINGS__CONNECTIONSTRING: Server={{databaseServer}};Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4 load: job: wrk variables: @@ -131,7 +131,7 @@ scenarios: - "/p:TrimMode=full" - "/p:EnableRequestDelegateGenerator=true" environmentVariables: - CONNECTIONSTRINGS__TODODB: Server={{databaseServer}};Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4 + APPSETTINGS__CONNECTIONSTRING: Server={{databaseServer}};Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4 load: job: wrk variables: @@ -147,7 +147,7 @@ scenarios: - "/p:PublishAot=false" - "/p:EnableRequestDelegateGenerator=false" environmentVariables: - CONNECTIONSTRINGS__TODODB: Server={{databaseServer}};Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4 + APPSETTINGS__CONNECTIONSTRING: Server={{databaseServer}};Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4 load: job: wrk variables: diff --git a/src/BenchmarksApps/TodosApi/AppSettings.cs b/src/BenchmarksApps/TodosApi/AppSettings.cs index 328a2dc28..ac705a360 100644 --- a/src/BenchmarksApps/TodosApi/AppSettings.cs +++ b/src/BenchmarksApps/TodosApi/AppSettings.cs @@ -5,14 +5,16 @@ namespace TodosApi; internal class AppSettings { public required string ConnectionString { get; set; } + public string? JwtSigningKey { get; set; } } +// Change to using ValidateDataAnnotations once https://github.com/dotnet/runtime/issues/77412 is complete internal class AppSettingsValidator : IValidateOptions { public ValidateOptionsResult Validate(string? name, AppSettings options) { - if (!string.IsNullOrEmpty(options.ConnectionString)) + if (string.IsNullOrEmpty(options.ConnectionString)) { return ValidateOptionsResult.Fail(""" Connection string not found. @@ -32,10 +34,20 @@ public static IServiceCollection ConfigureAppSettings(this IServiceCollection se services.Configure(configurationRoot.GetSection(nameof(AppSettings))) .AddSingleton, AppSettingsValidator>() .AddOptions() - // TODO: The following methods aren't currently supported by the config binder source generator - //.BindConfiguration(nameof(AppSettings)) - //.Configure(appSettings => builder.Configuration.Bind(nameof(AppSettings), appSettings)) .ValidateOnStart(); + + // Change to using BindConfiguration once https://github.com/dotnet/runtime/issues/83600 is complete + //services.AddSingleton, AppSettingsValidator>() + // .AddOptions() + // .BindConfiguration(nameof(AppSettings)) + // .ValidateOnStart(); + + // Change to using ValidateDataAnnotations once https://github.com/dotnet/runtime/issues/77412 is complete + //services.AddOptions() + // .BindConfiguration(nameof(AppSettings)) + // .ValidateDataAnnotations() + // .ValidateOnStart(); + return services; } } diff --git a/src/BenchmarksApps/TodosApi/DataExtensions.cs b/src/BenchmarksApps/TodosApi/DataExtensions.cs index f3595d0d1..890d476b0 100644 --- a/src/BenchmarksApps/TodosApi/DataExtensions.cs +++ b/src/BenchmarksApps/TodosApi/DataExtensions.cs @@ -3,6 +3,8 @@ namespace Npgsql; +// Replace this with https://www.nuget.org/packages/Nanorm once it's ready + internal static class DataExtensions { public static async Task ExecuteAsync(this NpgsqlDataSource dataSource, string commandText, CancellationToken cancellationToken = default) diff --git a/src/BenchmarksApps/TodosApi/TodosApi.csproj b/src/BenchmarksApps/TodosApi/TodosApi.csproj index ac7afa629..a1c70450d 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.csproj +++ b/src/BenchmarksApps/TodosApi/TodosApi.csproj @@ -9,7 +9,7 @@ preview b8ffb8d3-b768-460b-ac1f-ef267c954c85 true - true + false true $(DefineConstants);ENABLE_LOGGING From f21707699097ae2d53251ea69c948bf7bd7a1e25 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Fri, 21 Apr 2023 12:34:01 -0700 Subject: [PATCH 04/17] Update TodosApi.http --- src/BenchmarksApps/TodosApi/TodosApi.http | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BenchmarksApps/TodosApi/TodosApi.http b/src/BenchmarksApps/TodosApi/TodosApi.http index d9969348b..c9b5ccf1d 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.http +++ b/src/BenchmarksApps/TodosApi/TodosApi.http @@ -22,7 +22,7 @@ Accept: application/json ### -Get {{TodosApi_HostAddress}}/api/todos/find +Get {{TodosApi_HostAddress}}/api/todos/find?title=wash+the+dishes. Accept: application/json ### From 594f15bea0e02f17436789fecd0c235adb545abd Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Fri, 21 Apr 2023 17:59:37 -0700 Subject: [PATCH 05/17] Generate OpenAPI doc on build --- src/BenchmarksApps/TodosApi/Database.cs | 41 --- .../TodosApi/DatabaseInitializer.cs | 64 ++++ src/BenchmarksApps/TodosApi/Program.cs | 18 +- src/BenchmarksApps/TodosApi/TodosApi.csproj | 17 +- src/BenchmarksApps/TodosApi/TodosApi.json | 345 ++++++++++++++++++ src/BenchmarksApps/TodosApi/appsettings.json | 1 - 6 files changed, 440 insertions(+), 46 deletions(-) delete mode 100644 src/BenchmarksApps/TodosApi/Database.cs create mode 100644 src/BenchmarksApps/TodosApi/DatabaseInitializer.cs create mode 100644 src/BenchmarksApps/TodosApi/TodosApi.json diff --git a/src/BenchmarksApps/TodosApi/Database.cs b/src/BenchmarksApps/TodosApi/Database.cs deleted file mode 100644 index 48dc1d0c1..000000000 --- a/src/BenchmarksApps/TodosApi/Database.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Npgsql; - -namespace TodosApi; - -internal static class Database -{ - public static async Task Initialize(IServiceProvider services, ILogger logger, CancellationToken cancellationToken = default) - { - var db = services.GetRequiredService(); - - if (Environment.GetEnvironmentVariable("SUPPRESS_DB_INIT") != "true") - { - // NOTE: Npgsql removes the password from the connection string - logger.LogInformation("Ensuring database exists and is up to date at connection string '{connectionString}'", db.ConnectionString); - - var sql = $""" - CREATE TABLE IF NOT EXISTS public.todos - ( - {nameof(Todo.Id)} SERIAL PRIMARY KEY, - {nameof(Todo.Title)} text NOT NULL, - {nameof(Todo.DueBy)} date NULL, - {nameof(Todo.IsComplete)} boolean NOT NULL DEFAULT false - ); - DELETE FROM public.todos; - INSERT INTO - public.todos ({nameof(Todo.Title)}, {nameof(Todo.DueBy)}, {nameof(Todo.IsComplete)}) - VALUES - ('Wash the dishes.', CURRENT_DATE, true), - ('Dry the dishes.', CURRENT_DATE, true), - ('Turn the dishes over.', CURRENT_DATE, false), - ('Walk the kangaroo.', CURRENT_DATE + INTERVAL '1 day', false), - ('Call Grandma.', CURRENT_DATE + INTERVAL '1 day', false); - """; - await db.ExecuteAsync(sql, cancellationToken); - } - else - { - logger.LogInformation("Database initialization disabled for connection string '{connectionString}'", db.ConnectionString); - } - } -} diff --git a/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs b/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs new file mode 100644 index 000000000..c32912fac --- /dev/null +++ b/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs @@ -0,0 +1,64 @@ +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Npgsql; + +namespace TodosApi; + +internal class DatabaseInitializer : IHostedService +{ + private readonly NpgsqlDataSource _db; + private readonly ILogger _logger; + private readonly bool _initDatabase; + + public DatabaseInitializer(NpgsqlDataSource db, IServer server, ILogger logger) + { + _db = db; + _logger = logger; + _initDatabase = Environment.GetEnvironmentVariable("SUPPRESS_DB_INIT") != "true" + // Only run if this is an actual IServer implementation with addresses to listen on. + // Will not be the case for TestServer, NoopServer injected by the OpenAPI doc generator tool, etc. + && server.Features.Get() is { Addresses.Count: >0 }; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + if (_initDatabase) + { + return Initialize(cancellationToken); + } + + _logger.LogInformation("Database initialization disabled for connection string '{connectionString}'", _db.ConnectionString); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + private async Task Initialize(CancellationToken cancellationToken = default) + { + // NOTE: Npgsql removes the password from the connection string + _logger.LogInformation("Ensuring database exists and is up to date at connection string '{connectionString}'", _db.ConnectionString); + + var sql = $""" + CREATE TABLE IF NOT EXISTS public.todos + ( + {nameof(Todo.Id)} SERIAL PRIMARY KEY, + {nameof(Todo.Title)} text NOT NULL, + {nameof(Todo.DueBy)} date NULL, + {nameof(Todo.IsComplete)} boolean NOT NULL DEFAULT false + ); + DELETE FROM public.todos; + INSERT INTO + public.todos ({nameof(Todo.Title)}, {nameof(Todo.DueBy)}, {nameof(Todo.IsComplete)}) + VALUES + ('Wash the dishes.', CURRENT_DATE, true), + ('Dry the dishes.', CURRENT_DATE, true), + ('Turn the dishes over.', CURRENT_DATE, false), + ('Walk the kangaroo.', CURRENT_DATE + INTERVAL '1 day', false), + ('Call Grandma.', CURRENT_DATE + INTERVAL '1 day', false); + """; + await _db.ExecuteAsync(sql, cancellationToken); + } +} diff --git a/src/BenchmarksApps/TodosApi/Program.cs b/src/BenchmarksApps/TodosApi/Program.cs index cf2587eea..90eb1bf04 100644 --- a/src/BenchmarksApps/TodosApi/Program.cs +++ b/src/BenchmarksApps/TodosApi/Program.cs @@ -1,3 +1,6 @@ +#if ENABLE_OPENAPI +using Microsoft.OpenApi.Models; +#endif using Npgsql; using TodosApi; @@ -21,6 +24,7 @@ var appSettings = sp.GetRequiredService>().Value; return new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); }); +builder.Services.AddHostedService(); // Configure JSON serialization builder.Services.ConfigureHttpJsonOptions(options => @@ -36,16 +40,26 @@ // Problem details builder.Services.AddProblemDetails(); -var app = builder.Build(); +#if ENABLE_OPENAPI +// Configure OpenAPI +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(c => +{ + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Todos API", Version = "v1" }); +}); +#endif -await Database.Initialize(app.Services, app.Logger); +var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler(); } +app.MapShortCircuit(StatusCodes.Status404NotFound, "/favicon.ico"); + app.MapHealthChecks("/health"); + // Enables testing request exception handling behavior app.MapGet("/throw", void () => throw new InvalidOperationException("You hit the throw endpoint")); diff --git a/src/BenchmarksApps/TodosApi/TodosApi.csproj b/src/BenchmarksApps/TodosApi/TodosApi.csproj index a1c70450d..d743f02a1 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.csproj +++ b/src/BenchmarksApps/TodosApi/TodosApi.csproj @@ -10,13 +10,26 @@ b8ffb8d3-b768-460b-ac1f-ef267c954c85 true false - true + true + true $(DefineConstants);ENABLE_LOGGING + $(DefineConstants);ENABLE_OPENAPI - + + + + + + true + ./ + + + + + diff --git a/src/BenchmarksApps/TodosApi/TodosApi.json b/src/BenchmarksApps/TodosApi/TodosApi.json new file mode 100644 index 000000000..a5497486d --- /dev/null +++ b/src/BenchmarksApps/TodosApi/TodosApi.json @@ -0,0 +1,345 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Todos API", + "version": "v1" + }, + "paths": { + "/throw": { + "get": { + "tags": [ + "TodosApi" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/todos": { + "get": { + "tags": [ + "TodosApi" + ], + "operationId": "GetAllTodos", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Todo" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "TodosApi" + ], + "operationId": "CreateTodo", + "requestBody": { + "content": { }, + "required": true + }, + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/HttpValidationProblemDetails" + } + } + } + } + } + } + }, + "/api/todos/complete": { + "get": { + "tags": [ + "TodosApi" + ], + "operationId": "GetCompleteTodos", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Todo" + } + } + } + } + } + } + } + }, + "/api/todos/incomplete": { + "get": { + "tags": [ + "TodosApi" + ], + "operationId": "GetIncompleteTodos", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Todo" + } + } + } + } + } + } + } + }, + "/api/todos/{id}": { + "get": { + "tags": [ + "TodosApi" + ], + "operationId": "GetTodoById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "put": { + "tags": [ + "TodosApi" + ], + "operationId": "UpdateTodo", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { }, + "required": true + }, + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/HttpValidationProblemDetails" + } + } + } + } + } + }, + "delete": { + "tags": [ + "TodosApi" + ], + "operationId": "DeleteTodo", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/todos/find": { + "get": { + "tags": [ + "TodosApi" + ], + "operationId": "FindTodo", + "parameters": [ + { + "name": "title", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "isComplete", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/todos/{id}/mark-complete": { + "put": { + "tags": [ + "TodosApi" + ], + "operationId": "MarkComplete", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/todos/{id}/mark-incomplete": { + "put": { + "tags": [ + "TodosApi" + ], + "operationId": "MarkIncomplete", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/api/todos/delete-all": { + "delete": { + "tags": [ + "TodosApi" + ], + "operationId": "DeleteAll", + "responses": { + "200": { + "description": "Success" + } + } + } + } + }, + "components": { + "schemas": { + "HttpValidationProblemDetails": { + "type": "object", + "properties": { + "type": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "status": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "detail": { + "type": "string", + "nullable": true + }, + "instance": { + "type": "string", + "nullable": true + }, + "errors": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + }, + "nullable": true + } + }, + "additionalProperties": { } + }, + "Todo": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "title": { + "type": "string", + "nullable": true + }, + "dueBy": { + "type": "string", + "format": "date", + "nullable": true + }, + "isComplete": { + "type": "boolean" + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/TodosApi/appsettings.json b/src/BenchmarksApps/TodosApi/appsettings.json index 6b6ae8970..d73d9463d 100644 --- a/src/BenchmarksApps/TodosApi/appsettings.json +++ b/src/BenchmarksApps/TodosApi/appsettings.json @@ -5,7 +5,6 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*", "Authentication": { "Schemes": { "Bearer": { From b7ccd33c436c8cece5a9e7acc3fbe715c481d504 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Tue, 25 Apr 2023 14:24:20 -0700 Subject: [PATCH 06/17] Update TodosApi.csproj --- src/BenchmarksApps/TodosApi/TodosApi.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/BenchmarksApps/TodosApi/TodosApi.csproj b/src/BenchmarksApps/TodosApi/TodosApi.csproj index d743f02a1..ee19ed3ab 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.csproj +++ b/src/BenchmarksApps/TodosApi/TodosApi.csproj @@ -29,7 +29,6 @@ - - + From 825ca9c3fdbc2818ba7d257ac6754a42be4cce4b Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Wed, 26 Apr 2023 17:53:58 -0700 Subject: [PATCH 07/17] More changes to enable OpenAPI doc generation --- .../TodosApi/.config/dotnet-tools.json | 12 +++++++++++ src/BenchmarksApps/TodosApi/AppSettings.cs | 21 ++++++++++++++++++- .../TodosApi/DatabaseHealthCheck.cs | 2 +- .../TodosApi/DatabaseInitializer.cs | 15 +++++++++---- src/BenchmarksApps/TodosApi/Program.cs | 5 ++++- src/BenchmarksApps/TodosApi/TodosApi.csproj | 9 +++++--- 6 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 src/BenchmarksApps/TodosApi/.config/dotnet-tools.json diff --git a/src/BenchmarksApps/TodosApi/.config/dotnet-tools.json b/src/BenchmarksApps/TodosApi/.config/dotnet-tools.json new file mode 100644 index 000000000..9672707ed --- /dev/null +++ b/src/BenchmarksApps/TodosApi/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "swashbuckle.aspnetcore.cli": { + "version": "6.5.0", + "commands": [ + "swagger" + ] + } + } +} \ No newline at end of file diff --git a/src/BenchmarksApps/TodosApi/AppSettings.cs b/src/BenchmarksApps/TodosApi/AppSettings.cs index ac705a360..998507c0c 100644 --- a/src/BenchmarksApps/TodosApi/AppSettings.cs +++ b/src/BenchmarksApps/TodosApi/AppSettings.cs @@ -4,9 +4,26 @@ namespace TodosApi; internal class AppSettings { + private bool _suppressDbInitialization; + +#if GENERATING_OPENAPI_DOC + public AppSettings() + { + GeneratingOpenApiDoc = true; + } +#endif + public required string ConnectionString { get; set; } + public bool GeneratingOpenApiDoc { get; set; } + public string? JwtSigningKey { get; set; } + + public bool SuppressDbInitialization + { + get => _suppressDbInitialization || GeneratingOpenApiDoc; + set => _suppressDbInitialization = value; + } } // Change to using ValidateDataAnnotations once https://github.com/dotnet/runtime/issues/77412 is complete @@ -14,7 +31,7 @@ internal class AppSettingsValidator : IValidateOptions { public ValidateOptionsResult Validate(string? name, AppSettings options) { - if (string.IsNullOrEmpty(options.ConnectionString)) + if (string.IsNullOrEmpty(options.ConnectionString) && !options.GeneratingOpenApiDoc) { return ValidateOptionsResult.Fail(""" Connection string not found. @@ -31,6 +48,8 @@ internal static class AppSettingsExtensions { public static IServiceCollection ConfigureAppSettings(this IServiceCollection services, IConfigurationRoot configurationRoot) { + // Can't use the configuration binding source generator due to bug where it emits non-compiling code right now + // https://github.com/dotnet/runtime/issues/83600 services.Configure(configurationRoot.GetSection(nameof(AppSettings))) .AddSingleton, AppSettingsValidator>() .AddOptions() diff --git a/src/BenchmarksApps/TodosApi/DatabaseHealthCheck.cs b/src/BenchmarksApps/TodosApi/DatabaseHealthCheck.cs index f80bc78c4..870d7e331 100644 --- a/src/BenchmarksApps/TodosApi/DatabaseHealthCheck.cs +++ b/src/BenchmarksApps/TodosApi/DatabaseHealthCheck.cs @@ -3,7 +3,7 @@ namespace TodosApi; -public class DatabaseHealthCheck : IHealthCheck +internal class DatabaseHealthCheck : IHealthCheck { private readonly NpgsqlDataSource _dataSource; diff --git a/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs b/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs index c32912fac..84091da95 100644 --- a/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs +++ b/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.Extensions.Options; using Npgsql; namespace TodosApi; @@ -10,11 +11,11 @@ internal class DatabaseInitializer : IHostedService private readonly ILogger _logger; private readonly bool _initDatabase; - public DatabaseInitializer(NpgsqlDataSource db, IServer server, ILogger logger) + public DatabaseInitializer(NpgsqlDataSource db, IOptions appSettings, IServer server, ILogger logger) { _db = db; _logger = logger; - _initDatabase = Environment.GetEnvironmentVariable("SUPPRESS_DB_INIT") != "true" + _initDatabase = !appSettings.Value.SuppressDbInitialization // Only run if this is an actual IServer implementation with addresses to listen on. // Will not be the case for TestServer, NoopServer injected by the OpenAPI doc generator tool, etc. && server.Features.Get() is { Addresses.Count: >0 }; @@ -27,7 +28,10 @@ public Task StartAsync(CancellationToken cancellationToken) return Initialize(cancellationToken); } - _logger.LogInformation("Database initialization disabled for connection string '{connectionString}'", _db.ConnectionString); + if (_logger.IsEnabled(LogLevel.Information)) + { + _logger.LogInformation("Database initialization disabled for connection string '{connectionString}'", _db?.ConnectionString); + } return Task.CompletedTask; } @@ -39,7 +43,10 @@ public Task StopAsync(CancellationToken cancellationToken) private async Task Initialize(CancellationToken cancellationToken = default) { // NOTE: Npgsql removes the password from the connection string - _logger.LogInformation("Ensuring database exists and is up to date at connection string '{connectionString}'", _db.ConnectionString); + if (_logger.IsEnabled(LogLevel.Information)) + { + _logger.LogInformation("Ensuring database exists and is up to date at connection string '{connectionString}'", _db.ConnectionString); + } var sql = $""" CREATE TABLE IF NOT EXISTS public.todos diff --git a/src/BenchmarksApps/TodosApi/Program.cs b/src/BenchmarksApps/TodosApi/Program.cs index 90eb1bf04..e458f78d9 100644 --- a/src/BenchmarksApps/TodosApi/Program.cs +++ b/src/BenchmarksApps/TodosApi/Program.cs @@ -1,3 +1,4 @@ +using Microsoft.Extensions.Options; #if ENABLE_OPENAPI using Microsoft.OpenApi.Models; #endif @@ -22,7 +23,9 @@ builder.Services.AddSingleton(sp => { var appSettings = sp.GetRequiredService>().Value; - return new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); + return appSettings.GeneratingOpenApiDoc + ? default! + : new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); }); builder.Services.AddHostedService(); diff --git a/src/BenchmarksApps/TodosApi/TodosApi.csproj b/src/BenchmarksApps/TodosApi/TodosApi.csproj index ee19ed3ab..e65fb90d3 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.csproj +++ b/src/BenchmarksApps/TodosApi/TodosApi.csproj @@ -9,9 +9,10 @@ preview b8ffb8d3-b768-460b-ac1f-ef267c954c85 true + false true - true + true $(DefineConstants);ENABLE_LOGGING $(DefineConstants);ENABLE_OPENAPI @@ -24,11 +25,13 @@ - true - ./ + + false + $(DefineConstants);GENERATING_OPENAPI_DOC + From 35de3490495a2fbc258f27bce1abb79108f1e89d Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Thu, 27 Apr 2023 17:11:43 -0700 Subject: [PATCH 08/17] Disable MapShortCircuit due to issue --- src/BenchmarksApps/TodosApi/Program.cs | 3 ++- .../{TodosApi.json => TodosApi.openapi.json} | 24 +++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) rename src/BenchmarksApps/TodosApi/{TodosApi.json => TodosApi.openapi.json} (88%) diff --git a/src/BenchmarksApps/TodosApi/Program.cs b/src/BenchmarksApps/TodosApi/Program.cs index e458f78d9..53a28558a 100644 --- a/src/BenchmarksApps/TodosApi/Program.cs +++ b/src/BenchmarksApps/TodosApi/Program.cs @@ -59,7 +59,8 @@ app.UseExceptionHandler(); } -app.MapShortCircuit(StatusCodes.Status404NotFound, "/favicon.ico"); +// Causes issue with native AOT currently: https://github.com/dotnet/aspnetcore/issues/47941 +//app.MapShortCircuit(StatusCodes.Status404NotFound, "/favicon.ico"); app.MapHealthChecks("/health"); diff --git a/src/BenchmarksApps/TodosApi/TodosApi.json b/src/BenchmarksApps/TodosApi/TodosApi.openapi.json similarity index 88% rename from src/BenchmarksApps/TodosApi/TodosApi.json rename to src/BenchmarksApps/TodosApi/TodosApi.openapi.json index a5497486d..149a18f4d 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.json +++ b/src/BenchmarksApps/TodosApi/TodosApi.openapi.json @@ -8,7 +8,7 @@ "/throw": { "get": { "tags": [ - "TodosApi" + "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ], "responses": { "200": { @@ -20,7 +20,7 @@ "/api/todos": { "get": { "tags": [ - "TodosApi" + "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ], "operationId": "GetAllTodos", "responses": { @@ -41,7 +41,7 @@ }, "post": { "tags": [ - "TodosApi" + "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ], "operationId": "CreateTodo", "requestBody": { @@ -65,7 +65,7 @@ "/api/todos/complete": { "get": { "tags": [ - "TodosApi" + "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ], "operationId": "GetCompleteTodos", "responses": { @@ -88,7 +88,7 @@ "/api/todos/incomplete": { "get": { "tags": [ - "TodosApi" + "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ], "operationId": "GetIncompleteTodos", "responses": { @@ -111,7 +111,7 @@ "/api/todos/{id}": { "get": { "tags": [ - "TodosApi" + "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ], "operationId": "GetTodoById", "parameters": [ @@ -133,7 +133,7 @@ }, "put": { "tags": [ - "TodosApi" + "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ], "operationId": "UpdateTodo", "parameters": [ @@ -166,7 +166,7 @@ }, "delete": { "tags": [ - "TodosApi" + "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ], "operationId": "DeleteTodo", "parameters": [ @@ -190,7 +190,7 @@ "/api/todos/find": { "get": { "tags": [ - "TodosApi" + "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ], "operationId": "FindTodo", "parameters": [ @@ -220,7 +220,7 @@ "/api/todos/{id}/mark-complete": { "put": { "tags": [ - "TodosApi" + "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ], "operationId": "MarkComplete", "parameters": [ @@ -244,7 +244,7 @@ "/api/todos/{id}/mark-incomplete": { "put": { "tags": [ - "TodosApi" + "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ], "operationId": "MarkIncomplete", "parameters": [ @@ -268,7 +268,7 @@ "/api/todos/delete-all": { "delete": { "tags": [ - "TodosApi" + "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ], "operationId": "DeleteAll", "responses": { From 91a056b313e46bd62515b66e84247ba4467c492c Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Fri, 28 Apr 2023 13:17:53 -0700 Subject: [PATCH 09/17] Updates --- src/BenchmarksApps/TodosApi/DataExtensions.cs | 2 ++ .../TodosApi/DatabaseConfiguration.cs | 23 ++++++++++++++++ .../TodosApi/DatabaseInitializer.cs | 13 +++------ .../TodosApi/OpenApiExtensions.cs | 20 ++++++++++++++ src/BenchmarksApps/TodosApi/Program.cs | 27 +++---------------- src/BenchmarksApps/TodosApi/TodosApi.csproj | 2 ++ src/BenchmarksApps/TodosApi/TodosApi.http | 2 +- 7 files changed, 56 insertions(+), 33 deletions(-) create mode 100644 src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs create mode 100644 src/BenchmarksApps/TodosApi/OpenApiExtensions.cs diff --git a/src/BenchmarksApps/TodosApi/DataExtensions.cs b/src/BenchmarksApps/TodosApi/DataExtensions.cs index 890d476b0..723c4e0f8 100644 --- a/src/BenchmarksApps/TodosApi/DataExtensions.cs +++ b/src/BenchmarksApps/TodosApi/DataExtensions.cs @@ -1,5 +1,7 @@ using System.Data; using System.Runtime.CompilerServices; +using Microsoft.Extensions.Options; +using TodosApi; namespace Npgsql; diff --git a/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs b/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs new file mode 100644 index 000000000..127813d0b --- /dev/null +++ b/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.Options; +using Npgsql; +using TodosApi; + +namespace Microsoft.Extensions.Hosting; + +internal static class DatabaseConfiguration +{ + public static IServiceCollection AddDatabase(this IServiceCollection services) + { + services.AddSingleton(static sp => + { + var appSettings = sp.GetRequiredService>().Value; + var db = appSettings.GeneratingOpenApiDoc + ? default! + : new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); + + return db; + }); + services.AddHostedService(); + return services; + } +} diff --git a/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs b/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs index 84091da95..81e1c1cc6 100644 --- a/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs +++ b/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs @@ -11,14 +11,11 @@ internal class DatabaseInitializer : IHostedService private readonly ILogger _logger; private readonly bool _initDatabase; - public DatabaseInitializer(NpgsqlDataSource db, IOptions appSettings, IServer server, ILogger logger) + public DatabaseInitializer(NpgsqlDataSource db, IOptions appSettings, ILogger logger) { _db = db; _logger = logger; - _initDatabase = !appSettings.Value.SuppressDbInitialization - // Only run if this is an actual IServer implementation with addresses to listen on. - // Will not be the case for TestServer, NoopServer injected by the OpenAPI doc generator tool, etc. - && server.Features.Get() is { Addresses.Count: >0 }; + _initDatabase = !appSettings.Value.SuppressDbInitialization && !appSettings.Value.GeneratingOpenApiDoc; } public Task StartAsync(CancellationToken cancellationToken) @@ -32,14 +29,12 @@ public Task StartAsync(CancellationToken cancellationToken) { _logger.LogInformation("Database initialization disabled for connection string '{connectionString}'", _db?.ConnectionString); } - return Task.CompletedTask; - } - public Task StopAsync(CancellationToken cancellationToken) - { return Task.CompletedTask; } + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + private async Task Initialize(CancellationToken cancellationToken = default) { // NOTE: Npgsql removes the password from the connection string diff --git a/src/BenchmarksApps/TodosApi/OpenApiExtensions.cs b/src/BenchmarksApps/TodosApi/OpenApiExtensions.cs new file mode 100644 index 000000000..36fae1258 --- /dev/null +++ b/src/BenchmarksApps/TodosApi/OpenApiExtensions.cs @@ -0,0 +1,20 @@ +#if ENABLE_OPENAPI +using Microsoft.OpenApi.Models; +#endif + +namespace Microsoft.Extensions.Hosting; + +internal static class OpenApiExtensions +{ + public static IServiceCollection AddOpenApi(this IServiceCollection services) + { +#if ENABLE_OPENAPI + services.AddEndpointsApiExplorer(); + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Todos API", Version = "v1" }); + }); +#endif + return services; + } +} diff --git a/src/BenchmarksApps/TodosApi/Program.cs b/src/BenchmarksApps/TodosApi/Program.cs index 53a28558a..0ad577b5b 100644 --- a/src/BenchmarksApps/TodosApi/Program.cs +++ b/src/BenchmarksApps/TodosApi/Program.cs @@ -1,8 +1,3 @@ -using Microsoft.Extensions.Options; -#if ENABLE_OPENAPI -using Microsoft.OpenApi.Models; -#endif -using Npgsql; using TodosApi; var builder = WebApplication.CreateSlimBuilder(args); @@ -20,14 +15,7 @@ builder.Services.AddAuthorization(); // Configure data access -builder.Services.AddSingleton(sp => -{ - var appSettings = sp.GetRequiredService>().Value; - return appSettings.GeneratingOpenApiDoc - ? default! - : new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); -}); -builder.Services.AddHostedService(); +builder.Services.AddDatabase(); // Configure JSON serialization builder.Services.ConfigureHttpJsonOptions(options => @@ -43,14 +31,8 @@ // Problem details builder.Services.AddProblemDetails(); -#if ENABLE_OPENAPI -// Configure OpenAPI -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(c => -{ - c.SwaggerDoc("v1", new OpenApiInfo { Title = "Todos API", Version = "v1" }); -}); -#endif +// OpenAPI +builder.Services.AddOpenApi(); var app = builder.Build(); @@ -59,8 +41,7 @@ app.UseExceptionHandler(); } -// Causes issue with native AOT currently: https://github.com/dotnet/aspnetcore/issues/47941 -//app.MapShortCircuit(StatusCodes.Status404NotFound, "/favicon.ico"); +app.MapShortCircuit(StatusCodes.Status404NotFound, "/favicon.ico"); app.MapHealthChecks("/health"); diff --git a/src/BenchmarksApps/TodosApi/TodosApi.csproj b/src/BenchmarksApps/TodosApi/TodosApi.csproj index e65fb90d3..f9874e9a0 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.csproj +++ b/src/BenchmarksApps/TodosApi/TodosApi.csproj @@ -22,6 +22,8 @@ + + diff --git a/src/BenchmarksApps/TodosApi/TodosApi.http b/src/BenchmarksApps/TodosApi/TodosApi.http index c9b5ccf1d..5e4bad0a0 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.http +++ b/src/BenchmarksApps/TodosApi/TodosApi.http @@ -1,6 +1,6 @@ @TodosApi_HostAddress = http://localhost:5054 # Uncomment following line if sending requests to published app -#@TodosApi_HostAddress = http://localhost:5000 +@TodosApi_HostAddress = http://localhost:5000 # For more info on HTTP files go to https://aka.ms/vs/httpfile From 2f85f8b792d4dfecc1eeab8c0cfe9c1cd21c3f7a Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Fri, 28 Apr 2023 16:47:12 -0700 Subject: [PATCH 10/17] Add OpenAPI runtime feature to trim related code in Release builds --- src/BenchmarksApps.sln | 10 ++++++ .../AspNetCore.OpenApi.csproj | 17 ++++++++++ .../ILLink.Substitutions.xml | 8 +++++ .../AspNetCore.OpenApi/OpenApiFeature.cs | 17 ++++++++++ .../build/AspNetCore.OpenApi.targets | 14 +++++++++ src/BenchmarksApps/TodosApi/AppSettings.cs | 19 ++---------- .../TodosApi/DatabaseConfiguration.cs | 4 +-- .../TodosApi/DatabaseInitializer.cs | 6 ++-- .../TodosApi/OpenApiExtensions.cs | 16 +++++----- src/BenchmarksApps/TodosApi/TodosApi.csproj | 28 ++++++++--------- .../{TodosApi.openapi.json => TodosApi.json} | 31 ++++++++++++------- 11 files changed, 112 insertions(+), 58 deletions(-) create mode 100644 src/BenchmarksApps/AspNetCore.OpenApi/AspNetCore.OpenApi.csproj create mode 100644 src/BenchmarksApps/AspNetCore.OpenApi/ILLink.Substitutions.xml create mode 100644 src/BenchmarksApps/AspNetCore.OpenApi/OpenApiFeature.cs create mode 100644 src/BenchmarksApps/AspNetCore.OpenApi/build/AspNetCore.OpenApi.targets rename src/BenchmarksApps/TodosApi/{TodosApi.openapi.json => TodosApi.json} (88%) diff --git a/src/BenchmarksApps.sln b/src/BenchmarksApps.sln index 5800ec3c7..386c31c2f 100644 --- a/src/BenchmarksApps.sln +++ b/src/BenchmarksApps.sln @@ -55,6 +55,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorUnited", "BenchmarksA EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodosApi", "BenchmarksApps\TodosApi\TodosApi.csproj", "{8E1A1F61-43E4-4629-A25B-7E5FA82697D0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetCore.OpenApi", "BenchmarksApps\AspNetCore.OpenApi\AspNetCore.OpenApi.csproj", "{28F432A6-1328-4996-91DD-BB1C87F45BF2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug_Database|Any CPU = Debug_Database|Any CPU @@ -207,6 +209,14 @@ Global {8E1A1F61-43E4-4629-A25B-7E5FA82697D0}.Release_Database|Any CPU.Build.0 = Release_Database|Any CPU {8E1A1F61-43E4-4629-A25B-7E5FA82697D0}.Release|Any CPU.ActiveCfg = Release|Any CPU {8E1A1F61-43E4-4629-A25B-7E5FA82697D0}.Release|Any CPU.Build.0 = Release|Any CPU + {28F432A6-1328-4996-91DD-BB1C87F45BF2}.Debug_Database|Any CPU.ActiveCfg = Debug_Database|Any CPU + {28F432A6-1328-4996-91DD-BB1C87F45BF2}.Debug_Database|Any CPU.Build.0 = Debug_Database|Any CPU + {28F432A6-1328-4996-91DD-BB1C87F45BF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28F432A6-1328-4996-91DD-BB1C87F45BF2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28F432A6-1328-4996-91DD-BB1C87F45BF2}.Release_Database|Any CPU.ActiveCfg = Release_Database|Any CPU + {28F432A6-1328-4996-91DD-BB1C87F45BF2}.Release_Database|Any CPU.Build.0 = Release_Database|Any CPU + {28F432A6-1328-4996-91DD-BB1C87F45BF2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28F432A6-1328-4996-91DD-BB1C87F45BF2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/BenchmarksApps/AspNetCore.OpenApi/AspNetCore.OpenApi.csproj b/src/BenchmarksApps/AspNetCore.OpenApi/AspNetCore.OpenApi.csproj new file mode 100644 index 000000000..7f3d0cb1f --- /dev/null +++ b/src/BenchmarksApps/AspNetCore.OpenApi/AspNetCore.OpenApi.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + diff --git a/src/BenchmarksApps/AspNetCore.OpenApi/ILLink.Substitutions.xml b/src/BenchmarksApps/AspNetCore.OpenApi/ILLink.Substitutions.xml new file mode 100644 index 000000000..50c2c47a3 --- /dev/null +++ b/src/BenchmarksApps/AspNetCore.OpenApi/ILLink.Substitutions.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/src/BenchmarksApps/AspNetCore.OpenApi/OpenApiFeature.cs b/src/BenchmarksApps/AspNetCore.OpenApi/OpenApiFeature.cs new file mode 100644 index 000000000..3f5fd4b7b --- /dev/null +++ b/src/BenchmarksApps/AspNetCore.OpenApi/OpenApiFeature.cs @@ -0,0 +1,17 @@ +namespace Microsoft.AspNetCore.OpenApi; + +public static class OpenApiFeature +{ + /// + /// Indicates whether APIs related to OpenAPI/Swagger functionality are enabled. + /// + /// + /// The value of the property is backed by the "Microsoft.AspNetCore.OpenApi.OpenApiFeature.IsEnabled" + /// setting and defaults to if unset. + /// + public static bool IsEnabled { get; } = + AppContext.TryGetSwitch( + switchName: "Microsoft.AspNetCore.OpenApi.OpenApiFeature.IsEnabled", + isEnabled: out var value) + ? value : true; +} diff --git a/src/BenchmarksApps/AspNetCore.OpenApi/build/AspNetCore.OpenApi.targets b/src/BenchmarksApps/AspNetCore.OpenApi/build/AspNetCore.OpenApi.targets new file mode 100644 index 000000000..1b1c52ce7 --- /dev/null +++ b/src/BenchmarksApps/AspNetCore.OpenApi/build/AspNetCore.OpenApi.targets @@ -0,0 +1,14 @@ + + + + false + + + + + + + diff --git a/src/BenchmarksApps/TodosApi/AppSettings.cs b/src/BenchmarksApps/TodosApi/AppSettings.cs index 998507c0c..629bd11af 100644 --- a/src/BenchmarksApps/TodosApi/AppSettings.cs +++ b/src/BenchmarksApps/TodosApi/AppSettings.cs @@ -4,26 +4,11 @@ namespace TodosApi; internal class AppSettings { - private bool _suppressDbInitialization; - -#if GENERATING_OPENAPI_DOC - public AppSettings() - { - GeneratingOpenApiDoc = true; - } -#endif - public required string ConnectionString { get; set; } - public bool GeneratingOpenApiDoc { get; set; } - public string? JwtSigningKey { get; set; } - public bool SuppressDbInitialization - { - get => _suppressDbInitialization || GeneratingOpenApiDoc; - set => _suppressDbInitialization = value; - } + public bool SuppressDbInitialization { get; set; } } // Change to using ValidateDataAnnotations once https://github.com/dotnet/runtime/issues/77412 is complete @@ -31,7 +16,7 @@ internal class AppSettingsValidator : IValidateOptions { public ValidateOptionsResult Validate(string? name, AppSettings options) { - if (string.IsNullOrEmpty(options.ConnectionString) && !options.GeneratingOpenApiDoc) + if (string.IsNullOrEmpty(options.ConnectionString)) { return ValidateOptionsResult.Fail(""" Connection string not found. diff --git a/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs b/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs index 127813d0b..bc1730b3d 100644 --- a/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs +++ b/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs @@ -11,9 +11,7 @@ public static IServiceCollection AddDatabase(this IServiceCollection services) services.AddSingleton(static sp => { var appSettings = sp.GetRequiredService>().Value; - var db = appSettings.GeneratingOpenApiDoc - ? default! - : new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); + var db = new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); return db; }); diff --git a/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs b/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs index 81e1c1cc6..1f4412845 100644 --- a/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs +++ b/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs @@ -1,6 +1,4 @@ -using Microsoft.AspNetCore.Hosting.Server; -using Microsoft.AspNetCore.Hosting.Server.Features; -using Microsoft.Extensions.Options; +using Microsoft.Extensions.Options; using Npgsql; namespace TodosApi; @@ -15,7 +13,7 @@ public DatabaseInitializer(NpgsqlDataSource db, IOptions appSetting { _db = db; _logger = logger; - _initDatabase = !appSettings.Value.SuppressDbInitialization && !appSettings.Value.GeneratingOpenApiDoc; + _initDatabase = !appSettings.Value.SuppressDbInitialization; } public Task StartAsync(CancellationToken cancellationToken) diff --git a/src/BenchmarksApps/TodosApi/OpenApiExtensions.cs b/src/BenchmarksApps/TodosApi/OpenApiExtensions.cs index 36fae1258..40d475bee 100644 --- a/src/BenchmarksApps/TodosApi/OpenApiExtensions.cs +++ b/src/BenchmarksApps/TodosApi/OpenApiExtensions.cs @@ -1,6 +1,5 @@ -#if ENABLE_OPENAPI +using Microsoft.AspNetCore.OpenApi; using Microsoft.OpenApi.Models; -#endif namespace Microsoft.Extensions.Hosting; @@ -8,13 +7,14 @@ internal static class OpenApiExtensions { public static IServiceCollection AddOpenApi(this IServiceCollection services) { -#if ENABLE_OPENAPI - services.AddEndpointsApiExplorer(); - services.AddSwaggerGen(c => + if (OpenApiFeature.IsEnabled) { - c.SwaggerDoc("v1", new OpenApiInfo { Title = "Todos API", Version = "v1" }); - }); -#endif + services.AddEndpointsApiExplorer(); + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Todos API", Version = "v1" }); + }); + } return services; } } diff --git a/src/BenchmarksApps/TodosApi/TodosApi.csproj b/src/BenchmarksApps/TodosApi/TodosApi.csproj index f9874e9a0..e79063ab5 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.csproj +++ b/src/BenchmarksApps/TodosApi/TodosApi.csproj @@ -9,31 +9,31 @@ preview b8ffb8d3-b768-460b-ac1f-ef267c954c85 true + .\ + false true - true $(DefineConstants);ENABLE_LOGGING - $(DefineConstants);ENABLE_OPENAPI - - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + - - - false - $(DefineConstants);GENERATING_OPENAPI_DOC - - - - - - + diff --git a/src/BenchmarksApps/TodosApi/TodosApi.openapi.json b/src/BenchmarksApps/TodosApi/TodosApi.json similarity index 88% rename from src/BenchmarksApps/TodosApi/TodosApi.openapi.json rename to src/BenchmarksApps/TodosApi/TodosApi.json index 149a18f4d..75336a737 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.openapi.json +++ b/src/BenchmarksApps/TodosApi/TodosApi.json @@ -8,7 +8,7 @@ "/throw": { "get": { "tags": [ - "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + "TodosApi" ], "responses": { "200": { @@ -20,7 +20,7 @@ "/api/todos": { "get": { "tags": [ - "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + "TodosApi" ], "operationId": "GetAllTodos", "responses": { @@ -41,7 +41,7 @@ }, "post": { "tags": [ - "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + "TodosApi" ], "operationId": "CreateTodo", "requestBody": { @@ -65,7 +65,7 @@ "/api/todos/complete": { "get": { "tags": [ - "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + "TodosApi" ], "operationId": "GetCompleteTodos", "responses": { @@ -88,7 +88,7 @@ "/api/todos/incomplete": { "get": { "tags": [ - "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + "TodosApi" ], "operationId": "GetIncompleteTodos", "responses": { @@ -111,7 +111,7 @@ "/api/todos/{id}": { "get": { "tags": [ - "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + "TodosApi" ], "operationId": "GetTodoById", "parameters": [ @@ -119,6 +119,7 @@ "name": "id", "in": "path", "required": true, + "style": "simple", "schema": { "type": "integer", "format": "int32" @@ -133,7 +134,7 @@ }, "put": { "tags": [ - "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + "TodosApi" ], "operationId": "UpdateTodo", "parameters": [ @@ -141,6 +142,7 @@ "name": "id", "in": "path", "required": true, + "style": "simple", "schema": { "type": "integer", "format": "int32" @@ -166,7 +168,7 @@ }, "delete": { "tags": [ - "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + "TodosApi" ], "operationId": "DeleteTodo", "parameters": [ @@ -174,6 +176,7 @@ "name": "id", "in": "path", "required": true, + "style": "simple", "schema": { "type": "integer", "format": "int32" @@ -190,7 +193,7 @@ "/api/todos/find": { "get": { "tags": [ - "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + "TodosApi" ], "operationId": "FindTodo", "parameters": [ @@ -198,6 +201,7 @@ "name": "title", "in": "query", "required": true, + "style": "form", "schema": { "type": "string" } @@ -205,6 +209,7 @@ { "name": "isComplete", "in": "query", + "style": "form", "schema": { "type": "boolean" } @@ -220,7 +225,7 @@ "/api/todos/{id}/mark-complete": { "put": { "tags": [ - "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + "TodosApi" ], "operationId": "MarkComplete", "parameters": [ @@ -228,6 +233,7 @@ "name": "id", "in": "path", "required": true, + "style": "simple", "schema": { "type": "integer", "format": "int32" @@ -244,7 +250,7 @@ "/api/todos/{id}/mark-incomplete": { "put": { "tags": [ - "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + "TodosApi" ], "operationId": "MarkIncomplete", "parameters": [ @@ -252,6 +258,7 @@ "name": "id", "in": "path", "required": true, + "style": "simple", "schema": { "type": "integer", "format": "int32" @@ -268,7 +275,7 @@ "/api/todos/delete-all": { "delete": { "tags": [ - "TodosApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" + "TodosApi" ], "operationId": "DeleteAll", "responses": { From 08daa96e4f9b09c12b3ea9a64b14bb376c6c0acc Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Mon, 1 May 2023 10:06:06 -0700 Subject: [PATCH 11/17] Don't require database config/init if run as part of the build --- src/BenchmarksApps/TodosApi/AppSettings.cs | 9 ++++++++- src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs | 5 ++++- src/BenchmarksApps/TodosApi/DatabaseInitializer.cs | 8 ++++---- src/BenchmarksApps/TodosApi/TodosApi.csproj | 6 +++--- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/BenchmarksApps/TodosApi/AppSettings.cs b/src/BenchmarksApps/TodosApi/AppSettings.cs index 629bd11af..34828f9c2 100644 --- a/src/BenchmarksApps/TodosApi/AppSettings.cs +++ b/src/BenchmarksApps/TodosApi/AppSettings.cs @@ -14,9 +14,16 @@ internal class AppSettings // Change to using ValidateDataAnnotations once https://github.com/dotnet/runtime/issues/77412 is complete internal class AppSettingsValidator : IValidateOptions { + private readonly IHostEnvironment _hostEnvironment; + + public AppSettingsValidator(IHostEnvironment hostEnvironment) + { + _hostEnvironment = hostEnvironment; + } + public ValidateOptionsResult Validate(string? name, AppSettings options) { - if (string.IsNullOrEmpty(options.ConnectionString)) + if (!_hostEnvironment.IsEnvironment("Build") && string.IsNullOrEmpty(options.ConnectionString)) { return ValidateOptionsResult.Fail(""" Connection string not found. diff --git a/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs b/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs index bc1730b3d..5e52af0af 100644 --- a/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs +++ b/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs @@ -11,7 +11,10 @@ public static IServiceCollection AddDatabase(this IServiceCollection services) services.AddSingleton(static sp => { var appSettings = sp.GetRequiredService>().Value; - var db = new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); + var hostEnvironment = sp.GetRequiredService(); + var db = hostEnvironment.IsEnvironment("Build") + ? default! + : new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); return db; }); diff --git a/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs b/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs index 1f4412845..fd6b4a512 100644 --- a/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs +++ b/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs @@ -9,11 +9,11 @@ internal class DatabaseInitializer : IHostedService private readonly ILogger _logger; private readonly bool _initDatabase; - public DatabaseInitializer(NpgsqlDataSource db, IOptions appSettings, ILogger logger) + public DatabaseInitializer(NpgsqlDataSource db, IOptions appSettings, IHostEnvironment hostEnvironment, ILogger logger) { _db = db; _logger = logger; - _initDatabase = !appSettings.Value.SuppressDbInitialization; + _initDatabase = !(hostEnvironment.IsEnvironment("Build") || appSettings.Value.SuppressDbInitialization); } public Task StartAsync(CancellationToken cancellationToken) @@ -25,7 +25,7 @@ public Task StartAsync(CancellationToken cancellationToken) if (_logger.IsEnabled(LogLevel.Information)) { - _logger.LogInformation("Database initialization disabled for connection string '{connectionString}'", _db?.ConnectionString); + _logger.LogInformation("Database initialization is disabled"); } return Task.CompletedTask; @@ -38,7 +38,7 @@ private async Task Initialize(CancellationToken cancellationToken = default) // NOTE: Npgsql removes the password from the connection string if (_logger.IsEnabled(LogLevel.Information)) { - _logger.LogInformation("Ensuring database exists and is up to date at connection string '{connectionString}'", _db.ConnectionString); + _logger.LogInformation("Ensuring database exists and is up to date"); } var sql = $""" diff --git a/src/BenchmarksApps/TodosApi/TodosApi.csproj b/src/BenchmarksApps/TodosApi/TodosApi.csproj index e79063ab5..48a562e54 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.csproj +++ b/src/BenchmarksApps/TodosApi/TodosApi.csproj @@ -20,13 +20,13 @@ + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - From e3d54ad022d1a8be7d0c68e6c66c14e9397a5c98 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Mon, 1 May 2023 10:31:58 -0700 Subject: [PATCH 12/17] Add schema to launchSettings.json files --- .../BasicMinimalApi/Properties/launchSettings.json | 1 + .../DistributedCache/Properties/launchSettings.json | 1 + src/BenchmarksApps/Grpc/BasicGrpc/Properties/launchSettings.json | 1 + .../Grpc/GrpcHttpApiServer/Server/Properties/launchSettings.json | 1 + .../HelloWorldMiddleware/Properties/launchSettings.json | 1 + src/BenchmarksApps/HelloWorldMvc/Properties/launchSettings.json | 1 + src/BenchmarksApps/MapAction/Properties/launchSettings.json | 1 + src/BenchmarksApps/Mvc/Properties/launchSettings.json | 1 + src/BenchmarksApps/SignalR/Properties/launchSettings.json | 1 + src/BenchmarksApps/StaticFiles/Properties/launchSettings.json | 1 + src/BenchmarksApps/TcpEcho/Properties/launchSettings.json | 1 + .../TechEmpower/BlazorUnited/Properties/launchSettings.json | 1 + .../TechEmpower/Minimal/Properties/launchSettings.json | 1 + .../TechEmpower/Mvc/Properties/launchSettings.json | 1 + .../PlatformBenchmarks/Properties/launchSettings.json | 1 + src/BenchmarksApps/Websocket/Properties/launchSettings.json | 1 + 16 files changed, 16 insertions(+) diff --git a/src/BenchmarksApps/BasicMinimalApi/Properties/launchSettings.json b/src/BenchmarksApps/BasicMinimalApi/Properties/launchSettings.json index b5267280f..5ecae91f9 100644 --- a/src/BenchmarksApps/BasicMinimalApi/Properties/launchSettings.json +++ b/src/BenchmarksApps/BasicMinimalApi/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "BasicMinimalApi": { "commandName": "Project", diff --git a/src/BenchmarksApps/DistributedCache/Properties/launchSettings.json b/src/BenchmarksApps/DistributedCache/Properties/launchSettings.json index b2e6e410c..9344b26f8 100644 --- a/src/BenchmarksApps/DistributedCache/Properties/launchSettings.json +++ b/src/BenchmarksApps/DistributedCache/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "DistributedCache": { "commandName": "Project", diff --git a/src/BenchmarksApps/Grpc/BasicGrpc/Properties/launchSettings.json b/src/BenchmarksApps/Grpc/BasicGrpc/Properties/launchSettings.json index 754a65a9b..bafcc5f4d 100644 --- a/src/BenchmarksApps/Grpc/BasicGrpc/Properties/launchSettings.json +++ b/src/BenchmarksApps/Grpc/BasicGrpc/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "BasicGrpc": { "commandName": "Project", diff --git a/src/BenchmarksApps/Grpc/GrpcHttpApiServer/Server/Properties/launchSettings.json b/src/BenchmarksApps/Grpc/GrpcHttpApiServer/Server/Properties/launchSettings.json index 04544aa1a..97e58a11b 100644 --- a/src/BenchmarksApps/Grpc/GrpcHttpApiServer/Server/Properties/launchSettings.json +++ b/src/BenchmarksApps/Grpc/GrpcHttpApiServer/Server/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "Server": { "commandName": "Project", diff --git a/src/BenchmarksApps/HelloWorldMiddleware/Properties/launchSettings.json b/src/BenchmarksApps/HelloWorldMiddleware/Properties/launchSettings.json index 1d5b541e3..96a3a5667 100644 --- a/src/BenchmarksApps/HelloWorldMiddleware/Properties/launchSettings.json +++ b/src/BenchmarksApps/HelloWorldMiddleware/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "HelloWorldMiddleware": { "commandName": "Project", diff --git a/src/BenchmarksApps/HelloWorldMvc/Properties/launchSettings.json b/src/BenchmarksApps/HelloWorldMvc/Properties/launchSettings.json index 7b66d8e49..1c1aabc32 100644 --- a/src/BenchmarksApps/HelloWorldMvc/Properties/launchSettings.json +++ b/src/BenchmarksApps/HelloWorldMvc/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "HelloWorldMvc": { "commandName": "Project", diff --git a/src/BenchmarksApps/MapAction/Properties/launchSettings.json b/src/BenchmarksApps/MapAction/Properties/launchSettings.json index d9733efd6..281196e09 100644 --- a/src/BenchmarksApps/MapAction/Properties/launchSettings.json +++ b/src/BenchmarksApps/MapAction/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "MapAction": { "commandName": "Project", diff --git a/src/BenchmarksApps/Mvc/Properties/launchSettings.json b/src/BenchmarksApps/Mvc/Properties/launchSettings.json index f120499c2..b57c05603 100644 --- a/src/BenchmarksApps/Mvc/Properties/launchSettings.json +++ b/src/BenchmarksApps/Mvc/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "Mvc": { "commandName": "Project", diff --git a/src/BenchmarksApps/SignalR/Properties/launchSettings.json b/src/BenchmarksApps/SignalR/Properties/launchSettings.json index 8e0e2e25f..e7607ff84 100644 --- a/src/BenchmarksApps/SignalR/Properties/launchSettings.json +++ b/src/BenchmarksApps/SignalR/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "BenchmarkServer": { "commandName": "Project", diff --git a/src/BenchmarksApps/StaticFiles/Properties/launchSettings.json b/src/BenchmarksApps/StaticFiles/Properties/launchSettings.json index 078b08531..305b18d63 100644 --- a/src/BenchmarksApps/StaticFiles/Properties/launchSettings.json +++ b/src/BenchmarksApps/StaticFiles/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "StaticFiles": { "commandName": "Project", diff --git a/src/BenchmarksApps/TcpEcho/Properties/launchSettings.json b/src/BenchmarksApps/TcpEcho/Properties/launchSettings.json index c931de446..a96142ba3 100644 --- a/src/BenchmarksApps/TcpEcho/Properties/launchSettings.json +++ b/src/BenchmarksApps/TcpEcho/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "TcpEcho": { "commandName": "Project", diff --git a/src/BenchmarksApps/TechEmpower/BlazorUnited/Properties/launchSettings.json b/src/BenchmarksApps/TechEmpower/BlazorUnited/Properties/launchSettings.json index 45311c8b0..21158c08c 100644 --- a/src/BenchmarksApps/TechEmpower/BlazorUnited/Properties/launchSettings.json +++ b/src/BenchmarksApps/TechEmpower/BlazorUnited/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "BlazorUnited": { "commandName": "Project", diff --git a/src/BenchmarksApps/TechEmpower/Minimal/Properties/launchSettings.json b/src/BenchmarksApps/TechEmpower/Minimal/Properties/launchSettings.json index 6e44cd548..060102075 100644 --- a/src/BenchmarksApps/TechEmpower/Minimal/Properties/launchSettings.json +++ b/src/BenchmarksApps/TechEmpower/Minimal/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "Minimal": { "commandName": "Project", diff --git a/src/BenchmarksApps/TechEmpower/Mvc/Properties/launchSettings.json b/src/BenchmarksApps/TechEmpower/Mvc/Properties/launchSettings.json index 34462f12c..629716fce 100644 --- a/src/BenchmarksApps/TechEmpower/Mvc/Properties/launchSettings.json +++ b/src/BenchmarksApps/TechEmpower/Mvc/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "Mvc": { "commandName": "Project", diff --git a/src/BenchmarksApps/TechEmpower/PlatformBenchmarks/Properties/launchSettings.json b/src/BenchmarksApps/TechEmpower/PlatformBenchmarks/Properties/launchSettings.json index d6ea99634..89d1445f7 100644 --- a/src/BenchmarksApps/TechEmpower/PlatformBenchmarks/Properties/launchSettings.json +++ b/src/BenchmarksApps/TechEmpower/PlatformBenchmarks/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "PlatformBenchmarks": { "commandName": "Project", diff --git a/src/BenchmarksApps/Websocket/Properties/launchSettings.json b/src/BenchmarksApps/Websocket/Properties/launchSettings.json index 742327a86..7169c8001 100644 --- a/src/BenchmarksApps/Websocket/Properties/launchSettings.json +++ b/src/BenchmarksApps/Websocket/Properties/launchSettings.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "BenchmarkServer": { "commandName": "Project", From 3429565a717ccc882ce77e1563593ce2bebd22bf Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Mon, 1 May 2023 10:37:46 -0700 Subject: [PATCH 13/17] Delete dotnet-tools.json --- .../TodosApi/.config/dotnet-tools.json | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 src/BenchmarksApps/TodosApi/.config/dotnet-tools.json diff --git a/src/BenchmarksApps/TodosApi/.config/dotnet-tools.json b/src/BenchmarksApps/TodosApi/.config/dotnet-tools.json deleted file mode 100644 index 9672707ed..000000000 --- a/src/BenchmarksApps/TodosApi/.config/dotnet-tools.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": 1, - "isRoot": true, - "tools": { - "swashbuckle.aspnetcore.cli": { - "version": "6.5.0", - "commands": [ - "swagger" - ] - } - } -} \ No newline at end of file From 7af808e1df22459fa73e30eab68d758541bcfc1a Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Mon, 1 May 2023 10:49:17 -0700 Subject: [PATCH 14/17] Refactor environment check --- src/BenchmarksApps/TodosApi/AppSettings.cs | 23 ++++++++----------- .../TodosApi/DatabaseConfiguration.cs | 2 +- .../TodosApi/DatabaseInitializer.cs | 2 +- .../TodosApi/HostEnvironmentExtensions.cs | 6 +++++ src/BenchmarksApps/TodosApi/Program.cs | 2 +- 5 files changed, 19 insertions(+), 16 deletions(-) create mode 100644 src/BenchmarksApps/TodosApi/HostEnvironmentExtensions.cs diff --git a/src/BenchmarksApps/TodosApi/AppSettings.cs b/src/BenchmarksApps/TodosApi/AppSettings.cs index 34828f9c2..2bf7c4679 100644 --- a/src/BenchmarksApps/TodosApi/AppSettings.cs +++ b/src/BenchmarksApps/TodosApi/AppSettings.cs @@ -14,16 +14,9 @@ internal class AppSettings // Change to using ValidateDataAnnotations once https://github.com/dotnet/runtime/issues/77412 is complete internal class AppSettingsValidator : IValidateOptions { - private readonly IHostEnvironment _hostEnvironment; - - public AppSettingsValidator(IHostEnvironment hostEnvironment) - { - _hostEnvironment = hostEnvironment; - } - public ValidateOptionsResult Validate(string? name, AppSettings options) { - if (!_hostEnvironment.IsEnvironment("Build") && string.IsNullOrEmpty(options.ConnectionString)) + if (string.IsNullOrEmpty(options.ConnectionString)) { return ValidateOptionsResult.Fail(""" Connection string not found. @@ -38,14 +31,18 @@ Connection string not found. internal static class AppSettingsExtensions { - public static IServiceCollection ConfigureAppSettings(this IServiceCollection services, IConfigurationRoot configurationRoot) + public static IServiceCollection ConfigureAppSettings(this IServiceCollection services, IConfigurationRoot configurationRoot, IHostEnvironment hostEnvironment) { // Can't use the configuration binding source generator due to bug where it emits non-compiling code right now // https://github.com/dotnet/runtime/issues/83600 - services.Configure(configurationRoot.GetSection(nameof(AppSettings))) - .AddSingleton, AppSettingsValidator>() - .AddOptions() - .ValidateOnStart(); + var optionsBuilder = services.Configure(configurationRoot.GetSection(nameof(AppSettings))) + .AddOptions(); + + if (!hostEnvironment.IsBuild()) + { + services.AddSingleton, AppSettingsValidator>(); + optionsBuilder.ValidateOnStart(); + } // Change to using BindConfiguration once https://github.com/dotnet/runtime/issues/83600 is complete //services.AddSingleton, AppSettingsValidator>() diff --git a/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs b/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs index 5e52af0af..5f3b363b6 100644 --- a/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs +++ b/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs @@ -12,7 +12,7 @@ public static IServiceCollection AddDatabase(this IServiceCollection services) { var appSettings = sp.GetRequiredService>().Value; var hostEnvironment = sp.GetRequiredService(); - var db = hostEnvironment.IsEnvironment("Build") + var db = hostEnvironment.IsBuild() ? default! : new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); diff --git a/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs b/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs index fd6b4a512..3cafb55c2 100644 --- a/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs +++ b/src/BenchmarksApps/TodosApi/DatabaseInitializer.cs @@ -13,7 +13,7 @@ public DatabaseInitializer(NpgsqlDataSource db, IOptions appSetting { _db = db; _logger = logger; - _initDatabase = !(hostEnvironment.IsEnvironment("Build") || appSettings.Value.SuppressDbInitialization); + _initDatabase = !(hostEnvironment.IsBuild() || appSettings.Value.SuppressDbInitialization); } public Task StartAsync(CancellationToken cancellationToken) diff --git a/src/BenchmarksApps/TodosApi/HostEnvironmentExtensions.cs b/src/BenchmarksApps/TodosApi/HostEnvironmentExtensions.cs new file mode 100644 index 000000000..88c42c881 --- /dev/null +++ b/src/BenchmarksApps/TodosApi/HostEnvironmentExtensions.cs @@ -0,0 +1,6 @@ +namespace Microsoft.Extensions.Hosting; + +internal static class HostEnvironmentExtensions +{ + public static bool IsBuild(this IHostEnvironment hostEnvironment) => hostEnvironment.IsEnvironment("Build"); +} diff --git a/src/BenchmarksApps/TodosApi/Program.cs b/src/BenchmarksApps/TodosApi/Program.cs index 0ad577b5b..ac77414db 100644 --- a/src/BenchmarksApps/TodosApi/Program.cs +++ b/src/BenchmarksApps/TodosApi/Program.cs @@ -7,7 +7,7 @@ #endif // Bind app settings from configuration & validate -builder.Services.ConfigureAppSettings(builder.Configuration); +builder.Services.ConfigureAppSettings(builder.Configuration, builder.Environment); // Configure authentication & authorization builder.Services.AddAuthentication().AddJwtBearer(); From 5f42e33a00d35091b21cbd303ed6aef4b4fa939a Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Tue, 2 May 2023 09:11:18 -0700 Subject: [PATCH 15/17] Update src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs Co-authored-by: Eric Erhardt --- src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs b/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs index 5f3b363b6..52e6ef410 100644 --- a/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs +++ b/src/BenchmarksApps/TodosApi/DatabaseConfiguration.cs @@ -13,8 +13,8 @@ public static IServiceCollection AddDatabase(this IServiceCollection services) var appSettings = sp.GetRequiredService>().Value; var hostEnvironment = sp.GetRequiredService(); var db = hostEnvironment.IsBuild() - ? default! - : new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); + ? default! + : new NpgsqlSlimDataSourceBuilder(appSettings.ConnectionString).Build(); return db; }); From 991b98ee39975c46c891fb718a6fca1d2c8e883e Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Tue, 2 May 2023 09:17:16 -0700 Subject: [PATCH 16/17] Update appsettings.json --- src/BenchmarksApps/TodosApi/appsettings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/BenchmarksApps/TodosApi/appsettings.json b/src/BenchmarksApps/TodosApi/appsettings.json index d73d9463d..14aee9c59 100644 --- a/src/BenchmarksApps/TodosApi/appsettings.json +++ b/src/BenchmarksApps/TodosApi/appsettings.json @@ -15,5 +15,6 @@ "ValidIssuer": "dotnet-user-jwts" } } - } + }, + "AllowedHosts": "*" } \ No newline at end of file From 51ee72ec9a3fbcac914da621ab4ef353077e10f9 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Tue, 2 May 2023 09:17:41 -0700 Subject: [PATCH 17/17] Update TodosApi.http --- src/BenchmarksApps/TodosApi/TodosApi.http | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BenchmarksApps/TodosApi/TodosApi.http b/src/BenchmarksApps/TodosApi/TodosApi.http index 5e4bad0a0..c9b5ccf1d 100644 --- a/src/BenchmarksApps/TodosApi/TodosApi.http +++ b/src/BenchmarksApps/TodosApi/TodosApi.http @@ -1,6 +1,6 @@ @TodosApi_HostAddress = http://localhost:5054 # Uncomment following line if sending requests to published app -@TodosApi_HostAddress = http://localhost:5000 +#@TodosApi_HostAddress = http://localhost:5000 # For more info on HTTP files go to https://aka.ms/vs/httpfile