Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Aspire #80

Merged
merged 11 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CleanArchitecture.Api/CleanArchitecture.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<ProjectReference Include="..\CleanArchitecture.Domain\CleanArchitecture.Domain.csproj" />
<ProjectReference Include="..\CleanArchitecture.gRPC\CleanArchitecture.gRPC.csproj" />
<ProjectReference Include="..\CleanArchitecture.Infrastructure\CleanArchitecture.Infrastructure.csproj" />
<ProjectReference Include="..\CleanArchitecture.ServiceDefaults\CleanArchitecture.ServiceDefaults.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
41 changes: 41 additions & 0 deletions CleanArchitecture.Api/Extensions/ConfigurationExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using CleanArchitecture.Domain.Rabbitmq;
using Microsoft.Extensions.Configuration;

namespace CleanArchitecture.Api.Extensions;

public static class ConfigurationExtensions
{
public static RabbitMqConfiguration GetRabbitMqConfiguration(
this IConfiguration configuration)
{
var isAspire = configuration["ASPIRE_ENABLED"] == "true";

var rabbitEnabled = configuration["RabbitMQ:Enabled"];
var rabbitHost = configuration["RabbitMQ:Host"];
var rabbitPort = configuration["RabbitMQ:Port"];
var rabbitUser = configuration["RabbitMQ:Username"];
var rabbitPass = configuration["RabbitMQ:Password"];

if (isAspire)
{
rabbitEnabled = "true";
var connectionString = configuration["ConnectionStrings:RabbitMq"];

var rabbitUri = new Uri(connectionString!);
rabbitHost = rabbitUri.Host;
rabbitPort = rabbitUri.Port.ToString();
rabbitUser = rabbitUri.UserInfo.Split(':')[0];
rabbitPass = rabbitUri.UserInfo.Split(':')[1];
}

return new RabbitMqConfiguration()
{
Host = rabbitHost ?? "",
Port = int.Parse(rabbitPort ?? "0"),
Enabled = bool.Parse(rabbitEnabled ?? "false"),
Username = rabbitUser ?? "",
Password = rabbitPass ?? ""
};
}
}
36 changes: 22 additions & 14 deletions CleanArchitecture.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@
using CleanArchitecture.Domain.Rabbitmq.Extensions;
using CleanArchitecture.Infrastructure.Database;
using CleanArchitecture.Infrastructure.Extensions;
using CleanArchitecture.ServiceDefaults;
using HealthChecks.ApplicationStatus.DependencyInjection;
using HealthChecks.UI.Client;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();

builder.Services.AddControllers();
builder.Services.AddGrpc();
builder.Services.AddGrpcReflection();
Expand All @@ -28,40 +30,44 @@
.AddDbContextCheck<ApplicationDbContext>()
.AddApplicationStatus();

var isAspire = builder.Configuration["ASPIRE_ENABLED"] == "true";

var rabbitConfiguration = builder.Configuration.GetRabbitMqConfiguration();
var redisConnectionString =
isAspire ? builder.Configuration["ConnectionStrings:Redis"] : builder.Configuration["RedisHostName"];
var dbConnectionString = isAspire
? builder.Configuration["ConnectionStrings:Database"]
: builder.Configuration["ConnectionStrings:DefaultConnection"];

if (builder.Environment.IsProduction())
{
var rabbitHost = builder.Configuration["RabbitMQ:Host"];
var rabbitPort = builder.Configuration["RabbitMQ:Port"];
var rabbitUser = builder.Configuration["RabbitMQ:Username"];
var rabbitPass = builder.Configuration["RabbitMQ:Password"];

builder.Services
.AddHealthChecks()
.AddSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")!)
.AddRedis(builder.Configuration["RedisHostName"]!, "Redis")
.AddSqlServer(dbConnectionString!)
.AddRedis(redisConnectionString!, "Redis")
.AddRabbitMQ(
$"amqp://{rabbitUser}:{rabbitPass}@{rabbitHost}:{rabbitPort}",
rabbitConfiguration.ConnectionString,
name: "RabbitMQ");
}

builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseLazyLoadingProxies();
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"),
options.UseSqlServer(dbConnectionString,
b => b.MigrationsAssembly("CleanArchitecture.Infrastructure"));
});

builder.Services.AddSwagger();
builder.Services.AddAuth(builder.Configuration);
builder.Services.AddInfrastructure(builder.Configuration, "CleanArchitecture.Infrastructure");
builder.Services.AddInfrastructure("CleanArchitecture.Infrastructure", dbConnectionString!);
builder.Services.AddQueryHandlers();
builder.Services.AddServices();
builder.Services.AddSortProviders();
builder.Services.AddCommandHandlers();
builder.Services.AddNotificationHandlers();
builder.Services.AddApiUser();

builder.Services.AddRabbitMqHandler(builder.Configuration, "RabbitMQ");
builder.Services.AddRabbitMqHandler(rabbitConfiguration);

builder.Services.AddHostedService<SetInactiveUsersService>();

Expand All @@ -73,11 +79,11 @@
console.IncludeScopes = true;
}));

if (builder.Environment.IsProduction() || !string.IsNullOrWhiteSpace(builder.Configuration["RedisHostName"]))
if (builder.Environment.IsProduction() || !string.IsNullOrWhiteSpace(redisConnectionString))
{
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration["RedisHostName"];
options.Configuration = redisConnectionString;
options.InstanceName = "clean-architecture";
});
}
Expand All @@ -88,6 +94,8 @@

var app = builder.Build();

app.MapDefaultEndpoints();

using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
Expand Down
16 changes: 0 additions & 16 deletions CleanArchitecture.Api/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:38452",
"sslPort": 44309
}
},
"profiles": {
"CleanArchitecture.Api": {
"commandName": "Project",
Expand All @@ -18,14 +10,6 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
25 changes: 25 additions & 0 deletions CleanArchitecture.AppHost/CleanArchitecture.AppHost.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0" />

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
<UserSecretsId>e7ec3788-69e9-4631-b350-d59657ddd747</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.0.0" />
<PackageReference Include="Aspire.Hosting.RabbitMQ" Version="9.0.0" />
<PackageReference Include="Aspire.Hosting.Redis" Version="9.0.0" />
<PackageReference Include="Aspire.Hosting.SqlServer" Version="9.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CleanArchitecture.Api\CleanArchitecture.Api.csproj" />
</ItemGroup>

</Project>
26 changes: 26 additions & 0 deletions CleanArchitecture.AppHost/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
var builder = DistributedApplication.CreateBuilder(args);

var redis = builder.AddRedis("Redis").WithRedisInsight();

var rabbitPasswordRessource = new ParameterResource("password", _ => "guest");
var rabbitPasswordParameter =
builder.AddParameter("username", rabbitPasswordRessource.Value);

var rabbitMq = builder
.AddRabbitMQ("RabbitMq", null, rabbitPasswordParameter, 5672)
.WithManagementPlugin();

var sqlServer = builder.AddSqlServer("SqlServer");
var db = sqlServer.AddDatabase("Database", "clean-architecture");

builder.AddProject<Projects.CleanArchitecture_Api>("CleanArchitecture-Api")
.WithOtlpExporter()
.WithHttpHealthCheck("/health")
.WithReference(redis)
.WaitFor(redis)
.WithReference(rabbitMq)
.WaitFor(rabbitMq)
.WithReference(db)
.WaitFor(sqlServer);

builder.Build().Run();
18 changes: 18 additions & 0 deletions CleanArchitecture.AppHost/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"Aspire": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:17270;http://localhost:15188",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21200",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22111",
"ASPIRE_ENABLED": "true"
}
}
}
}
8 changes: 8 additions & 0 deletions CleanArchitecture.AppHost/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions CleanArchitecture.AppHost/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace CleanArchitecture.Domain.Rabbitmq.Extensions;
Expand All @@ -7,12 +6,9 @@ public static class ServiceCollectionExtensions
{
public static IServiceCollection AddRabbitMqHandler(
this IServiceCollection services,
IConfiguration configuration,
string rabbitMqConfigSection)
RabbitMqConfiguration configuration)
{
var rabbitMq = new RabbitMqConfiguration();
configuration.Bind(rabbitMqConfigSection, rabbitMq);
services.AddSingleton(rabbitMq);
services.AddSingleton(configuration);

services.AddSingleton<RabbitMqHandler>();
services.AddHostedService(serviceProvider => serviceProvider.GetService<RabbitMqHandler>()!);
Expand Down
2 changes: 2 additions & 0 deletions CleanArchitecture.Domain/Rabbitmq/RabbitMqConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ public sealed class RabbitMqConfiguration
public bool Enabled { get; set; }
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;

public string ConnectionString => $"amqp://{Username}:{Password}@{Host}:{Port}";
}
13 changes: 9 additions & 4 deletions CleanArchitecture.Domain/Rabbitmq/RabbitMqHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ namespace CleanArchitecture.Domain.Rabbitmq;

