diff --git a/.github/workflows/build-and-dockerize.yml b/.github/workflows/build-and-dockerize.yml
index 7fb4ebe5..2a7a68f4 100644
--- a/.github/workflows/build-and-dockerize.yml
+++ b/.github/workflows/build-and-dockerize.yml
@@ -39,7 +39,6 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- dotnet-quality: 'preview'
- name: Install dependencies
run: dotnet restore
- name: Build
diff --git a/BervProject.WebApi.Boilerplate.AppHost/BervProject.WebApi.Boilerplate.AppHost.csproj b/BervProject.WebApi.Boilerplate.AppHost/BervProject.WebApi.Boilerplate.AppHost.csproj
new file mode 100644
index 00000000..0469cd84
--- /dev/null
+++ b/BervProject.WebApi.Boilerplate.AppHost/BervProject.WebApi.Boilerplate.AppHost.csproj
@@ -0,0 +1,26 @@
+
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+ true
+ 0f1966e4-7b2b-4a28-a9b6-8198aab433ec
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BervProject.WebApi.Boilerplate.AppHost/Program.cs b/BervProject.WebApi.Boilerplate.AppHost/Program.cs
new file mode 100644
index 00000000..00f371eb
--- /dev/null
+++ b/BervProject.WebApi.Boilerplate.AppHost/Program.cs
@@ -0,0 +1,32 @@
+var builder = DistributedApplication.CreateBuilder(args);
+
+var cache = builder.AddRedis("cache").WithRedisInsight();
+var postgres = builder.AddPostgres("postgres").WithPgAdmin();
+var postgresdb = postgres.AddDatabase("postgresdb");
+var serviceBus = builder.AddAzureServiceBus("messaging").RunAsEmulator();
+var storage = builder.AddAzureStorage("storage").RunAsEmulator();
+var blobs = storage.AddBlobs("blobs");
+var queues = storage.AddQueues("queues");
+var tables = storage.AddTables("tables");
+
+var migration = builder.AddProject("migrations")
+ .WithReference(postgresdb, connectionName: "BoilerplateConnectionString")
+ .WithExplicitStart();
+
+builder.AddProject("apiservice")
+ .WithHttpEndpoint()
+ .WithReference(cache, connectionName: "Redis")
+ .WithReference(postgresdb, connectionName: "BoilerplateConnectionString")
+ .WithReference(blobs, connectionName: "AzureStorageBlob")
+ .WithReference(queues, connectionName: "AzureStorageQueue")
+ .WithReference(tables, connectionName: "AzureStorageTable")
+ .WithReference(serviceBus, connectionName: "AzureServiceBus")
+ .WaitFor(cache)
+ .WaitFor(postgresdb)
+ .WaitFor(blobs)
+ .WaitFor(queues)
+ .WaitFor(tables)
+ .WaitFor(serviceBus)
+ .WaitForCompletion(migration);
+
+builder.Build().Run();
diff --git a/BervProject.WebApi.Boilerplate.AppHost/appsettings.Development.json b/BervProject.WebApi.Boilerplate.AppHost/appsettings.Development.json
new file mode 100644
index 00000000..0c208ae9
--- /dev/null
+++ b/BervProject.WebApi.Boilerplate.AppHost/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/BervProject.WebApi.Boilerplate.AppHost/appsettings.json b/BervProject.WebApi.Boilerplate.AppHost/appsettings.json
new file mode 100644
index 00000000..31c092aa
--- /dev/null
+++ b/BervProject.WebApi.Boilerplate.AppHost/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning",
+ "Aspire.Hosting.Dcp": "Warning"
+ }
+ }
+}
diff --git a/BervProject.WebApi.Boilerplate.MigrationService/BervProject.WebApi.Boilerplate.MigrationService.csproj b/BervProject.WebApi.Boilerplate.MigrationService/BervProject.WebApi.Boilerplate.MigrationService.csproj
new file mode 100644
index 00000000..ca71465b
--- /dev/null
+++ b/BervProject.WebApi.Boilerplate.MigrationService/BervProject.WebApi.Boilerplate.MigrationService.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net9.0
+ enable
+ enable
+ dotnet-BervProject.WebApi.Boilerplate.MigrationService-02d1add9-9cd8-4b0e-96ab-9dedc82c871c
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BervProject.WebApi.Boilerplate.MigrationService/Program.cs b/BervProject.WebApi.Boilerplate.MigrationService/Program.cs
new file mode 100644
index 00000000..d228a1d4
--- /dev/null
+++ b/BervProject.WebApi.Boilerplate.MigrationService/Program.cs
@@ -0,0 +1,15 @@
+using BervProject.WebApi.Boilerplate.EntityFramework;
+using BervProject.WebApi.Boilerplate.MigrationService;
+
+var builder = Host.CreateApplicationBuilder(args);
+
+builder.AddServiceDefaults();
+
+builder.Services.AddHostedService();
+
+builder.Services.AddOpenTelemetry()
+ .WithTracing(tracing => tracing.AddSource(Worker.ActivitySourceName));
+builder.AddNpgsqlDbContext("BoilerplateConnectionString");
+
+var host = builder.Build();
+host.Run();
diff --git a/BervProject.WebApi.Boilerplate.MigrationService/Worker.cs b/BervProject.WebApi.Boilerplate.MigrationService/Worker.cs
new file mode 100644
index 00000000..df663d0d
--- /dev/null
+++ b/BervProject.WebApi.Boilerplate.MigrationService/Worker.cs
@@ -0,0 +1,52 @@
+using System.Diagnostics;
+using BervProject.WebApi.Boilerplate.EntityFramework;
+using Microsoft.EntityFrameworkCore;
+
+namespace BervProject.WebApi.Boilerplate.MigrationService;
+
+public class Worker : BackgroundService
+{
+ public const string ActivitySourceName = "Migrations";
+ private static readonly ActivitySource SActivitySource = new(ActivitySourceName);
+
+ private readonly IServiceProvider _serviceProvider;
+ private readonly IHostApplicationLifetime _hostApplicationLifetime;
+
+ public Worker(IServiceProvider serviceProvider,
+ IHostApplicationLifetime hostApplicationLifetime)
+ {
+ _serviceProvider = serviceProvider;
+ _hostApplicationLifetime = hostApplicationLifetime;
+ }
+
+ protected override async Task ExecuteAsync(CancellationToken cancellationToken)
+ {
+ using var activity = SActivitySource.StartActivity("Migrating database", ActivityKind.Client);
+
+ try
+ {
+ using var scope = _serviceProvider.CreateScope();
+ var dbContext = scope.ServiceProvider.GetRequiredService();
+
+ await RunMigrationAsync(dbContext, cancellationToken);
+ }
+ catch (Exception ex)
+ {
+ activity?.AddException(ex);
+ throw;
+ }
+
+ _hostApplicationLifetime.StopApplication();
+ }
+
+ private static async Task RunMigrationAsync(BoilerplateDbContext dbContext, CancellationToken cancellationToken)
+ {
+ var strategy = dbContext.Database.CreateExecutionStrategy();
+ await strategy.ExecuteAsync(async () =>
+ {
+ // Run migration in a transaction to avoid partial migration if it fails.
+ await dbContext.Database.MigrateAsync(cancellationToken);
+ });
+ }
+
+}
diff --git a/BervProject.WebApi.Boilerplate.MigrationService/appsettings.Development.json b/BervProject.WebApi.Boilerplate.MigrationService/appsettings.Development.json
new file mode 100644
index 00000000..b2dcdb67
--- /dev/null
+++ b/BervProject.WebApi.Boilerplate.MigrationService/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/BervProject.WebApi.Boilerplate.MigrationService/appsettings.json b/BervProject.WebApi.Boilerplate.MigrationService/appsettings.json
new file mode 100644
index 00000000..b2dcdb67
--- /dev/null
+++ b/BervProject.WebApi.Boilerplate.MigrationService/appsettings.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/BervProject.WebApi.Boilerplate.ServiceDefaults/BervProject.WebApi.Boilerplate.ServiceDefaults.csproj b/BervProject.WebApi.Boilerplate.ServiceDefaults/BervProject.WebApi.Boilerplate.ServiceDefaults.csproj
new file mode 100644
index 00000000..eeda27dd
--- /dev/null
+++ b/BervProject.WebApi.Boilerplate.ServiceDefaults/BervProject.WebApi.Boilerplate.ServiceDefaults.csproj
@@ -0,0 +1,22 @@
+
+
+
+ net9.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BervProject.WebApi.Boilerplate.ServiceDefaults/Extensions.cs b/BervProject.WebApi.Boilerplate.ServiceDefaults/Extensions.cs
new file mode 100644
index 00000000..2a3f4e07
--- /dev/null
+++ b/BervProject.WebApi.Boilerplate.ServiceDefaults/Extensions.cs
@@ -0,0 +1,118 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Diagnostics.HealthChecks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.ServiceDiscovery;
+using OpenTelemetry;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Trace;
+
+namespace Microsoft.Extensions.Hosting;
+
+// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
+// This project should be referenced by each service project in your solution.
+// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults
+public static class Extensions
+{
+ public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
+ {
+ builder.ConfigureOpenTelemetry();
+
+ builder.AddDefaultHealthChecks();
+
+ builder.Services.AddServiceDiscovery();
+
+ builder.Services.ConfigureHttpClientDefaults(http =>
+ {
+ // Turn on resilience by default
+ http.AddStandardResilienceHandler();
+
+ // Turn on service discovery by default
+ http.AddServiceDiscovery();
+ });
+
+ // Uncomment the following to restrict the allowed schemes for service discovery.
+ // builder.Services.Configure(options =>
+ // {
+ // options.AllowedSchemes = ["https"];
+ // });
+
+ return builder;
+ }
+
+ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder)
+ {
+ builder.Logging.AddOpenTelemetry(logging =>
+ {
+ logging.IncludeFormattedMessage = true;
+ logging.IncludeScopes = true;
+ });
+
+ builder.Services.AddOpenTelemetry()
+ .WithMetrics(metrics =>
+ {
+ metrics.AddAspNetCoreInstrumentation()
+ .AddHttpClientInstrumentation()
+ .AddRuntimeInstrumentation();
+ })
+ .WithTracing(tracing =>
+ {
+ tracing.AddAspNetCoreInstrumentation()
+ // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
+ //.AddGrpcClientInstrumentation()
+ .AddHttpClientInstrumentation();
+ });
+
+ builder.AddOpenTelemetryExporters();
+
+ return builder;
+ }
+
+ private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostApplicationBuilder builder)
+ {
+ var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
+
+ if (useOtlpExporter)
+ {
+ builder.Services.AddOpenTelemetry().UseOtlpExporter();
+ }
+
+ // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
+ //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
+ //{
+ // builder.Services.AddOpenTelemetry()
+ // .UseAzureMonitor();
+ //}
+
+ return builder;
+ }
+
+ public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicationBuilder builder)
+ {
+ builder.Services.AddHealthChecks()
+ // Add a default liveness check to ensure app is responsive
+ .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
+
+ return builder;
+ }
+
+ public static WebApplication MapDefaultEndpoints(this WebApplication app)
+ {
+ // Adding health checks endpoints to applications in non-development environments has security implications.
+ // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
+ if (app.Environment.IsDevelopment())
+ {
+ // All health checks must pass for app to be considered ready to accept traffic after starting
+ app.MapHealthChecks("/health");
+
+ // Only health checks tagged with the "live" tag must pass for app to be considered alive
+ app.MapHealthChecks("/alive", new HealthCheckOptions
+ {
+ Predicate = r => r.Tags.Contains("live")
+ });
+ }
+
+ return app;
+ }
+}
diff --git a/BervProject.WebApi.Boilerplate.sln b/BervProject.WebApi.Boilerplate.sln
index e9626cd0..c83925f2 100644
--- a/BervProject.WebApi.Boilerplate.sln
+++ b/BervProject.WebApi.Boilerplate.sln
@@ -19,24 +19,94 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BervProject.WebApi.Integration.Test", "BervProject.WebApi.Integration.Test\BervProject.WebApi.Integration.Test.csproj", "{B1139AC3-3DC2-453D-9A72-9C7196F9759C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BervProject.WebApi.Boilerplate.AppHost", "BervProject.WebApi.Boilerplate.AppHost\BervProject.WebApi.Boilerplate.AppHost.csproj", "{D6E4407A-586B-4D75-A5F7-5AC9E7016614}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BervProject.WebApi.Boilerplate.ServiceDefaults", "BervProject.WebApi.Boilerplate.ServiceDefaults\BervProject.WebApi.Boilerplate.ServiceDefaults.csproj", "{3E0AA90A-F50F-4226-8236-947B6DC82BCC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BervProject.WebApi.Boilerplate.MigrationService", "BervProject.WebApi.Boilerplate.MigrationService\BervProject.WebApi.Boilerplate.MigrationService.csproj", "{94B60493-45E4-4437-9155-3D30DFBFB66A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Debug|x64.Build.0 = Debug|Any CPU
+ {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Debug|x86.Build.0 = Debug|Any CPU
{61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Release|Any CPU.ActiveCfg = Release|Any CPU
{61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Release|Any CPU.Build.0 = Release|Any CPU
+ {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Release|x64.ActiveCfg = Release|Any CPU
+ {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Release|x64.Build.0 = Release|Any CPU
+ {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Release|x86.ActiveCfg = Release|Any CPU
+ {61F9CED4-DF01-40F5-A126-DE9F73C7AA89}.Release|x86.Build.0 = Release|Any CPU
{CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Debug|x64.Build.0 = Debug|Any CPU
+ {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Debug|x86.Build.0 = Debug|Any CPU
{CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Release|x64.ActiveCfg = Release|Any CPU
+ {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Release|x64.Build.0 = Release|Any CPU
+ {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Release|x86.ActiveCfg = Release|Any CPU
+ {CE1B1BF2-9EF2-4C07-902F-817D81EFD22E}.Release|x86.Build.0 = Release|Any CPU
{B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Debug|x64.Build.0 = Debug|Any CPU
+ {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Debug|x86.Build.0 = Debug|Any CPU
{B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Release|x64.ActiveCfg = Release|Any CPU
+ {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Release|x64.Build.0 = Release|Any CPU
+ {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Release|x86.ActiveCfg = Release|Any CPU
+ {B1139AC3-3DC2-453D-9A72-9C7196F9759C}.Release|x86.Build.0 = Release|Any CPU
+ {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Debug|x64.Build.0 = Debug|Any CPU
+ {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Debug|x86.Build.0 = Debug|Any CPU
+ {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Release|x64.ActiveCfg = Release|Any CPU
+ {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Release|x64.Build.0 = Release|Any CPU
+ {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Release|x86.ActiveCfg = Release|Any CPU
+ {D6E4407A-586B-4D75-A5F7-5AC9E7016614}.Release|x86.Build.0 = Release|Any CPU
+ {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Debug|x64.Build.0 = Debug|Any CPU
+ {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Debug|x86.Build.0 = Debug|Any CPU
+ {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Release|x64.ActiveCfg = Release|Any CPU
+ {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Release|x64.Build.0 = Release|Any CPU
+ {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Release|x86.ActiveCfg = Release|Any CPU
+ {3E0AA90A-F50F-4226-8236-947B6DC82BCC}.Release|x86.Build.0 = Release|Any CPU
+ {94B60493-45E4-4437-9155-3D30DFBFB66A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {94B60493-45E4-4437-9155-3D30DFBFB66A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {94B60493-45E4-4437-9155-3D30DFBFB66A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {94B60493-45E4-4437-9155-3D30DFBFB66A}.Debug|x64.Build.0 = Debug|Any CPU
+ {94B60493-45E4-4437-9155-3D30DFBFB66A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {94B60493-45E4-4437-9155-3D30DFBFB66A}.Debug|x86.Build.0 = Debug|Any CPU
+ {94B60493-45E4-4437-9155-3D30DFBFB66A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {94B60493-45E4-4437-9155-3D30DFBFB66A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {94B60493-45E4-4437-9155-3D30DFBFB66A}.Release|x64.ActiveCfg = Release|Any CPU
+ {94B60493-45E4-4437-9155-3D30DFBFB66A}.Release|x64.Build.0 = Release|Any CPU
+ {94B60493-45E4-4437-9155-3D30DFBFB66A}.Release|x86.ActiveCfg = Release|Any CPU
+ {94B60493-45E4-4437-9155-3D30DFBFB66A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/BervProject.WebApi.Boilerplate/BervProject.WebApi.Boilerplate.csproj b/BervProject.WebApi.Boilerplate/BervProject.WebApi.Boilerplate.csproj
index bacabe8b..efe6affd 100644
--- a/BervProject.WebApi.Boilerplate/BervProject.WebApi.Boilerplate.csproj
+++ b/BervProject.WebApi.Boilerplate/BervProject.WebApi.Boilerplate.csproj
@@ -3,6 +3,7 @@
net9.0
BervProject.WebApi.Boilerplate
+ true
@@ -31,6 +32,7 @@
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/BervProject.WebApi.Boilerplate/Extensions/SetupAzureExtension.cs b/BervProject.WebApi.Boilerplate/Extensions/SetupAzureExtension.cs
index fbe1d6d7..0dc6a248 100644
--- a/BervProject.WebApi.Boilerplate/Extensions/SetupAzureExtension.cs
+++ b/BervProject.WebApi.Boilerplate/Extensions/SetupAzureExtension.cs
@@ -1,23 +1,24 @@
-namespace BervProject.WebApi.Boilerplate.Extenstions;
+using Microsoft.Extensions.Configuration;
-using BervProject.WebApi.Boilerplate.ConfigModel;
-using BervProject.WebApi.Boilerplate.Entities;
+namespace BervProject.WebApi.Boilerplate.Extenstions;
+
+using Entities;
using BervProject.WebApi.Boilerplate.Services.Azure;
-using BervProject.WebApi.Boilerplate.Services;
+using Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Azure;
public static class SetupAzureExtension
{
- public static void SetupAzure(this IServiceCollection services, AzureConfiguration azureConfig)
+ public static void SetupAzure(this IServiceCollection services, ConfigurationManager config)
{
services.AddAzureClients(builder =>
{
- builder.AddBlobServiceClient(azureConfig.Storage.Blob.ConnectionString);
- builder.AddQueueServiceClient(azureConfig.Storage.Queue.ConnectionString);
- builder.AddServiceBusClient(azureConfig.ServiceBus.ConnectionString);
- builder.AddTableServiceClient(azureConfig.Storage.Table.ConnectionString);
+ builder.AddBlobServiceClient(config.GetConnectionString("AzureStorageBlob"));
+ builder.AddQueueServiceClient(config.GetConnectionString("AzureStorageQueue"));
+ builder.AddServiceBusClient(config.GetConnectionString("AzureServiceBus"));
+ builder.AddTableServiceClient(config.GetConnectionString("AzureStorageTable"));
});
services.AddScoped();
services.AddScoped();
diff --git a/BervProject.WebApi.Boilerplate/Program.cs b/BervProject.WebApi.Boilerplate/Program.cs
index 989ffcd7..dd26e9be 100644
--- a/BervProject.WebApi.Boilerplate/Program.cs
+++ b/BervProject.WebApi.Boilerplate/Program.cs
@@ -15,6 +15,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
+using Microsoft.OpenApi.Models;
using NLog.Web;
var builder = WebApplication.CreateBuilder(args);
@@ -36,17 +37,20 @@
builder.Services.SetupAWS();
// azure services
-builder.Services.SetupAzure(azureConfig);
+builder.Services.SetupAzure(builder.Configuration);
// cron services
builder.Services.AddScoped();
-builder.Services.AddHangfire(x => x.UsePostgreSqlStorage(builder.Configuration.GetConnectionString("BoilerplateConnectionString")));
+builder.Services.AddHangfire(x => x.UsePostgreSqlStorage(opt =>
+{
+ opt.UseNpgsqlConnection(builder.Configuration.GetConnectionString("BoilerplateConnectionString"));
+}));
builder.Services.AddHangfireServer();
// essential services
builder.Services.AddStackExchangeRedisCache(options =>
{
- options.Configuration = builder.Configuration["Redis:ConnectionString"];
+ options.Configuration = builder.Configuration.GetConnectionString("Redis");
});
builder.Services.AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString("BoilerplateConnectionString")));
@@ -57,6 +61,12 @@
{
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
+ options.SwaggerDoc("v1", new OpenApiInfo
+ {
+ Version = "v1",
+ Title = "Boilerplate API",
+ Description = "An ASP.NET Core Web API"
+ });
});
var app = builder.Build();
diff --git a/BervProject.WebApi.Boilerplate/appsettings.json b/BervProject.WebApi.Boilerplate/appsettings.json
index 7b3bd18b..c37a0274 100644
--- a/BervProject.WebApi.Boilerplate/appsettings.json
+++ b/BervProject.WebApi.Boilerplate/appsettings.json
@@ -25,27 +25,23 @@
"Azure": {
"Storage": {
"Blob": {
- "ConnectionString": "UseDevelopmentStorage=true",
"ContainerName": "testblob"
},
"Queue": {
- "ConnectionString": "UseDevelopmentStorage=true",
"QueueName": "testqueue"
- },
- "Table": {
- "ConnectionString": "UseDevelopmentStorage=true"
}
},
"ServiceBus": {
- "ConnectionString": "",
- "QueueName": "",
- "TopicName": ""
+ "QueueName": "testqueue",
+ "TopicName": "testtopic"
}
},
"ConnectionStrings": {
- "BoilerplateConnectionString": "Host=localhost;Database=testdb;Username=postgres;Password=devpass4444"
- },
- "Redis": {
- "ConnectionString": "localhost:6379"
+ "BoilerplateConnectionString": "Host=localhost;Database=testdb;Username=postgres;Password=devpass4444",
+ "AzureStorageBlob": "UseDevelopmentStorage=true",
+ "AzureStorageQueue": "UseDevelopmentStorage=true",
+ "AzureStorageTable": "UseDevelopmentStorage=true",
+ "AzureServiceBus": "",
+ "Redis": "localhost:6379"
}
}
diff --git a/BervProject.WebApi.Integration.Test/BervProject.WebApi.Integration.Test.csproj b/BervProject.WebApi.Integration.Test/BervProject.WebApi.Integration.Test.csproj
index 2d056445..1bd40f14 100644
--- a/BervProject.WebApi.Integration.Test/BervProject.WebApi.Integration.Test.csproj
+++ b/BervProject.WebApi.Integration.Test/BervProject.WebApi.Integration.Test.csproj
@@ -4,7 +4,7 @@
net9.0
enable
enable
-
+ false
false
diff --git a/BervProject.WebApi.Test/BervProject.WebApi.Test.csproj b/BervProject.WebApi.Test/BervProject.WebApi.Test.csproj
index 21d26101..0eaadeb6 100644
--- a/BervProject.WebApi.Test/BervProject.WebApi.Test.csproj
+++ b/BervProject.WebApi.Test/BervProject.WebApi.Test.csproj
@@ -2,7 +2,7 @@
net9.0
-
+ false
false
diff --git a/README.md b/README.md
index 084826cd..e4043ea7 100644
--- a/README.md
+++ b/README.md
@@ -8,9 +8,9 @@ Net Core Web API Boilerplate for My Project
## Build Status
-| Github Action | Azure Pipelines | Codecov |
-|:-------------:|:---------------:|:-------:|
-|  | [](https://dev.azure.com/berviantoleo/NETCoreWebAPIBoilerplate/_build/latest?definitionId=6&branchName=main) | [](https://codecov.io/gh/bervProject/NETCoreAPIBoilerplate) |
+| Github Action (Build) | Github Action (Docker) | Azure Pipelines | Codecov |
+|:---:|:---:|:---:|:---:|
+| [](https://github.com/bervProject/NETCoreAPIBoilerplate/actions/workflows/build-and-dockerize.yml) | [](https://github.com/bervProject/NETCoreAPIBoilerplate/actions/workflows/docker.yml) | [](https://dev.azure.com/berviantoleo/NETCoreWebAPIBoilerplate/_build/latest?definitionId=6&branchName=main) | [](https://codecov.io/gh/bervProject/NETCoreAPIBoilerplate) |
## LICENSE
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 1dca922a..5c4a5af5 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -82,7 +82,7 @@ jobs:
displayName: 'Publish the project - $(buildConfiguration)'
inputs:
command: 'publish'
- projects: '**/*.csproj'
+ projects: '**/BervProject.WebApi.Boilerplate.csproj'
publishWebProjects: false
arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
zipAfterPublish: true