Skip to content

Commit a96f259

Browse files
Copilotkamilbaczek
andcommitted
Add Aspire connection string support for PostgreSQL and RabbitMQ, update README
Co-authored-by: kamilbaczek <74410956+kamilbaczek@users.noreply.github.com>
1 parent 060985b commit a96f259

5 files changed

Lines changed: 96 additions & 8 deletions

File tree

Chapter-3-microservice-extraction/Fitnet.Contracts/Src/Fitnet.Contracts.Infrastructure/Database/DatabaseModule.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,24 @@ namespace EvolutionaryArchitecture.Fitnet.Contracts.Infrastructure.Database;
1010
internal static class DatabaseModule
1111
{
1212
private const string DatabaseConfigurationSection = "Database";
13+
private const string PostgresConnectionName = "fitnet";
1314

1415
internal static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration)
1516
{
1617
services.Configure<DatabaseOptions>(options => configuration.GetSection(DatabaseConfigurationSection).Bind(options));
1718
services.AddDbContext<ContractsPersistence>((serviceProvider, options) =>
1819
{
19-
var databaseOptions = serviceProvider.GetRequiredService<IOptions<DatabaseOptions>>();
20-
options.UseNpgsql(databaseOptions.Value.ConnectionString);
20+
// Try to get Aspire connection string first
21+
var connectionString = configuration.GetConnectionString(PostgresConnectionName);
22+
23+
if (string.IsNullOrEmpty(connectionString))
24+
{
25+
// Fallback to legacy configuration
26+
var databaseOptions = serviceProvider.GetRequiredService<IOptions<DatabaseOptions>>();
27+
connectionString = databaseOptions.Value.ConnectionString;
28+
}
29+
30+
options.UseNpgsql(connectionString);
2131
});
2232
services.AddRepositories();
2333

Chapter-3-microservice-extraction/Fitnet/Src/Offers/Fitnet.Offers.DataAccess/Database/DatabaseModule.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,24 @@ namespace EvolutionaryArchitecture.Fitnet.Offers.DataAccess.Database;
99
internal static class DatabaseModule
1010
{
1111
private const string DatabaseConfigurationSection = "Database";
12+
private const string PostgresConnectionName = "fitnet";
1213

1314
internal static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration)
1415
{
1516
services.Configure<DatabaseOptions>(_ => configuration.GetSection(DatabaseConfigurationSection));
1617
services.AddDbContext<OffersPersistence>((serviceProvider, options) =>
1718
{
18-
var databaseOptions = serviceProvider.GetRequiredService<IOptions<DatabaseOptions>>();
19-
options.UseNpgsql(databaseOptions.Value.ConnectionString);
19+
// Try to get Aspire connection string first
20+
var connectionString = configuration.GetConnectionString(PostgresConnectionName);
21+
22+
if (string.IsNullOrEmpty(connectionString))
23+
{
24+
// Fallback to legacy configuration
25+
var databaseOptions = serviceProvider.GetRequiredService<IOptions<DatabaseOptions>>();
26+
connectionString = databaseOptions.Value.ConnectionString;
27+
}
28+
29+
options.UseNpgsql(connectionString);
2030
});
2131

2232
return services;

Chapter-3-microservice-extraction/Fitnet/Src/Passes/Fitnet.Passes.DataAccess/Database/DatabaseModule.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,24 @@ namespace EvolutionaryArchitecture.Fitnet.Passes.DataAccess.Database;
99
internal static class DatabaseModule
1010
{
1111
private const string DatabaseConfigurationSection = "Database";
12+
private const string PostgresConnectionName = "fitnet";
1213

1314
internal static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration)
1415
{
1516
services.Configure<DatabaseOptions>(_ => configuration.GetSection(DatabaseConfigurationSection));
1617
services.AddDbContext<PassesPersistence>((serviceProvider, options) =>
1718
{
18-
var databaseOptions = serviceProvider.GetRequiredService<IOptions<DatabaseOptions>>();
19-
options.UseNpgsql(databaseOptions.Value.ConnectionString);
19+
// Try to get Aspire connection string first
20+
var connectionString = configuration.GetConnectionString(PostgresConnectionName);
21+
22+
if (string.IsNullOrEmpty(connectionString))
23+
{
24+
// Fallback to legacy configuration
25+
var databaseOptions = serviceProvider.GetRequiredService<IOptions<DatabaseOptions>>();
26+
connectionString = databaseOptions.Value.ConnectionString;
27+
}
28+
29+
options.UseNpgsql(connectionString);
2030
});
2131

2232
return services;

Chapter-3-microservice-extraction/Fitnet/Src/Reports/Fitnet.Reports/DataAccess/DatabaseConnectionFactory.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
namespace EvolutionaryArchitecture.Fitnet.Reports.DataAccess;
22

3+
using Microsoft.Extensions.Configuration;
34
using Microsoft.Extensions.Options;
45
using System.Data;
56
using Npgsql;
67

7-
internal sealed class DatabaseConnectionFactory(IOptions<DatabaseOptions> databaseOptions) : IDatabaseConnectionFactory
8+
internal sealed class DatabaseConnectionFactory : IDatabaseConnectionFactory
89
{
10+
private readonly string _connectionString;
911
private NpgsqlConnection? _connection;
12+
13+
public DatabaseConnectionFactory(IOptions<DatabaseOptions> databaseOptions, IConfiguration configuration)
14+
{
15+
// Try to get Aspire connection string first
16+
_connectionString = configuration.GetConnectionString("fitnet") ?? databaseOptions.Value.ConnectionString ?? throw new InvalidOperationException("Database connection string is not configured");
17+
}
1018

1119
public IDbConnection Create()
1220
{
@@ -15,7 +23,7 @@ public IDbConnection Create()
1523
return _connection;
1624
}
1725

18-
_connection = new NpgsqlConnection(databaseOptions.Value.ConnectionString);
26+
_connection = new NpgsqlConnection(_connectionString);
1927
_connection.Open();
2028

2129
return _connection;

Chapter-3-microservice-extraction/README.adoc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,56 @@ The `Contracts` microservice runs on port `:8081`. Please navigate to http://loc
160160

161161
That's it! You should now be able to run the application using either one of the above. :thumbsup:
162162

163+
=== Run with .NET Aspire (Recommended)
164+
165+
.NET Aspire provides a modern way to run and orchestrate distributed applications with built-in observability, service discovery, and resilience. This is the recommended approach for local development.
166+
167+
==== Requirements
168+
- .NET SDK 9.0 or higher
169+
- Docker (for PostgreSQL and RabbitMQ containers)
170+
171+
==== Steps to run
172+
173+
1. Create you own personal access token in Github (it is needed to be able to download our GH Packages for `Common`). Instruction how to do it you can find https://www.educative.io/answers/how-to-create-a-personal-access-token-for-github-access[here]. Your PAT must have only one value of `read:packages`.
174+
175+
2. Configure NuGet credentials as described in the "Building and debugging code in Rider IDE" section below.
176+
177+
3. Navigate to the AppHost directory:
178+
[source,shell]
179+
----
180+
cd Fitnet.AppHost
181+
----
182+
183+
4. Run the Aspire AppHost:
184+
[source,shell]
185+
----
186+
dotnet run
187+
----
188+
189+
The Aspire Dashboard will automatically open in your browser, showing:
190+
191+
- **Services**: All running services (Fitnet modular monolith and Contracts microservice)
192+
- **Resources**: PostgreSQL database and RabbitMQ message broker
193+
- **Traces**: Distributed tracing across all services
194+
- **Metrics**: Performance metrics for each service
195+
- **Logs**: Consolidated logs from all services
196+
197+
The applications will be available at:
198+
199+
- Fitnet modular monolith: http://localhost:8080 or http://localhost:8080/swagger/index.html
200+
- Contracts microservice: http://localhost:8081 or http://localhost:8081/swagger/index.html
201+
- Aspire Dashboard: The URL will be displayed in the console when you run the AppHost
202+
203+
==== Benefits of using Aspire
204+
205+
- **Automatic orchestration**: PostgreSQL and RabbitMQ are automatically started as Docker containers
206+
- **Service discovery**: Services can discover each other automatically
207+
- **Observability**: Built-in distributed tracing, metrics, and log aggregation
208+
- **Connection strings**: Automatically injected into services
209+
- **Health checks**: Monitor the health of all services and dependencies
210+
- **Resilience**: HTTP clients are configured with retry policies and circuit breakers
211+
212+
163213
=== Building and debugging code in Rider IDE
164214

165215
Before you build or debug code in `Rider` or `Visual Studio` IDE, you first have to provide your user name and previously generated PAT for artifactory to download packages for `Common` which is a part of this repository. When you load the solution, your IDE should request the credentials:

0 commit comments

Comments
 (0)