public sealed class RabbitMqHandler : BackgroundService
{
private IChannel? _channel;
private readonly RabbitMqConfiguration _configuration;

private readonly ConcurrentDictionary<string, List<ConsumeEventHandler>> _consumers = new();

private readonly ILogger<RabbitMqHandler> _logger;

private readonly ConcurrentQueue<IRabbitMqAction> _pendingActions = new();
private IChannel? _channel;

public RabbitMqHandler(
RabbitMqConfiguration configuration,
Expand All @@ -38,17 +38,21 @@ public override async Task StartAsync(CancellationToken cancellationToken)
return;
}

_logger.LogInformation("Starting RabbitMQ connection");

var factory = new ConnectionFactory
{
AutomaticRecoveryEnabled = true,
HostName = _configuration.Host,
Port = _configuration.Port,
UserName = _configuration.Username,
Password = _configuration.Password,
Password = _configuration.Password
};

var connection = await factory.CreateConnectionAsync(cancellationToken);
_channel = await connection.CreateChannelAsync(null, cancellationToken);

await base.StartAsync(cancellationToken);
}


Expand Down Expand Up @@ -129,14 +133,15 @@ public void AddExchangeConsumer(string exchange, string queue, ConsumeEventHandl
AddExchangeConsumer(exchange, string.Empty, queue, consumer);
}

private async Task AddEventConsumer(string exchange, string queueName, string routingKey, ConsumeEventHandler consumer)
private async Task AddEventConsumer(string exchange, string queueName, string routingKey,
ConsumeEventHandler consumer)
{
if (!_configuration.Enabled)
{
_logger.LogInformation("RabbitMQ is disabled. Event consumer will not be added.");
return;
}

var key = $"{exchange}-{routingKey}";

if (!_consumers.TryGetValue(key, out var consumers))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using CleanArchitecture.Infrastructure.Repositories;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace CleanArchitecture.Infrastructure.Extensions;
Expand All @@ -16,24 +15,23 @@ public static class ServiceCollectionExtensions
{
public static IServiceCollection AddInfrastructure(
this IServiceCollection services,
IConfiguration configuration,
string migrationsAssemblyName,
string connectionStringName = "DefaultConnection")
string connectionString)
{
// Add event store db context
services.AddDbContext<EventStoreDbContext>(
options =>
{
options.UseSqlServer(
configuration.GetConnectionString(connectionStringName),
connectionString,
b => b.MigrationsAssembly(migrationsAssemblyName));
});

services.AddDbContext<DomainNotificationStoreDbContext>(
options =>
{
options.UseSqlServer(
configuration.GetConnectionString(connectionStringName),
connectionString,
b => b.MigrationsAssembly(migrationsAssemblyName));
});

Expand Down
Loading
Loading