diff --git a/.vscode/launch.json b/.vscode/launch.json
index 29787f7..4668dab 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -89,6 +89,24 @@
},
}
},
+ {
+ "name": "Aspire: Run All (Debug)",
+ "type": "coreclr",
+ "preLaunchTask": "dotnet: build (Debug)",
+ "request": "launch",
+ "program": "${workspaceFolder}/src/NServiceBusTutorial.AspireHost/bin/Debug/net9.0/NServiceBusTutorial.AspireHost.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/src/NServiceBusTutorial.AspireHost/bin/Debug/net9.0",
+ "stopAtEntry": false,
+ "internalConsoleOptions": "openOnSessionStart",
+ "env": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21007",
+ "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22245",
+ "ASPNETCORE_URLS": "https://localhost:17143"
+ },
+ },
],
"compounds": [
{
diff --git a/Directory.Packages.props b/Directory.Packages.props
index a43026c..b07e731 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -37,11 +37,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NServiceBusTutorial.sln b/NServiceBusTutorial.sln
index 4ae58bb..638e6fb 100644
--- a/NServiceBusTutorial.sln
+++ b/NServiceBusTutorial.sln
@@ -41,6 +41,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NServiceBusTutorial.Worker"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NServiceBusTutorial.Saga", "src\NServiceBusTutorial.Saga\NServiceBusTutorial.Saga.csproj", "{B171BFFE-FE6D-4EA1-AB48-334072F89B40}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NServiceBusTutorial.AspireHost", "src\NServiceBusTutorial.AspireHost\NServiceBusTutorial.AspireHost.csproj", "{6002A3B9-6FB4-4E0F-89FB-044AB2655434}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NServiceBusTutorial.ServiceDefaults", "src\NServiceBusTutorial.ServiceDefaults\NServiceBusTutorial.ServiceDefaults.csproj", "{6DC1366E-F471-4145-9558-CD1B5EDFEB5D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -171,6 +175,30 @@ Global
{B171BFFE-FE6D-4EA1-AB48-334072F89B40}.Release|x64.Build.0 = Release|Any CPU
{B171BFFE-FE6D-4EA1-AB48-334072F89B40}.Release|x86.ActiveCfg = Release|Any CPU
{B171BFFE-FE6D-4EA1-AB48-334072F89B40}.Release|x86.Build.0 = Release|Any CPU
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434}.Debug|x64.Build.0 = Debug|Any CPU
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434}.Debug|x86.Build.0 = Debug|Any CPU
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434}.Release|x64.ActiveCfg = Release|Any CPU
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434}.Release|x64.Build.0 = Release|Any CPU
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434}.Release|x86.ActiveCfg = Release|Any CPU
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434}.Release|x86.Build.0 = Release|Any CPU
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D}.Debug|x64.Build.0 = Debug|Any CPU
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D}.Debug|x86.Build.0 = Debug|Any CPU
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D}.Release|x64.ActiveCfg = Release|Any CPU
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D}.Release|x64.Build.0 = Release|Any CPU
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D}.Release|x86.ActiveCfg = Release|Any CPU
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -186,6 +214,8 @@ Global
{7A8F52CA-113E-4461-8D91-80A1683DDC26} = {B31B4797-1D9F-4288-808C-BE9A31A98C7D}
{558A7852-42FB-4867-B9AB-0D58F69CD7F6} = {106AE906-5075-410A-B941-912F811848EE}
{B171BFFE-FE6D-4EA1-AB48-334072F89B40} = {106AE906-5075-410A-B941-912F811848EE}
+ {6002A3B9-6FB4-4E0F-89FB-044AB2655434} = {106AE906-5075-410A-B941-912F811848EE}
+ {6DC1366E-F471-4145-9558-CD1B5EDFEB5D} = {106AE906-5075-410A-B941-912F811848EE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B0F19343-8185-4A9F-9165-0EA8544BC925}
diff --git a/docker-compose.development.yml b/docker-compose.development.yml
deleted file mode 100644
index 055b338..0000000
--- a/docker-compose.development.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-services:
- postgres-db:
- image: postgres:latest
- container_name: postgres.db
- ports:
- - 5432:5432
- environment:
- - POSTGRES_USER=postgres
- - POSTGRES_PASSWORD=postgres
- - POSTGRES_DB=NServiceBusTutorial
\ No newline at end of file
diff --git a/src/NServiceBusTutorial.AspireHost/NServiceBusTutorial.AspireHost.csproj b/src/NServiceBusTutorial.AspireHost/NServiceBusTutorial.AspireHost.csproj
new file mode 100644
index 0000000..d4e5a3a
--- /dev/null
+++ b/src/NServiceBusTutorial.AspireHost/NServiceBusTutorial.AspireHost.csproj
@@ -0,0 +1,32 @@
+
+
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+ true
+ c540eeb6-e06b-4456-a539-be58dd8b88c7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/NServiceBusTutorial.AspireHost/Program.cs b/src/NServiceBusTutorial.AspireHost/Program.cs
new file mode 100644
index 0000000..aaa3acd
--- /dev/null
+++ b/src/NServiceBusTutorial.AspireHost/Program.cs
@@ -0,0 +1,23 @@
+var builder = DistributedApplication.CreateBuilder(args);
+
+var username = builder.AddParameter("username", "postgres",secret: false);
+var password = builder.AddParameter("password", "postgres",secret: false);
+
+var postgres = builder.AddPostgres("postgres", username, password, 5432);
+var domainDb = postgres.AddDatabase("NServiceBusTutorial");
+var sagaDb = postgres.AddDatabase("SagaDb");
+
+builder.AddProject("Web")
+ .WithReference(postgres)
+ .WaitFor(domainDb);
+
+builder.AddProject("Saga")
+ .WithReference(postgres)
+ .WaitFor(domainDb)
+ .WaitFor(sagaDb);
+
+builder.AddProject("Worker")
+ .WithReference(postgres)
+ .WaitFor(domainDb);
+
+builder.Build().Run();
diff --git a/src/NServiceBusTutorial.AspireHost/Properties/launchSettings.json b/src/NServiceBusTutorial.AspireHost/Properties/launchSettings.json
new file mode 100644
index 0000000..f3d5d86
--- /dev/null
+++ b/src/NServiceBusTutorial.AspireHost/Properties/launchSettings.json
@@ -0,0 +1,29 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "https://localhost:17143;http://localhost:15258",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21007",
+ "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22245"
+ }
+ },
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:15258",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19187",
+ "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20134"
+ }
+ }
+ }
+}
diff --git a/src/NServiceBusTutorial.AspireHost/appsettings.json b/src/NServiceBusTutorial.AspireHost/appsettings.json
new file mode 100644
index 0000000..31c092a
--- /dev/null
+++ b/src/NServiceBusTutorial.AspireHost/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning",
+ "Aspire.Hosting.Dcp": "Warning"
+ }
+ }
+}
diff --git a/src/NServiceBusTutorial.Infrastructure/Data/AppDbContext.cs b/src/NServiceBusTutorial.Infrastructure/Data/AppDbContext.cs
index 1c485d4..789c0fd 100644
--- a/src/NServiceBusTutorial.Infrastructure/Data/AppDbContext.cs
+++ b/src/NServiceBusTutorial.Infrastructure/Data/AppDbContext.cs
@@ -1,5 +1,4 @@
-using System.Reflection;
-using Ardalis.SharedKernel;
+using Ardalis.SharedKernel;
using NServiceBusTutorial.Core.ContributorAggregate;
using Microsoft.EntityFrameworkCore;
@@ -21,7 +20,7 @@ public AppDbContext(DbContextOptions options,
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
- modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
+ modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
}
public override async Task SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
diff --git a/src/NServiceBusTutorial.Infrastructure/Data/Queries/ListContributorsQueryService.cs b/src/NServiceBusTutorial.Infrastructure/Data/Queries/ListContributorsQueryService.cs
index a41fc25..58b1698 100644
--- a/src/NServiceBusTutorial.Infrastructure/Data/Queries/ListContributorsQueryService.cs
+++ b/src/NServiceBusTutorial.Infrastructure/Data/Queries/ListContributorsQueryService.cs
@@ -12,8 +12,12 @@ public class ListContributorsQueryService(AppDbContext _db) : IListContributorsQ
public async Task> ListAsync()
{
// NOTE: This will fail if testing with EF InMemory provider!
- var result = await _db.Database.SqlQuery(
- $"SELECT Id, Name, PhoneNumber_Number AS PhoneNumber, Verification FROM Contributors") // don't fetch other big columns
+ // var result = await _db.Database.SqlQuery(
+ // $"SELECT Id, Name, PhoneNumber_Number AS PhoneNumber, Verification FROM public.Contributors") // don't fetch other big columns
+ // .ToListAsync();
+ var result = await _db.Contributors
+ .AsNoTracking()
+ .Select(c => new ContributorDTO(c.Id, c.Name, c.PhoneNumber!.Number, c.Verification.Name))
.ToListAsync();
return result;
diff --git a/src/NServiceBusTutorial.Infrastructure/Data/SeedData.cs b/src/NServiceBusTutorial.Infrastructure/Data/SeedData.cs
index 0bcc574..df7301a 100644
--- a/src/NServiceBusTutorial.Infrastructure/Data/SeedData.cs
+++ b/src/NServiceBusTutorial.Infrastructure/Data/SeedData.cs
@@ -1,6 +1,4 @@
using NServiceBusTutorial.Core.ContributorAggregate;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.DependencyInjection;
namespace NServiceBusTutorial.Infrastructure.Data;
@@ -9,15 +7,11 @@ public static class SeedData
public static readonly Contributor Contributor1 = new("Ardalis", new(string.Empty, "123-456-7890", string.Empty), ContributorStatus.CoreTeam, VerificationStatus.Pending);
public static readonly Contributor Contributor2 = new("Snowfrog", new(string.Empty, "098-765-4321", string.Empty), ContributorStatus.Community, VerificationStatus.Pending);
- public static void Initialize(IServiceProvider serviceProvider)
+ public static void Initialize(IServiceProvider serviceProvider, AppDbContext dbContext)
{
- using (var dbContext = new AppDbContext(
- serviceProvider.GetRequiredService>(), null))
- {
- if (dbContext.Contributors.Any()) return; // DB has been seeded
+ if (dbContext.Contributors.Any()) return; // DB has been seeded
- PopulateTestData(dbContext);
- }
+ PopulateTestData(dbContext);
}
public static void PopulateTestData(AppDbContext dbContext)
{
diff --git a/src/NServiceBusTutorial.Infrastructure/NServiceBusTutorial.Infrastructure.csproj b/src/NServiceBusTutorial.Infrastructure/NServiceBusTutorial.Infrastructure.csproj
index ae5150a..ef56d58 100644
--- a/src/NServiceBusTutorial.Infrastructure/NServiceBusTutorial.Infrastructure.csproj
+++ b/src/NServiceBusTutorial.Infrastructure/NServiceBusTutorial.Infrastructure.csproj
@@ -11,6 +11,12 @@
+
+
+
+
+
+
diff --git a/src/NServiceBusTutorial.Saga/ContributorVerificationSaga.cs b/src/NServiceBusTutorial.Saga/ContributorVerificationSaga.cs
index ebd8f58..001c92f 100644
--- a/src/NServiceBusTutorial.Saga/ContributorVerificationSaga.cs
+++ b/src/NServiceBusTutorial.Saga/ContributorVerificationSaga.cs
@@ -1,5 +1,6 @@
using NServiceBusTutorial.Core.ContributorAggregate.Commands;
using NServiceBusTutorial.Core.ContributorAggregate.Events;
+using Serilog;
namespace NServiceBusTutorial.Saga;
@@ -17,6 +18,7 @@ protected override void ConfigureHowToFindSaga(SagaPropertyMapper
+{
+ services.AddSerilog((services, loggerConfiguration) => loggerConfiguration
+ .ReadFrom.Configuration(hostContext.Configuration)
+ .ReadFrom.Services(services)
+ .Enrich.FromLogContext());
+
+ services.AddOpenTelemetry()
+ .ConfigureResource(resourceBuilder => resourceBuilder.AddService(endpointName))
+ .WithTracing(builder =>
+ {
+ builder.AddSource("NServiceBus.*");
+ builder.AddConsoleExporter();
+ });
+});
+
builder.UseNServiceBus(context =>
{
- var endpointConfiguration = new EndpointConfiguration("contributors-saga");
+ var endpointConfiguration = new EndpointConfiguration(endpointName);
endpointConfiguration.UseSerialization();
endpointConfiguration.EnableInstallers();
@@ -37,6 +58,7 @@
return new NpgsqlConnection(connectionString);
});
endpointConfiguration.EnableInstallers();
+ endpointConfiguration.EnableOpenTelemetry();
var recoverability = endpointConfiguration.Recoverability();
recoverability.Immediate(c => c.NumberOfRetries(0));
diff --git a/src/NServiceBusTutorial.Saga/appsettings.json b/src/NServiceBusTutorial.Saga/appsettings.json
index 79365c2..32bf7ae 100644
--- a/src/NServiceBusTutorial.Saga/appsettings.json
+++ b/src/NServiceBusTutorial.Saga/appsettings.json
@@ -1,11 +1,32 @@
{
"ConnectionStrings": {
- "DefaultConnection": "User ID=postgres;Password=postgres;Host=localhost;Port=5432;Database=NServiceBusTutorial;Pooling=true;MinPoolSize=1;MaxPoolSize=100;Timeout=15"
+ "DefaultConnection": "User ID=postgres;Password=postgres;Host=localhost;Port=5432;Database=SagaDb;Pooling=true;MinPoolSize=1;MaxPoolSize=100;Timeout=15"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
+ },
+ "Serilog": {
+ "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.OpenTelemetry" ],
+ "MinimumLevel": {
+ "Default": "Information"
+ },
+ "WriteTo": [
+ {
+ "Name": "Console"
+ },
+ {
+ "Name": "File",
+ "Args": {
+ "path": "logs/log.txt",
+ "rollingInterval": "Day"
+ }
+ },
+ {
+ "Name": "OpenTelemetry"
+ }
+ ]
}
}
diff --git a/src/NServiceBusTutorial.ServiceDefaults/Extensions.cs b/src/NServiceBusTutorial.ServiceDefaults/Extensions.cs
new file mode 100644
index 0000000..87808a3
--- /dev/null
+++ b/src/NServiceBusTutorial.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 TBuilder AddServiceDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder
+ {
+ 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 TBuilder ConfigureOpenTelemetry(this TBuilder builder) where TBuilder : IHostApplicationBuilder
+ {
+ 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 TBuilder AddOpenTelemetryExporters(this TBuilder builder) where TBuilder : IHostApplicationBuilder
+ {
+ 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 TBuilder AddDefaultHealthChecks(this TBuilder builder) where TBuilder : IHostApplicationBuilder
+ {
+ 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/src/NServiceBusTutorial.ServiceDefaults/NServiceBusTutorial.ServiceDefaults.csproj b/src/NServiceBusTutorial.ServiceDefaults/NServiceBusTutorial.ServiceDefaults.csproj
new file mode 100644
index 0000000..09110f1
--- /dev/null
+++ b/src/NServiceBusTutorial.ServiceDefaults/NServiceBusTutorial.ServiceDefaults.csproj
@@ -0,0 +1,22 @@
+
+
+
+ net9.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/NServiceBusTutorial.Web/Program.cs b/src/NServiceBusTutorial.Web/Program.cs
index 82c5ae6..932096e 100644
--- a/src/NServiceBusTutorial.Web/Program.cs
+++ b/src/NServiceBusTutorial.Web/Program.cs
@@ -12,6 +12,10 @@
using Serilog.Extensions.Logging;
using NServiceBusTutorial.Core.ContributorAggregate.Commands;
using NServiceBusTutorial.Core.ContributorAggregate.Events;
+using OpenTelemetry.Trace;
+using OpenTelemetry.Resources;
+
+string endpointName = "contributors-api";
var logger = Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
@@ -26,6 +30,14 @@
var microsoftLogger = new SerilogLoggerFactory(logger)
.CreateLogger();
+builder.Services.AddOpenTelemetry()
+ .ConfigureResource(resourceBuilder => resourceBuilder.AddService(endpointName))
+ .WithTracing(builder =>
+ {
+ builder.AddSource("NServiceBus.*");
+ builder.AddConsoleExporter();
+ });
+
// Configure Web Behavior
builder.Services.Configure(options =>
{
@@ -47,7 +59,7 @@
builder.Host.UseNServiceBus(context =>
{
- var endpointConfiguration = new EndpointConfiguration("contributors-api");
+ var endpointConfiguration = new EndpointConfiguration(endpointName);
endpointConfiguration.UseSerialization();
endpointConfiguration.EnableInstallers();
@@ -65,6 +77,7 @@
endpointConfiguration.SendOnly();
endpointConfiguration.EnableInstallers();
+ endpointConfiguration.EnableOpenTelemetry();
return endpointConfiguration;
});
@@ -100,8 +113,9 @@ static void SeedDatabase(WebApplication app)
{
var context = services.GetRequiredService();
// context.Database.Migrate();
+ context.Database.EnsureDeleted();
context.Database.EnsureCreated();
- SeedData.Initialize(services);
+ SeedData.Initialize(services, context);
}
catch (Exception ex)
{
diff --git a/src/NServiceBusTutorial.Web/appsettings.json b/src/NServiceBusTutorial.Web/appsettings.json
index e30447e..8c2e31d 100644
--- a/src/NServiceBusTutorial.Web/appsettings.json
+++ b/src/NServiceBusTutorial.Web/appsettings.json
@@ -4,6 +4,7 @@
, "SqliteConnection": "Data Source=database.sqlite"
},
"Serilog": {
+ "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.OpenTelemetry" ],
"MinimumLevel": {
"Default": "Information"
},
@@ -17,6 +18,9 @@
"path": "log.txt",
"rollingInterval": "Day"
}
+ },
+ {
+ "Name": "OpenTelemetry"
}
//Uncomment this section if you'd like to push your logs to Azure Application Insights
//Full list of Serilog Sinks can be found here: https://github.com/serilog/serilog/wiki/Provided-Sinks
diff --git a/src/NServiceBusTutorial.Worker/Program.cs b/src/NServiceBusTutorial.Worker/Program.cs
index 6e2de1e..5d43968 100644
--- a/src/NServiceBusTutorial.Worker/Program.cs
+++ b/src/NServiceBusTutorial.Worker/Program.cs
@@ -6,6 +6,11 @@
using NServiceBusTutorial.Infrastructure.Data;
using NServiceBusTutorial.Infrastructure.Notifications;
using NServiceBusTutorial.Worker.Contributors;
+using OpenTelemetry.Resources;
+using OpenTelemetry.Trace;
+using Serilog;
+
+string endpointName = "contributors-worker";
var builder = Host.CreateDefaultBuilder();
@@ -25,11 +30,24 @@
services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies([typeof(ContributorCreateCommandHandler).Assembly]));
services.AddScoped();
services.AddScoped();
+
+ services.AddSerilog((services, loggerConfiguration) => loggerConfiguration
+ .ReadFrom.Configuration(hostContext.Configuration)
+ .ReadFrom.Services(services)
+ .Enrich.FromLogContext());
+
+ services.AddOpenTelemetry()
+ .ConfigureResource(resourceBuilder => resourceBuilder.AddService(endpointName))
+ .WithTracing(builder =>
+ {
+ builder.AddSource("NServiceBus.*");
+ builder.AddConsoleExporter();
+ });
});
builder.UseNServiceBus(context =>
{
- var endpointConfiguration = new EndpointConfiguration("contributors-worker");
+ var endpointConfiguration = new EndpointConfiguration(endpointName);
endpointConfiguration.UseSerialization();
endpointConfiguration.EnableInstallers();
endpointConfiguration.SendFailedMessagesTo("error");
@@ -40,6 +58,8 @@
typeof(StartContributorVerificationCommand),
"contributors-saga");
+ endpointConfiguration.EnableOpenTelemetry();
+
var recoverability = endpointConfiguration.Recoverability();
recoverability.Immediate(c => c.NumberOfRetries(0));
recoverability.Delayed(c => c.NumberOfRetries(0));
diff --git a/src/NServiceBusTutorial.Worker/appsettings.json b/src/NServiceBusTutorial.Worker/appsettings.json
index ab06c07..a79eace 100644
--- a/src/NServiceBusTutorial.Worker/appsettings.json
+++ b/src/NServiceBusTutorial.Worker/appsettings.json
@@ -8,5 +8,26 @@
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
+ },
+ "Serilog": {
+ "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.OpenTelemetry" ],
+ "MinimumLevel": {
+ "Default": "Information"
+ },
+ "WriteTo": [
+ {
+ "Name": "Console"
+ },
+ {
+ "Name": "File",
+ "Args": {
+ "path": "log.txt",
+ "rollingInterval": "Day"
+ }
+ },
+ {
+ "Name": "OpenTelemetry"
+ }
+ ]
}
}