diff --git a/README.md b/README.md index e493e8c7..0b0fc551 100644 --- a/README.md +++ b/README.md @@ -73,10 +73,10 @@ You can use **Docker compose** to setup the infrastructure components just by ru ``` bash cd ./containers -# Setup the infrastructure +# Setup the infrastructure. Use this file to setup the basic infrastructure components (RabbitMQ, MongoDB) docker compose -f ./infrastructure.yml --env-file ./.env --project-name genocs up -d -# Use this file only in case you want to setup Redis and Postgres db (no need if you use mongo) +# Use this file only in case you want to setup Redis and PostgreSQL (no need if you use MongoDB) docker compose -f ./infrastructure-db.yml --env-file ./.env --project-name genocs up -d # Use this file only in case you want to setup monitoring infrastructure components (Prometheus, Grafana, InfluxDB, Jaeger, Seq) @@ -88,13 +88,13 @@ docker compose -f ./infrastructure-scaling.yml --env-file ./.env --project-name # Use this file only in case you want to setup security infrastructure components (Vault) docker compose -f ./infrastructure-security.yml --env-file ./.env --project-name genocs up -d -# Use this file only in case you want to setup sqlserver database (no need if you use postgres) +# Use this file only in case you want to setup sqlserver database (no need if you use PostgreSQL) docker compose -f ./infrastructure-sqlserver.yml --env-file ./.env --project-name genocs up -d -# Use this file only in case you want to setup mySql database (no need if you use postgres) +# Use this file only in case you want to setup mySql database (no need if you use PostgreSQL) docker compose -f ./infrastructure-mysql.yml --env-file ./.env --project-name genocs up -d -# Use this file only in case you want to setup oracle database (no need if you use postgres) +# Use this file only in case you want to setup oracle database (no need if you use PostgreSQL) docker compose -f ./infrastructure-oracle.yml --env-file ./.env --project-name genocs up -d # Use this file only in case you want to setup elk stack @@ -104,18 +104,24 @@ docker compose -f ./infrastructure-elk.yml --env-file ./.env --project-name geno docker compose -f ./infrastructure-ml.yml --env-file ./.env --project-name genocs up -d ``` -`infrastructure-bare.yml` allows to install the basic infrastructure components. They are: +`infrastructure.yml` allows to install the basic infrastructure components. They are: - [RabbitMQ](https://rabbitmq.com) - [Redis](https://redis.io) - [MongoDB](https://mongodb.com) -- [Postgres](https://www.postgresql.org/). +- [Postgres](https://www.postgresql.org/) -You can run them locally: + +`infrastructure-db.yml` allows to install Redis and PostgreSQL +- [Redis](https://redis.io) +- [Postgres](https://www.postgresql.org/) + + +You can check them locally: - [RabbitMQ](http://localhost:15672): `localhost:15672` -- Redis: `localhost:6379` -- MongoDB: `localhost:27017` -- Postgres: `localhost:5432` +- Redis: `TCP:localhost:6379` +- MongoDB: `TCP:localhost:27017` +- Postgres: `TCP:localhost:5432` `infrastructure-monitoring.yml` allows to install the monitoring infrastructure components. They are: @@ -126,7 +132,7 @@ You can run them locally: - [Seq](https://datalust.co/seq) -You can run them locally: +You can find the console locally at: - [Prometheus](localhost:9090): `localhost:9090` - [Grafana](localhost:3000): `localhost:3000` @@ -135,9 +141,13 @@ You can run them locally: - [Seq](localhost:5341): `localhost:5341` -`infrastructure-scaling.yml` allows to install the scaling infrastructure components. They are: -- Fabio -- Consul +`infrastructure-scaling.yml` allows to install the scaling infrastructure components composed by Fabio and Consul. + +- [Fabio](https://fabiolb.net/) +- [Consul](https://www.consul.io/) + + + `infrastructure-security.yml` allows to install the security infrastructure components. @@ -185,7 +195,7 @@ Use [**api-workbench**](./api-workbench.rest) inside Visual Studio code with [RE "enabled": false, "url": "http://localhost:8500", "service": "demo-service", - "address": "docker.for.win.localhost", + "address": "docker.for.mac.localhost", "port": "5070", "pingEnabled": true, "pingEndpoint": "health", diff --git a/containers/.env b/containers/.env new file mode 100644 index 00000000..407449c8 --- /dev/null +++ b/containers/.env @@ -0,0 +1,2 @@ +# This file is a template for the .env file that is used by the docker-compose.yml file. +POSTGRES_PASSWORD=mySecretPassword1234! diff --git a/genocs.sln b/genocs.sln index 16581cec..dac56edb 100644 --- a/genocs.sln +++ b/genocs.sln @@ -120,9 +120,11 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Application", "Application", "{B184733D-2415-4517-BC65-26ED22EEB2C2}" ProjectSection(SolutionItems) = preProject src\apps\apigateway.dockerfile = src\apps\apigateway.dockerfile - src\apps\application-docker-compose.yml = src\apps\application-docker-compose.yml + src\apps\docker-compose.override.yml = src\apps\docker-compose.override.yml + src\apps\docker-compose.yml = src\apps\docker-compose.yml src\apps\identity-webapi.dockerfile = src\apps\identity-webapi.dockerfile src\apps\order-webapi.dockerfile = src\apps\order-webapi.dockerfile + src\apps\local.env = src\apps\local.env src\apps\product-webapi.dockerfile = src\apps\product-webapi.dockerfile src\apps\signalr-webapi.dockerfile = src\apps\signalr-webapi.dockerfile EndProjectSection diff --git a/src/Genocs.Auth/Genocs.Auth.csproj b/src/Genocs.Auth/Genocs.Auth.csproj index 20296ed5..f8482eb1 100644 --- a/src/Genocs.Auth/Genocs.Auth.csproj +++ b/src/Genocs.Auth/Genocs.Auth.csproj @@ -24,8 +24,8 @@ - - + + diff --git a/src/Genocs.Core.Demo.Contracts/Genocs.Core.Demo.Contracts.csproj b/src/Genocs.Core.Demo.Contracts/Genocs.Core.Demo.Contracts.csproj index 0e849290..5c297bb3 100644 --- a/src/Genocs.Core.Demo.Contracts/Genocs.Core.Demo.Contracts.csproj +++ b/src/Genocs.Core.Demo.Contracts/Genocs.Core.Demo.Contracts.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Genocs.Core.Demo.Domain/Genocs.Core.Demo.Domain.csproj b/src/Genocs.Core.Demo.Domain/Genocs.Core.Demo.Domain.csproj index 2f1181c7..5f75ee48 100644 --- a/src/Genocs.Core.Demo.Domain/Genocs.Core.Demo.Domain.csproj +++ b/src/Genocs.Core.Demo.Domain/Genocs.Core.Demo.Domain.csproj @@ -12,8 +12,8 @@ - - + + diff --git a/src/Genocs.Core.Demo.WebApi/Genocs.Core.Demo.WebApi.csproj b/src/Genocs.Core.Demo.WebApi/Genocs.Core.Demo.WebApi.csproj index 2e1f5546..85e7e8b6 100644 --- a/src/Genocs.Core.Demo.WebApi/Genocs.Core.Demo.WebApi.csproj +++ b/src/Genocs.Core.Demo.WebApi/Genocs.Core.Demo.WebApi.csproj @@ -20,22 +20,22 @@ - - - - - - - - - + + + + + + + + + - + diff --git a/src/Genocs.Core.Demo.WebApi/Program.cs b/src/Genocs.Core.Demo.WebApi/Program.cs index 8b850a98..33d6eedd 100644 --- a/src/Genocs.Core.Demo.WebApi/Program.cs +++ b/src/Genocs.Core.Demo.WebApi/Program.cs @@ -20,10 +20,7 @@ .UseAzureKeyVault() .UseLogging(); -var services = builder.Services; - -services - .AddGenocs(builder.Configuration) +builder.AddGenocs() .AddJwt() // .AddOpenIdJwt() .AddOpenTelemetry() @@ -32,6 +29,8 @@ .AddApplicationServices() .Build(); +var services = builder.Services; + services.AddCors(); services.AddControllers().AddJsonOptions(x => { diff --git a/src/Genocs.Core.Demo.Worker/Genocs.Core.Demo.Worker.csproj b/src/Genocs.Core.Demo.Worker/Genocs.Core.Demo.Worker.csproj index a726e6f8..f9b2dcbc 100644 --- a/src/Genocs.Core.Demo.Worker/Genocs.Core.Demo.Worker.csproj +++ b/src/Genocs.Core.Demo.Worker/Genocs.Core.Demo.Worker.csproj @@ -14,9 +14,9 @@ - - - + + + diff --git a/src/Genocs.Core.Demo.Worker/appsettings.json b/src/Genocs.Core.Demo.Worker/appsettings.json index 9ebf71e1..6391c0f0 100644 --- a/src/Genocs.Core.Demo.Worker/appsettings.json +++ b/src/Genocs.Core.Demo.Worker/appsettings.json @@ -43,10 +43,10 @@ "enabled": false, "url": "http://localhost:8500", "service": "users-service", - "address": "docker.for.win.localhost", + "address": "docker.for.mac.localhost", "port": "5070", "pingEnabled": true, - "pingEndpoint": "ping", + "pingEndpoint": "healthz", "pingInterval": 3, "removeAfterInterval": 3 }, @@ -99,7 +99,7 @@ "interval": "day" }, "seq": { - "enabled": false, + "enabled": true, "url": "http://localhost:5341", "apiKey": "secret" }, diff --git a/src/Genocs.Core/Builders/Extensions.cs b/src/Genocs.Core/Builders/Extensions.cs index c389cd7e..4c82f9eb 100644 --- a/src/Genocs.Core/Builders/Extensions.cs +++ b/src/Genocs.Core/Builders/Extensions.cs @@ -20,6 +20,7 @@ public static IGenocsBuilder AddGenocs(this WebApplicationBuilder builder) { // Create the builder IGenocsBuilder gnxBuilder = GenocsBuilder.Create(builder); + Setup(gnxBuilder); return gnxBuilder; } @@ -33,32 +34,7 @@ public static IGenocsBuilder AddGenocs(this IServiceCollection services, IConfig { // Create the builder IGenocsBuilder builder = GenocsBuilder.Create(services, configuration); - - // Get the application options - AppOptions settings = builder.GetOptions(AppOptions.Position); - builder.Services.AddSingleton(settings); - - // Add the health checks - builder.Services - .AddHealthChecks() - .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); // Add a default liveness check to ensure app is responsive - - builder.Services.AddMemoryCache(); - - builder.Services.AddSingleton(); - - if (!settings.DisplayBanner || string.IsNullOrWhiteSpace(settings.Name)) - { - return builder; - } - - string version = settings.DisplayVersion ? $" {settings.Version}" : string.Empty; - Console.WriteLine(Figgle.FiggleFonts.Doom.Render(settings.Name + version)); - ConsoleColor current = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Blue; - Console.WriteLine("Runtime Version: {0}", Environment.Version.ToString()); - Console.ForegroundColor = current; - + Setup(builder); return builder; } @@ -160,6 +136,15 @@ public static WebApplication MapDefaultEndpoints(this WebApplication app) return app; } + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks("/healthz"); + + // 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") + }); + app.MapGet("/", async context => { // Get the Entry Assembly Name and Version @@ -170,16 +155,35 @@ public static WebApplication MapDefaultEndpoints(this WebApplication app) await context.Response.WriteAsync(context.RequestServices.GetService()?.Name ?? message); }); + return app; + } - // All health checks must pass for app to be considered ready to accept traffic after starting - app.MapHealthChecks("/health"); + private static void Setup(IGenocsBuilder builder) + { + // Get the application options + AppOptions settings = builder.GetOptions(AppOptions.Position); + builder.Services.AddSingleton(settings); - // Only health checks tagged with the "live" tag must pass for app to be considered alive - app.MapHealthChecks("/alive", new HealthCheckOptions + if (!settings.DisplayBanner || string.IsNullOrWhiteSpace(settings.Name)) { - Predicate = r => r.Tags.Contains("live") - }); + return; + } - return app; + string version = settings.DisplayVersion ? $" {settings.Version}" : string.Empty; + Console.WriteLine(Figgle.FiggleFonts.Doom.Render(settings.Name + version)); + ConsoleColor current = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Blue; + Console.WriteLine("Runtime Version: {0}", Environment.Version.ToString()); + Console.ForegroundColor = current; + + // Add the health checks + builder.Services + .AddHealthChecks(); + + // .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); // Add a default liveness check to ensure app is responsive + + builder.Services.AddMemoryCache(); + + builder.Services.AddSingleton(); } } \ No newline at end of file diff --git a/src/Genocs.Core/Genocs.Core.csproj b/src/Genocs.Core/Genocs.Core.csproj index 361e1a50..3d789e37 100644 --- a/src/Genocs.Core/Genocs.Core.csproj +++ b/src/Genocs.Core/Genocs.Core.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.Discovery.Consul/Extensions.cs b/src/Genocs.Discovery.Consul/Extensions.cs index 6a16f2be..a92d068c 100644 --- a/src/Genocs.Discovery.Consul/Extensions.cs +++ b/src/Genocs.Discovery.Consul/Extensions.cs @@ -80,7 +80,7 @@ public static void AddConsulHttpClient(this IGenocsBuilder builder, string clien c.GetRequiredService(), c.GetRequiredService(), serviceName, true)); - private static ServiceRegistration CreateConsulAgentRegistration(this IGenocsBuilder builder, ConsulOptions options) + private static ServiceRegistration? CreateConsulAgentRegistration(this IGenocsBuilder builder, ConsulOptions options) { bool enabled = options.Enabled; string? consulEnabled = Environment.GetEnvironmentVariable("CONSUL_ENABLED")?.ToLowerInvariant(); diff --git a/src/Genocs.Discovery.Consul/Genocs.Discovery.Consul.csproj b/src/Genocs.Discovery.Consul/Genocs.Discovery.Consul.csproj index 9055f004..1b289f3d 100644 --- a/src/Genocs.Discovery.Consul/Genocs.Discovery.Consul.csproj +++ b/src/Genocs.Discovery.Consul/Genocs.Discovery.Consul.csproj @@ -24,12 +24,11 @@ - - + + - diff --git a/src/Genocs.Discovery.Consul/IConsulService.cs b/src/Genocs.Discovery.Consul/IConsulService.cs index 9c405e4e..4f92966f 100644 --- a/src/Genocs.Discovery.Consul/IConsulService.cs +++ b/src/Genocs.Discovery.Consul/IConsulService.cs @@ -6,5 +6,5 @@ public interface IConsulService { Task RegisterServiceAsync(ServiceRegistration registration); Task DeregisterServiceAsync(string id); - Task> GetServiceAgentsAsync(string? service = null); + Task?> GetServiceAgentsAsync(string? service = null); } \ No newline at end of file diff --git a/src/Genocs.Discovery.Consul/Services/ConsulService.cs b/src/Genocs.Discovery.Consul/Services/ConsulService.cs index 0f32f333..05a4221e 100644 --- a/src/Genocs.Discovery.Consul/Services/ConsulService.cs +++ b/src/Genocs.Discovery.Consul/Services/ConsulService.cs @@ -21,7 +21,7 @@ public Task RegisterServiceAsync(ServiceRegistration regist public Task DeregisterServiceAsync(string id) => _client.PutAsync(GetEndpoint($"agent/service/deregister/{id}"), EmptyRequest); - public async Task> GetServiceAgentsAsync(string? service = null) + public async Task?> GetServiceAgentsAsync(string? service = null) { string filter = string.IsNullOrWhiteSpace(service) ? string.Empty : $"?filter=Service==\"{service}\""; var response = await _client.GetAsync(GetEndpoint($"agent/services{filter}")); @@ -38,5 +38,6 @@ public async Task> GetServiceAgentsAsync(strin private static StringContent GetPayload(object request) => new(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"); - private static string GetEndpoint(string endpoint) => $"{Version}/{endpoint}"; + private static string GetEndpoint(string endpoint) + => $"{Version}/{endpoint}"; } \ No newline at end of file diff --git a/src/Genocs.HTTP.RestEase/Genocs.HTTP.RestEase.csproj b/src/Genocs.HTTP.RestEase/Genocs.HTTP.RestEase.csproj index a6aacfd6..fbd22554 100644 --- a/src/Genocs.HTTP.RestEase/Genocs.HTTP.RestEase.csproj +++ b/src/Genocs.HTTP.RestEase/Genocs.HTTP.RestEase.csproj @@ -25,10 +25,10 @@ - - - - + + + + diff --git a/src/Genocs.HTTP/Genocs.HTTP.csproj b/src/Genocs.HTTP/Genocs.HTTP.csproj index 001692e7..bba35e2c 100644 --- a/src/Genocs.HTTP/Genocs.HTTP.csproj +++ b/src/Genocs.HTTP/Genocs.HTTP.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.HTTP/GenocsHttpClient.cs b/src/Genocs.HTTP/GenocsHttpClient.cs index 63d02470..7ccefdad 100644 --- a/src/Genocs.HTTP/GenocsHttpClient.cs +++ b/src/Genocs.HTTP/GenocsHttpClient.cs @@ -170,7 +170,8 @@ public void SetHeaders(IDictionary headers) } } - public void SetHeaders(Action headers) => headers?.Invoke(_client.DefaultRequestHeaders); + public void SetHeaders(Action headers) + => headers?.Invoke(_client.DefaultRequestHeaders); protected virtual async Task SendAsync(string uri, Method method, HttpContent? content = null, IHttpClientSerializer? serializer = null) { @@ -241,7 +242,7 @@ protected virtual Task GetResponseAsync(string uri, Method return content; } - protected async Task DeserializeJsonFromStream(Stream stream, IHttpClientSerializer? serializer = null) + protected async Task DeserializeJsonFromStream(Stream stream, IHttpClientSerializer? serializer = null) { if (stream is null || stream.CanRead is false) { diff --git a/src/Genocs.HTTP/HttpResult.cs b/src/Genocs.HTTP/HttpResult.cs index e838db6e..8f3b4c6a 100644 --- a/src/Genocs.HTTP/HttpResult.cs +++ b/src/Genocs.HTTP/HttpResult.cs @@ -1,14 +1,8 @@ namespace Genocs.HTTP; -public class HttpResult +public class HttpResult(T result, HttpResponseMessage response) { - public T Result { get; } - public HttpResponseMessage Response { get; } + public T Result { get; } = result; + public HttpResponseMessage Response { get; } = response; public bool HasResult => Result is not null; - - public HttpResult(T result, HttpResponseMessage response) - { - Result = result; - Response = response; - } } \ No newline at end of file diff --git a/src/Genocs.LoadBalancing.Fabio/Extensions.cs b/src/Genocs.LoadBalancing.Fabio/Extensions.cs index ba3ded7a..2225d5ac 100644 --- a/src/Genocs.LoadBalancing.Fabio/Extensions.cs +++ b/src/Genocs.LoadBalancing.Fabio/Extensions.cs @@ -37,22 +37,32 @@ public static IGenocsBuilder AddFabio( b => b.AddConsul(consulOptions, httpClientOptions)); } - public static IGenocsBuilder AddFabio(this IGenocsBuilder builder, - Func buildOptions, - Func buildConsulOptions, - HttpClientOptions httpClientOptions) + public static IGenocsBuilder AddFabio( + this IGenocsBuilder builder, + Func buildOptions, + Func buildConsulOptions, + HttpClientOptions httpClientOptions) { var fabioOptions = buildOptions(new FabioOptionsBuilder()).Build(); - return builder.AddFabio(fabioOptions, httpClientOptions, - b => b.AddConsul(buildConsulOptions, httpClientOptions)); + + return builder.AddFabio( + fabioOptions, + httpClientOptions, + b => b.AddConsul(buildConsulOptions, httpClientOptions)); } - public static IGenocsBuilder AddFabio(this IGenocsBuilder builder, FabioOptions fabioOptions, - ConsulOptions consulOptions, HttpClientOptions httpClientOptions) + public static IGenocsBuilder AddFabio( + this IGenocsBuilder builder, + FabioOptions fabioOptions, + ConsulOptions consulOptions, + HttpClientOptions httpClientOptions) => builder.AddFabio(fabioOptions, httpClientOptions, b => b.AddConsul(consulOptions, httpClientOptions)); - private static IGenocsBuilder AddFabio(this IGenocsBuilder builder, FabioOptions fabioOptions, - HttpClientOptions httpClientOptions, Action registerConsul) + private static IGenocsBuilder AddFabio( + this IGenocsBuilder builder, + FabioOptions fabioOptions, + HttpClientOptions httpClientOptions, + Action registerConsul) { registerConsul(builder); builder.Services.AddSingleton(fabioOptions); @@ -64,19 +74,24 @@ private static IGenocsBuilder AddFabio(this IGenocsBuilder builder, FabioOptions if (httpClientOptions.Type?.ToLowerInvariant() == "fabio") { - builder.Services.AddTransient(); - builder.Services.AddHttpClient("fabio-http") - .AddHttpMessageHandler(); + builder.Services + .AddTransient(); + builder.Services + .AddHttpClient("fabio-http") + .AddHttpMessageHandler(); builder.RemoveHttpClient(); - builder.Services.AddHttpClient("fabio") - .AddHttpMessageHandler(); + + builder.Services + .AddHttpClient("fabio") + .AddHttpMessageHandler(); } using var serviceProvider = builder.Services.BuildServiceProvider(); var registration = serviceProvider.GetRequiredService(); var tags = GetFabioTags(registration.Name, fabioOptions.Service); + if (registration.Tags is null) { registration.Tags = tags; @@ -91,12 +106,17 @@ private static IGenocsBuilder AddFabio(this IGenocsBuilder builder, FabioOptions return builder; } - public static void AddFabioHttpClient(this IGenocsBuilder builder, string clientName, string serviceName) - => builder.Services.AddHttpClient(clientName) - .AddHttpMessageHandler(c => new FabioMessageHandler(c.GetRequiredService(), serviceName)); - - private static void UpdateConsulRegistration(this IServiceCollection services, - ServiceRegistration registration) + public static void AddFabioHttpClient( + this IGenocsBuilder builder, + string clientName, + string serviceName) + => builder.Services + .AddHttpClient(clientName) + .AddHttpMessageHandler(c => new FabioMessageHandler(c.GetRequiredService(), serviceName)); + + private static void UpdateConsulRegistration( + this IServiceCollection services, + ServiceRegistration registration) { var serviceDescriptor = services.FirstOrDefault(sd => sd.ServiceType == typeof(ServiceRegistration)); services.Remove(serviceDescriptor); diff --git a/src/Genocs.LoadBalancing.Fabio/Genocs.LoadBalancing.Fabio.csproj b/src/Genocs.LoadBalancing.Fabio/Genocs.LoadBalancing.Fabio.csproj index d81ff3b4..0f2f27a5 100644 --- a/src/Genocs.LoadBalancing.Fabio/Genocs.LoadBalancing.Fabio.csproj +++ b/src/Genocs.LoadBalancing.Fabio/Genocs.LoadBalancing.Fabio.csproj @@ -24,13 +24,8 @@ - - - + + + - - - - - diff --git a/src/Genocs.LoadBalancing.Fabio/IFabioHttpClient.cs b/src/Genocs.LoadBalancing.Fabio/IFabioHttpClient.cs index 2968e1f4..6e08425b 100644 --- a/src/Genocs.LoadBalancing.Fabio/IFabioHttpClient.cs +++ b/src/Genocs.LoadBalancing.Fabio/IFabioHttpClient.cs @@ -2,6 +2,9 @@ namespace Genocs.LoadBalancing.Fabio; +/// +/// The Fabio HTTP client interface definition. +/// public interface IFabioHttpClient : IHttpClient { } \ No newline at end of file diff --git a/src/Genocs.LoadBalancing.Fabio/README_NUGET.md b/src/Genocs.LoadBalancing.Fabio/README_NUGET.md index 6ffbc96c..f6a7d24a 100644 --- a/src/Genocs.LoadBalancing.Fabio/README_NUGET.md +++ b/src/Genocs.LoadBalancing.Fabio/README_NUGET.md @@ -1,11 +1,13 @@ -# .NET query builder library +# Genocs Load Balancing library + +This package contains support for load balancing functionality by means of Fabio. -This package contains a query builder that is agnostic about the persistence layer. The library is designed by Genocs. -The libraries are built using .NET standard 2.1. ## Description -Persistence agnostic query builder service. +Fabio is a fast, modern, zero-conf load balancing HTTP(S) router for deploying microservices managed by consul. + +The libraries are built using .NET Core. ## Support @@ -14,52 +16,3 @@ Please check the GitHub repository getting more info. ## Release notes - -### [2024-01-23] 5.0.6 -- Refactory Settings -- Updated nuget packages - -### [2023-11-25] 5.0.5 -- Moved to NET8 - -### [yyyy-mm-dd] 5.0.4 -- - -### [yyyy-mm-dd] 5.0.3 -- - -### [yyyy-mm-dd] 5.0.2 -- - -### [yyyy-mm-dd] 5.0.1 -- - -### [2023-11-25] 5.0.0 -- Moved to NET8 - -### [2023-10-13] 5.0.0-preview.5.0 -- Added [editorconfig](https://editorconfig.org/) -- Added StyleCop -- Updated logo -- Updated readme - -### [2023-03-12] 5.0.0-preview.4.0 -- Implemented MongoDB repository interfaces - -### [2023-03-12] 5.0.0 -- New Architecture - -### [2023-03-12] 3.1.0 -- Added Builders - -### [2023-03-12] 3.0.0 -- Refactory to implement CQRS pattern - -### [2023-03-04] 2.4.1 -- Updated System.Text.Json - -### [2023-01-23] 1.1.0 -- Refactory enum - -### [2023-01-13] 1.0.0 -- First Release \ No newline at end of file diff --git a/src/Genocs.Logging/Genocs.Logging.csproj b/src/Genocs.Logging/Genocs.Logging.csproj index 5412bc16..e2d450af 100644 --- a/src/Genocs.Logging/Genocs.Logging.csproj +++ b/src/Genocs.Logging/Genocs.Logging.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.MessageBrokers.Outbox.MongoDB/Genocs.MessageBrokers.Outbox.MongoDB.csproj b/src/Genocs.MessageBrokers.Outbox.MongoDB/Genocs.MessageBrokers.Outbox.MongoDB.csproj index e06755d9..ce80682a 100644 --- a/src/Genocs.MessageBrokers.Outbox.MongoDB/Genocs.MessageBrokers.Outbox.MongoDB.csproj +++ b/src/Genocs.MessageBrokers.Outbox.MongoDB/Genocs.MessageBrokers.Outbox.MongoDB.csproj @@ -23,8 +23,8 @@ - - + + diff --git a/src/Genocs.MessageBrokers.Outbox/Genocs.MessageBrokers.Outbox.csproj b/src/Genocs.MessageBrokers.Outbox/Genocs.MessageBrokers.Outbox.csproj index 606ef8c7..fad347ca 100644 --- a/src/Genocs.MessageBrokers.Outbox/Genocs.MessageBrokers.Outbox.csproj +++ b/src/Genocs.MessageBrokers.Outbox/Genocs.MessageBrokers.Outbox.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.MessageBrokers.RabbitMQ/Clients/RabbitMqClient.cs b/src/Genocs.MessageBrokers.RabbitMQ/Clients/RabbitMqClient.cs index 60379a88..72d94f9c 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/Clients/RabbitMqClient.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/Clients/RabbitMqClient.cs @@ -6,22 +6,25 @@ namespace Genocs.MessageBrokers.RabbitMQ.Clients; internal sealed class RabbitMQClient : IRabbitMQClient { - private readonly object _lockObject = new(); private const string EmptyContext = "{}"; private readonly IConnection _connection; private readonly IContextProvider _contextProvider; - private readonly IRabbitMqSerializer _serializer; + private readonly IRabbitMQSerializer _serializer; private readonly ILogger _logger; private readonly bool _contextEnabled; private readonly bool _loggerEnabled; private readonly string _spanContextHeader; private readonly bool _persistMessages; - private int _channelsCount; - private readonly ConcurrentDictionary _channels = new(); + private readonly ConcurrentDictionary _channels = new(); private readonly int _maxChannels; + private int _channelsCount; - public RabbitMQClient(ProducerConnection connection, IContextProvider contextProvider, IRabbitMqSerializer serializer, - RabbitMQOptions options, ILogger logger) + public RabbitMQClient( + ProducerConnection connection, + IContextProvider contextProvider, + IRabbitMQSerializer serializer, + RabbitMQOptions options, + ILogger logger) { _connection = connection.Connection; _contextProvider = contextProvider; @@ -34,29 +37,34 @@ public RabbitMQClient(ProducerConnection connection, IContextProvider contextPro _maxChannels = options.MaxProducerChannels <= 0 ? 1000 : options.MaxProducerChannels; } - public void Send(object message, IConventions conventions, string messageId = null, string correlationId = null, - string spanContext = null, object messageContext = null, IDictionary headers = null) + public async Task SendAsync( + object message, + IConventions conventions, + string? messageId = null, + string? correlationId = null, + string? spanContext = null, + object? messageContext = null, + IDictionary? headers = null) { - var threadId = Thread.CurrentThread.ManagedThreadId; + int threadId = Thread.CurrentThread.ManagedThreadId; if (!_channels.TryGetValue(threadId, out var channel)) { - lock (_lockObject) + if (_channelsCount >= _maxChannels) { - if (_channelsCount >= _maxChannels) - { - throw new InvalidOperationException($"Cannot create RabbitMQ producer channel for thread: {threadId} " + - $"(reached the limit of {_maxChannels} channels). " + - "Modify `MaxProducerChannels` setting to allow more channels."); - } + throw new InvalidOperationException($"Cannot create RabbitMQ producer channel for thread: {threadId} " + + $"(reached the limit of {_maxChannels} channels). " + + "Modify `MaxProducerChannels` setting to allow more channels."); - channel = _connection.CreateModel(); - _channels.TryAdd(threadId, channel); - _channelsCount++; - if (_loggerEnabled) - { - _logger.LogTrace($"Created a channel for thread: {threadId}, total channels: {_channelsCount}/{_maxChannels}"); - } } + + channel = await _connection.CreateChannelAsync(); + _channels.TryAdd(threadId, channel); + _channelsCount++; + if (_loggerEnabled) + { + _logger.LogTrace($"Created a channel for thread: {threadId}, total channels: {_channelsCount}/{_maxChannels}"); + } + } else { @@ -67,16 +75,23 @@ public void Send(object message, IConventions conventions, string messageId = nu } var body = _serializer.Serialize(message); - var properties = channel.CreateBasicProperties(); + + BasicProperties properties = new BasicProperties(); + + // var properties = channel.BasicProperties(); properties.Persistent = _persistMessages; + properties.MessageId = string.IsNullOrWhiteSpace(messageId) ? Guid.NewGuid().ToString("N") : messageId; + properties.CorrelationId = string.IsNullOrWhiteSpace(correlationId) ? Guid.NewGuid().ToString("N") : correlationId; + properties.Timestamp = new AmqpTimestamp(DateTimeOffset.UtcNow.ToUnixTimeSeconds()); - properties.Headers = new Dictionary(); + + properties.Headers = new Dictionary(); if (_contextEnabled) { @@ -108,11 +123,17 @@ public void Send(object message, IConventions conventions, string messageId = nu $"[id: '{properties.MessageId}', correlation id: '{properties.CorrelationId}']"); } - channel.BasicPublish(conventions.Exchange, conventions.RoutingKey, properties, body.ToArray()); + await channel.BasicPublishAsync(conventions.Exchange, conventions.RoutingKey, true, properties, body.ToArray()); } - private void IncludeMessageContext(object context, IBasicProperties properties) + private void IncludeMessageContext(object? context, IBasicProperties properties) { + if (context is null) + return; + + if (properties.Headers is null) + return; + if (context is not null) { properties.Headers.Add(_contextProvider.HeaderName, _serializer.Serialize(context).ToArray()); diff --git a/src/Genocs.MessageBrokers.RabbitMQ/Contexts/ContextProvider.cs b/src/Genocs.MessageBrokers.RabbitMQ/Contexts/ContextProvider.cs index 57ee9060..1cc2fce9 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/Contexts/ContextProvider.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/Contexts/ContextProvider.cs @@ -2,10 +2,10 @@ namespace Genocs.MessageBrokers.RabbitMQ.Contexts; internal sealed class ContextProvider : IContextProvider { - private readonly IRabbitMqSerializer _serializer; + private readonly IRabbitMQSerializer _serializer; public string HeaderName { get; } - public ContextProvider(IRabbitMqSerializer serializer, RabbitMQOptions options) + public ContextProvider(IRabbitMQSerializer serializer, RabbitMQOptions options) { _serializer = serializer; HeaderName = string.IsNullOrWhiteSpace(options.Context?.Header) @@ -13,14 +13,14 @@ public ContextProvider(IRabbitMqSerializer serializer, RabbitMQOptions options) : options.Context.Header; } - public object Get(IDictionary headers) + public object? Get(IDictionary? headers) { if (headers is null) { return null; } - if (!headers.TryGetValue(HeaderName, out var context)) + if (!headers.TryGetValue(HeaderName, out object? context)) { return null; } diff --git a/src/Genocs.MessageBrokers.RabbitMQ/Extensions.cs b/src/Genocs.MessageBrokers.RabbitMQ/Extensions.cs index 15c93d89..0d47431b 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/Extensions.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/Extensions.cs @@ -35,12 +35,12 @@ public static class Extensions /// The serializer. /// /// Raised when configuration is incorrect. - public static IGenocsBuilder AddRabbitMq( + public static async Task AddRabbitMQAsync( this IGenocsBuilder builder, string sectionName = SectionName, Func? plugins = null, Action? connectionFactoryConfigurator = null, - IRabbitMqSerializer? serializer = null) + IRabbitMQSerializer? serializer = null) { if (string.IsNullOrWhiteSpace(sectionName)) { @@ -51,7 +51,7 @@ public static IGenocsBuilder AddRabbitMq( builder.Services.AddSingleton(options); if (!builder.TryRegister(RegistryName)) { - return builder; + return await Task.FromResult(builder); } if (options.HostNames is null || !options.HostNames.Any()) @@ -72,8 +72,8 @@ public static IGenocsBuilder AddRabbitMq( builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddTransient(); builder.Services.AddHostedService(); @@ -85,7 +85,7 @@ public static IGenocsBuilder AddRabbitMq( } else { - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); } var pluginsRegistry = new RabbitMqPluginsRegistry(); @@ -105,8 +105,6 @@ public static IGenocsBuilder AddRabbitMq( SocketWriteTimeout = options.SocketWriteTimeout, RequestedChannelMax = options.RequestedChannelMax, RequestedFrameMax = options.RequestedFrameMax, - UseBackgroundThreadsForIO = options.UseBackgroundThreadsForIO, - DispatchConsumersAsync = true, ContinuationTimeout = options.ContinuationTimeout, HandshakeContinuationTimeout = options.HandshakeContinuationTimeout, NetworkRecoveryInterval = options.NetworkRecoveryInterval, @@ -118,8 +116,8 @@ public static IGenocsBuilder AddRabbitMq( connectionFactoryConfigurator?.Invoke(connectionFactory); logger.LogDebug($"Connecting to RabbitMQ: '{string.Join(", ", options.HostNames)}'..."); - var consumerConnection = connectionFactory.CreateConnection(options.HostNames.ToList(), $"{options.ConnectionName}_consumer"); - var producerConnection = connectionFactory.CreateConnection(options.HostNames.ToList(), $"{options.ConnectionName}_producer"); + var consumerConnection = await connectionFactory.CreateConnectionAsync(options.HostNames.ToList(), $"{options.ConnectionName}_consumer"); + var producerConnection = await connectionFactory.CreateConnectionAsync(options.HostNames.ToList(), $"{options.ConnectionName}_producer"); logger.LogDebug($"Connected to RabbitMQ: '{string.Join(", ", options.HostNames)}'."); builder.Services.AddSingleton(new ConsumerConnection(consumerConnection)); builder.Services.AddSingleton(new ProducerConnection(producerConnection)); @@ -212,6 +210,6 @@ public static IGenocsBuilder AddExceptionToFailedMessageMapper(this IGenocsBu return builder; } - public static IBusSubscriber UseRabbitMq(this IApplicationBuilder app) - => new RabbitMqSubscriber(app.ApplicationServices.GetRequiredService()); + public static IBusSubscriber UseRabbitMQ(this IApplicationBuilder app) + => new RabbitMQSubscriber(app.ApplicationServices.GetRequiredService()); } \ No newline at end of file diff --git a/src/Genocs.MessageBrokers.RabbitMQ/Genocs.MessageBrokers.RabbitMQ.csproj b/src/Genocs.MessageBrokers.RabbitMQ/Genocs.MessageBrokers.RabbitMQ.csproj index a36b28d6..ef26b78e 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/Genocs.MessageBrokers.RabbitMQ.csproj +++ b/src/Genocs.MessageBrokers.RabbitMQ/Genocs.MessageBrokers.RabbitMQ.csproj @@ -22,13 +22,13 @@ - + - + diff --git a/src/Genocs.MessageBrokers.RabbitMQ/IRabbitMqClient.cs b/src/Genocs.MessageBrokers.RabbitMQ/IRabbitMqClient.cs index b7d4e687..dc0be008 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/IRabbitMqClient.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/IRabbitMqClient.cs @@ -2,12 +2,12 @@ namespace Genocs.MessageBrokers.RabbitMQ; public interface IRabbitMQClient { - void Send( - object? message, - IConventions conventions, - string? messageId = null, - string? correlationId = null, - string? spanContext = null, - object? messageContext = null, - IDictionary? headers = null); + Task SendAsync( + object message, + IConventions conventions, + string? messageId = null, + string? correlationId = null, + string? spanContext = null, + object? messageContext = null, + IDictionary? headers = null); } \ No newline at end of file diff --git a/src/Genocs.MessageBrokers.RabbitMQ/IRabbitMqSerializer.cs b/src/Genocs.MessageBrokers.RabbitMQ/IRabbitMqSerializer.cs index ce700415..0fbdab94 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/IRabbitMqSerializer.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/IRabbitMqSerializer.cs @@ -1,6 +1,6 @@ namespace Genocs.MessageBrokers.RabbitMQ; -public interface IRabbitMqSerializer +public interface IRabbitMQSerializer { ReadOnlySpan Serialize(object value); object? Deserialize(ReadOnlySpan value, Type type); diff --git a/src/Genocs.MessageBrokers.RabbitMQ/Initializers/RabbitMqExchangeInitializer.cs b/src/Genocs.MessageBrokers.RabbitMQ/Initializers/RabbitMqExchangeInitializer.cs index d80af9f3..e51c0c35 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/Initializers/RabbitMqExchangeInitializer.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/Initializers/RabbitMqExchangeInitializer.cs @@ -1,7 +1,7 @@ +using System.Reflection; using Genocs.Common.Types; using Microsoft.Extensions.Logging; using RabbitMQ.Client; -using System.Reflection; namespace Genocs.MessageBrokers.RabbitMQ.Initializers; @@ -13,8 +13,10 @@ public class RabbitMqExchangeInitializer : IInitializer private readonly ILogger _logger; private readonly bool _loggerEnabled; - public RabbitMqExchangeInitializer(ProducerConnection connection, RabbitMQOptions options, - ILogger logger) + public RabbitMqExchangeInitializer( + ProducerConnection connection, + RabbitMQOptions options, + ILogger logger) { _connection = connection.Connection; _options = options; @@ -22,7 +24,7 @@ public RabbitMqExchangeInitializer(ProducerConnection connection, RabbitMQOption _loggerEnabled = _options.Logger?.Enabled == true; } - public Task InitializeAsync() + public async Task InitializeAsync() { var exchanges = AppDomain.CurrentDomain .GetAssemblies() @@ -32,41 +34,41 @@ public Task InitializeAsync() .Distinct() .ToList(); - using var channel = _connection.CreateModel(); + using var channel = await _connection.CreateChannelAsync(); if (_options.Exchange?.Declare == true) { Log(_options.Exchange.Name, _options.Exchange.Type); - channel.ExchangeDeclare( - _options.Exchange.Name, - _options.Exchange.Type, - _options.Exchange.Durable, - _options.Exchange.AutoDelete); + await channel.ExchangeDeclareAsync( + _options.Exchange.Name, + _options.Exchange.Type, + _options.Exchange.Durable, + _options.Exchange.AutoDelete); if (_options.DeadLetter?.Enabled is true && _options.DeadLetter?.Declare is true) { - channel.ExchangeDeclare( - $"{_options.DeadLetter.Prefix}{_options.Exchange.Name}{_options.DeadLetter.Suffix}", - ExchangeType.Direct, - _options.Exchange.Durable, - _options.Exchange.AutoDelete); + await channel.ExchangeDeclareAsync( + $"{_options.DeadLetter.Prefix}{_options.Exchange.Name}{_options.DeadLetter.Suffix}", + ExchangeType.Direct, + _options.Exchange.Durable, + _options.Exchange.AutoDelete); } } foreach (string? exchange in exchanges) { + if (string.IsNullOrWhiteSpace(exchange)) continue; + if (exchange.Equals(_options.Exchange?.Name, StringComparison.InvariantCultureIgnoreCase)) { continue; } Log(exchange, DefaultType); - channel.ExchangeDeclare(exchange, DefaultType, true); + await channel.ExchangeDeclareAsync(exchange, DefaultType, true); } - channel.Close(); - - return Task.CompletedTask; + await channel.CloseAsync(); } private void Log(string exchange, string type) diff --git a/src/Genocs.MessageBrokers.RabbitMQ/Internals/RabbitMqBackgroundService.cs b/src/Genocs.MessageBrokers.RabbitMQ/Internals/RabbitMqBackgroundService.cs index 26d077e8..79068321 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/Internals/RabbitMqBackgroundService.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/Internals/RabbitMqBackgroundService.cs @@ -8,6 +8,7 @@ using RabbitMQ.Client; using RabbitMQ.Client.Events; using System.Collections.Concurrent; +using System.Runtime.CompilerServices; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; @@ -24,7 +25,7 @@ internal sealed class RabbitMqBackgroundService : BackgroundService WriteIndented = true }; - private readonly ConcurrentDictionary _channels = new(); + private readonly ConcurrentDictionary _channels = new(); private readonly EmptyExceptionToMessageMapper _exceptionMapper = new(); private readonly EmptyExceptionToFailedMessageMapper _exceptionFailedMapper = new(); private readonly IServiceProvider _serviceProvider; @@ -32,7 +33,7 @@ internal sealed class RabbitMqBackgroundService : BackgroundService private readonly IConnection _producerConnection; private readonly MessageSubscribersChannel _messageSubscribersChannel; private readonly IBusPublisher _publisher; - private readonly IRabbitMqSerializer _rabbitMqSerializer; + private readonly IRabbitMQSerializer _rabbitMqSerializer; private readonly IConventionsProvider _conventionsProvider; private readonly IContextProvider _contextProvider; private readonly ILogger _logger; @@ -54,10 +55,10 @@ public RabbitMqBackgroundService(IServiceProvider serviceProvider) _producerConnection = serviceProvider.GetRequiredService().Connection; _messageSubscribersChannel = serviceProvider.GetRequiredService(); _publisher = _serviceProvider.GetRequiredService(); - _rabbitMqSerializer = _serviceProvider.GetRequiredService(); + _rabbitMqSerializer = _serviceProvider.GetRequiredService(); _conventionsProvider = _serviceProvider.GetRequiredService(); _contextProvider = _serviceProvider.GetRequiredService(); - _logger = _serviceProvider.GetRequiredService>(); + _logger = _serviceProvider.GetRequiredService>(); _exceptionToMessageMapper = _serviceProvider.GetService() ?? _exceptionMapper; _exceptionToFailedMessageMapper = _serviceProvider.GetService() ?? _exceptionFailedMapper; _pluginsExecutor = _serviceProvider.GetRequiredService(); @@ -78,15 +79,15 @@ public RabbitMqBackgroundService(IServiceProvider serviceProvider) return; } - _consumerConnection.CallbackException += ConnectionOnCallbackException; - _consumerConnection.ConnectionShutdown += ConnectionOnConnectionShutdown; - _consumerConnection.ConnectionBlocked += ConnectionOnConnectionBlocked; - _consumerConnection.ConnectionUnblocked += ConnectionOnConnectionUnblocked; + _consumerConnection.CallbackExceptionAsync += ConnectionOnCallbackExceptionAsync; + _consumerConnection.ConnectionShutdownAsync += ConnectionOnConnectionShutdownAsync; + _consumerConnection.ConnectionBlockedAsync += ConnectionOnConnectionBlockedAsync; + _consumerConnection.ConnectionUnblockedAsync += ConnectionOnConnectionUnblockedAsync; - _producerConnection.CallbackException += ConnectionOnCallbackException; - _producerConnection.ConnectionShutdown += ConnectionOnConnectionShutdown; - _producerConnection.ConnectionBlocked += ConnectionOnConnectionBlocked; - _producerConnection.ConnectionUnblocked += ConnectionOnConnectionUnblocked; + _producerConnection.CallbackExceptionAsync += ConnectionOnCallbackExceptionAsync; + _producerConnection.ConnectionShutdownAsync += ConnectionOnConnectionShutdownAsync; + _producerConnection.ConnectionBlockedAsync += ConnectionOnConnectionBlockedAsync; + _producerConnection.ConnectionUnblockedAsync += ConnectionOnConnectionUnblockedAsync; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) @@ -98,7 +99,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) switch (messageSubscriber.Action) { case MessageSubscriberAction.Subscribe: - Subscribe(messageSubscriber); + await SubscribeAsync(messageSubscriber); break; case MessageSubscriberAction.Unsubscribe: Unsubscribe(messageSubscriber); @@ -115,7 +116,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } } - private void Subscribe(IMessageSubscriber messageSubscriber) + private async Task SubscribeAsync(IMessageSubscriber messageSubscriber) { var conventions = _conventionsProvider.Get(messageSubscriber.Type); var channelKey = GetChannelKey(conventions); @@ -124,7 +125,7 @@ private void Subscribe(IMessageSubscriber messageSubscriber) return; } - var channel = _consumerConnection.CreateModel(); + var channel = await _consumerConnection.CreateChannelAsync(); var channelInfoLog = $"exchange: '{conventions.Exchange}', queue: '{conventions.Queue}', " + $"routing key: '{conventions.RoutingKey}'"; @@ -137,7 +138,7 @@ private void Subscribe(IMessageSubscriber messageSubscriber) _logger.LogTrace($"Added the channel: {channel.ChannelNumber} for {channelInfoLog}."); - var declare = _options.Queue?.Declare ?? true; + bool declare = _options.Queue?.Declare ?? true; var durable = _options.Queue?.Durable ?? true; var exclusive = _options.Queue?.Exclusive ?? false; var autoDelete = _options.Queue?.AutoDelete ?? false; @@ -165,11 +166,12 @@ private void Subscribe(IMessageSubscriber messageSubscriber) {"x-dead-letter-routing-key", deadLetterQueue}, } : new Dictionary(); - channel.QueueDeclare(conventions.Queue, durable, exclusive, autoDelete, queueArguments); + + await channel.QueueDeclareAsync(conventions.Queue, durable, exclusive, autoDelete, queueArguments); } - channel.QueueBind(conventions.Queue, conventions.Exchange, conventions.RoutingKey); - channel.BasicQos(_qosOptions.PrefetchSize, _qosOptions.PrefetchCount, _qosOptions.Global); + await channel.QueueBindAsync(conventions.Queue, conventions.Exchange, conventions.RoutingKey); + await channel.BasicQosAsync(_qosOptions.PrefetchSize, _qosOptions.PrefetchCount, _qosOptions.Global); if (_options.DeadLetter?.Enabled is true) { @@ -191,15 +193,19 @@ private void Subscribe(IMessageSubscriber messageSubscriber) _logger.LogInformation($"Declaring a dead letter queue: '{deadLetterQueue}' " + $"for an exchange: '{deadLetterExchange}'{(ttl.HasValue ? $", message TTL: {ttl} ms." : ".")}"); - channel.QueueDeclare(deadLetterQueue, _options.DeadLetter.Durable, _options.DeadLetter.Exclusive, - _options.DeadLetter.AutoDelete, deadLetterArgs); + await channel.QueueDeclareAsync( + deadLetterQueue, + _options.DeadLetter.Durable, + _options.DeadLetter.Exclusive, + _options.DeadLetter.AutoDelete, + deadLetterArgs); } - channel.QueueBind(deadLetterQueue, deadLetterExchange, deadLetterQueue); + await channel.QueueBindAsync(deadLetterQueue, deadLetterExchange, deadLetterQueue); } var consumer = new AsyncEventingBasicConsumer(channel); - consumer.Received += async (_, args) => + consumer.ReceivedAsync += async (_, args) => { try { @@ -213,7 +219,8 @@ private void Subscribe(IMessageSubscriber messageSubscriber) if (_loggerEnabled) { var messagePayload = _logMessagePayload ? Encoding.UTF8.GetString(args.Body.Span) : string.Empty; - _logger.LogInformation("Received a message with ID: '{MessageId}', " + + _logger.LogInformation( + "Received a message with ID: '{MessageId}', " + "Correlation ID: '{CorrelationId}', timestamp: {Timestamp}, " + "queue: {Queue}, routing key: {RoutingKey}, exchange: {Exchange}, payload: {MessagePayload}", messageId, correlationId, timestamp, conventions.Queue, conventions.RoutingKey, conventions.Exchange, messagePayload); @@ -230,12 +237,12 @@ Task Next(object m, object ctx, BasicDeliverEventArgs a) catch (Exception ex) { _logger.LogError(ex, ex.Message); - channel.BasicNack(args.DeliveryTag, false, _requeueFailedMessages); + await channel.BasicNackAsync(args.DeliveryTag, false, _requeueFailedMessages); await Task.Yield(); } }; - channel.BasicConsume(conventions.Queue, false, consumer); + await channel.BasicConsumeAsync(conventions.Queue, false, consumer); } private object BuildCorrelationContext(IServiceScope scope, BasicDeliverEventArgs args) @@ -255,9 +262,15 @@ private object BuildCorrelationContext(IServiceScope scope, BasicDeliverEventArg return correlationContext; } - private async Task TryHandleAsync(IModel channel, object message, string messageId, string correlationId, - object messageContext, BasicDeliverEventArgs args, Func handle, - bool deadLetterEnabled) + private async Task TryHandleAsync( + IChannel channel, + object message, + string messageId, + string correlationId, + object messageContext, + BasicDeliverEventArgs args, + Func handle, + bool deadLetterEnabled) { var currentRetry = 0; var messageName = message.GetType().Name.Underscore(); @@ -290,7 +303,7 @@ await retryPolicy.ExecuteAsync(async () => await handle(_serviceProvider, message, messageContext); } - channel.BasicAck(args.DeliveryTag, false); + channel.BasicAckAsync(args.DeliveryTag, false); await Task.Yield(); if (_loggerEnabled) @@ -305,7 +318,7 @@ await retryPolicy.ExecuteAsync(async () => _logger.LogError(ex, ex.Message); if (ex is RabbitMqMessageProcessingTimeoutException) { - channel.BasicNack(args.DeliveryTag, false, _requeueFailedMessages); + channel.BasicNackAsync(args.DeliveryTag, false, _requeueFailedMessages); await Task.Yield(); return; } @@ -340,7 +353,7 @@ await _publisher.PublishAsync(failedMessage.Message, failedMessageId, correlatio if (!deadLetterEnabled || !failedMessage.MoveToDeadLetter) { - channel.BasicAck(args.DeliveryTag, false); + channel.BasicAckAsync(args.DeliveryTag, false); await Task.Yield(); return; } @@ -364,7 +377,7 @@ await _publisher.PublishAsync(failedMessage.Message, failedMessageId, correlatio if (failedMessage is not null && !failedMessage.MoveToDeadLetter) { - channel.BasicAck(args.DeliveryTag, false); + channel.BasicAckAsync(args.DeliveryTag, false); await Task.Yield(); return; } @@ -375,7 +388,7 @@ await _publisher.PublishAsync(failedMessage.Message, failedMessageId, correlatio "{CorrelationId} will be moved to DLX", messageName, messageId, correlationId); } - channel.BasicNack(args.DeliveryTag, false, _requeueFailedMessages); + channel.BasicNackAsync(args.DeliveryTag, false, _requeueFailedMessages); await Task.Yield(); } }); @@ -404,15 +417,15 @@ public override void Dispose() { if (_loggerEnabled && _options.Logger?.LogConnectionStatus is true) { - _consumerConnection.CallbackException -= ConnectionOnCallbackException; - _consumerConnection.ConnectionShutdown -= ConnectionOnConnectionShutdown; - _consumerConnection.ConnectionBlocked -= ConnectionOnConnectionBlocked; - _consumerConnection.ConnectionUnblocked -= ConnectionOnConnectionUnblocked; - - _producerConnection.CallbackException -= ConnectionOnCallbackException; - _producerConnection.ConnectionShutdown -= ConnectionOnConnectionShutdown; - _producerConnection.ConnectionBlocked -= ConnectionOnConnectionBlocked; - _producerConnection.ConnectionUnblocked -= ConnectionOnConnectionUnblocked; + _consumerConnection.CallbackExceptionAsync -= ConnectionOnCallbackExceptionAsync; + _consumerConnection.ConnectionShutdownAsync -= ConnectionOnConnectionShutdownAsync; + _consumerConnection.ConnectionBlockedAsync -= ConnectionOnConnectionBlockedAsync; + _consumerConnection.ConnectionUnblockedAsync -= ConnectionOnConnectionUnblockedAsync; + + _producerConnection.CallbackExceptionAsync -= ConnectionOnCallbackExceptionAsync; + _producerConnection.ConnectionShutdownAsync -= ConnectionOnConnectionShutdownAsync; + _producerConnection.ConnectionBlockedAsync -= ConnectionOnConnectionBlockedAsync; + _producerConnection.ConnectionUnblockedAsync -= ConnectionOnConnectionUnblockedAsync; } foreach (var (key, channel) in _channels) @@ -423,8 +436,8 @@ public override void Dispose() try { - _consumerConnection.Close(); - _producerConnection.Close(); + _consumerConnection.CloseAsync(); + _producerConnection.CloseAsync(); } catch { @@ -444,9 +457,9 @@ private class EmptyExceptionToFailedMessageMapper : IExceptionToFailedMessageMap public FailedMessage Map(Exception exception, object message) => null; } - private void ConnectionOnCallbackException(object sender, CallbackExceptionEventArgs eventArgs) + private async Task ConnectionOnCallbackExceptionAsync(object sender, CallbackExceptionEventArgs eventArgs) { - _logger.LogError("RabbitMQ callback exception occured."); + _logger.LogError("RabbitMQ callback exception occurred."); if (eventArgs.Exception is not null) { _logger.LogError(eventArgs.Exception, eventArgs.Exception.Message); @@ -456,21 +469,27 @@ private void ConnectionOnCallbackException(object sender, CallbackExceptionEvent { _logger.LogError(JsonSerializer.Serialize(eventArgs.Detail, SerializerOptions)); } + + await Task.CompletedTask; } - private void ConnectionOnConnectionShutdown(object sender, ShutdownEventArgs eventArgs) + private async Task ConnectionOnConnectionShutdownAsync(object sender, ShutdownEventArgs eventArgs) { - _logger.LogError($"RabbitMQ connection shutdown occured. Initiator: '{eventArgs.Initiator}', " + + _logger.LogError($"RabbitMQ connection shutdown occurred. Initiator: '{eventArgs.Initiator}', " + $"reply code: '{eventArgs.ReplyCode}', text: '{eventArgs.ReplyText}'."); + + await Task.CompletedTask; } - private void ConnectionOnConnectionBlocked(object sender, ConnectionBlockedEventArgs eventArgs) + private async Task ConnectionOnConnectionBlockedAsync(object sender, ConnectionBlockedEventArgs eventArgs) { _logger.LogError($"RabbitMQ connection has been blocked. {eventArgs.Reason}"); + await Task.CompletedTask; } - private void ConnectionOnConnectionUnblocked(object sender, EventArgs eventArgs) + private async Task ConnectionOnConnectionUnblockedAsync(object sender, AsyncEventArgs eventArgs) { _logger.LogInformation("RabbitMQ connection has been unblocked."); + await Task.CompletedTask; } } \ No newline at end of file diff --git a/src/Genocs.MessageBrokers.RabbitMQ/Publishers/RabbitMqPublisher.cs b/src/Genocs.MessageBrokers.RabbitMQ/Publishers/RabbitMqPublisher.cs index 143a6607..b1bce4d5 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/Publishers/RabbitMqPublisher.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/Publishers/RabbitMqPublisher.cs @@ -1,22 +1,33 @@ namespace Genocs.MessageBrokers.RabbitMQ.Publishers; -internal sealed class RabbitMqPublisher : IBusPublisher +internal sealed class RabbitMQPublisher : IBusPublisher { private readonly IRabbitMQClient _client; private readonly IConventionsProvider _conventionsProvider; - public RabbitMqPublisher(IRabbitMQClient client, IConventionsProvider conventionsProvider) + public RabbitMQPublisher(IRabbitMQClient client, IConventionsProvider conventionsProvider) { _client = client; _conventionsProvider = conventionsProvider; } - public Task PublishAsync(T message, string? messageId = null, string correlationId = null, - string spanContext = null, object messageContext = null, IDictionary headers = null) + public Task PublishAsync( + T message, + string? messageId = null, + string? correlationId = null, + string? spanContext = null, + object? messageContext = null, + IDictionary? headers = null) where T : class { - _client.Send(message, _conventionsProvider.Get(message.GetType()), messageId, correlationId, spanContext, - messageContext, headers); + _client.SendAsync( + message, + _conventionsProvider.Get(message.GetType()), + messageId, + correlationId, + spanContext, + messageContext, + headers); return Task.CompletedTask; } diff --git a/src/Genocs.MessageBrokers.RabbitMQ/RabbitMqOptions.cs b/src/Genocs.MessageBrokers.RabbitMQ/RabbitMqOptions.cs index bd0154b4..cd791f48 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/RabbitMqOptions.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/RabbitMqOptions.cs @@ -2,12 +2,12 @@ namespace Genocs.MessageBrokers.RabbitMQ; public class RabbitMQOptions { - public string ConnectionName { get; set; } - public IEnumerable HostNames { get; set; } + public string? ConnectionName { get; set; } + public IEnumerable? HostNames { get; set; } public int Port { get; set; } - public string VirtualHost { get; set; } - public string Username { get; set; } - public string Password { get; set; } + public string VirtualHost { get; set; } = "/"; + public string Username { get; set; } = "guest"; + public string Password { get; set; } = "guest"; public TimeSpan RequestedHeartbeat { get; set; } = TimeSpan.FromSeconds(60); public TimeSpan RequestedConnectionTimeout { get; set; } = TimeSpan.FromSeconds(30); public TimeSpan SocketReadTimeout { get; set; } = TimeSpan.FromSeconds(30); @@ -18,20 +18,19 @@ public class RabbitMQOptions public TimeSpan? MessageProcessingTimeout { get; set; } public ushort RequestedChannelMax { get; set; } public uint RequestedFrameMax { get; set; } - public bool UseBackgroundThreadsForIO { get; set; } - public string ConventionsCasing { get; set; } + public string? ConventionsCasing { get; set; } public int Retries { get; set; } public int RetryInterval { get; set; } public bool MessagesPersisted { get; set; } - public ContextOptions Context { get; set; } - public ExchangeOptions Exchange { get; set; } - public LoggerOptions Logger { get; set; } - public SslOptions Ssl { get; set; } - public QueueOptions Queue { get; set; } - public DeadLetterOptions DeadLetter { get; set; } - public QosOptions Qos { get; set; } - public ConventionsOptions Conventions { get; set; } - public string SpanContextHeader { get; set; } + public ContextOptions? Context { get; set; } + public ExchangeOptions? Exchange { get; set; } + public LoggerOptions? Logger { get; set; } + public SslOptions? Ssl { get; set; } + public QueueOptions? Queue { get; set; } + public DeadLetterOptions? DeadLetter { get; set; } + public QosOptions? Qos { get; set; } + public ConventionsOptions? Conventions { get; set; } + public string? SpanContextHeader { get; set; } public int MaxProducerChannels { get; set; } public bool RequeueFailedMessages { get; set; } @@ -48,13 +47,13 @@ public class LoggerOptions public class ContextOptions { public bool Enabled { get; set; } - public string Header { get; set; } + public string? Header { get; set; } } public class ExchangeOptions { - public string Name { get; set; } - public string Type { get; set; } + public string? Name { get; set; } + public string? Type { get; set; } public bool Declare { get; set; } public bool Durable { get; set; } public bool AutoDelete { get; set; } @@ -62,7 +61,7 @@ public class ExchangeOptions public class QueueOptions { - public string Template { get; set; } + public string? Template { get; set; } public bool Declare { get; set; } public bool Durable { get; set; } public bool Exclusive { get; set; } @@ -72,8 +71,8 @@ public class QueueOptions public class DeadLetterOptions { public bool Enabled { get; set; } - public string Prefix { get; set; } - public string Suffix { get; set; } + public string? Prefix { get; set; } + public string? Suffix { get; set; } public bool Declare { get; set; } public bool Durable { get; set; } public bool Exclusive { get; set; } @@ -84,10 +83,10 @@ public class DeadLetterOptions public class SslOptions { public bool Enabled { get; set; } - public string ServerName { get; set; } - public string CertificatePath { get; set; } - public string CaCertificatePath { get; set; } - public IEnumerable X509IgnoredStatuses { get; set; } + public string? ServerName { get; set; } + public string? CertificatePath { get; set; } + public string? CaCertificatePath { get; set; } + public IEnumerable? X509IgnoredStatuses { get; set; } } public class QosOptions @@ -99,7 +98,7 @@ public class QosOptions public class ConventionsOptions { - public MessageAttributeOptions MessageAttribute { get; set; } + public MessageAttributeOptions? MessageAttribute { get; set; } public class MessageAttributeOptions { diff --git a/src/Genocs.MessageBrokers.RabbitMQ/RabbitMqPlugin.cs b/src/Genocs.MessageBrokers.RabbitMQ/RabbitMqPlugin.cs index 3ffb8fc6..3466f4c7 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/RabbitMqPlugin.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/RabbitMqPlugin.cs @@ -7,8 +7,7 @@ public abstract class RabbitMQPlugin : IRabbitMqPlugin, IRabbitMqPluginAccessor { private Func _successor; - public abstract Task HandleAsync(object message, object correlationContext, - BasicDeliverEventArgs args); + public abstract Task HandleAsync(object message, object correlationContext, BasicDeliverEventArgs args); public Task Next(object message, object correlationContext, BasicDeliverEventArgs args) => _successor(message, correlationContext, args); diff --git a/src/Genocs.MessageBrokers.RabbitMQ/Serializers/NewtonsoftJsonRabbitMqSerializer.cs b/src/Genocs.MessageBrokers.RabbitMQ/Serializers/NewtonsoftJsonRabbitMqSerializer.cs index 1cb8fd48..ed2afb77 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/Serializers/NewtonsoftJsonRabbitMqSerializer.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/Serializers/NewtonsoftJsonRabbitMqSerializer.cs @@ -4,11 +4,11 @@ namespace Genocs.MessageBrokers.RabbitMQ.Serializers; -public sealed class NewtonsoftJsonRabbitMqSerializer : IRabbitMqSerializer +public sealed class NewtonsoftJsonRabbitMQSerializer : IRabbitMQSerializer { private readonly JsonSerializerSettings _settings; - public NewtonsoftJsonRabbitMqSerializer(JsonSerializerSettings settings = null) + public NewtonsoftJsonRabbitMQSerializer(JsonSerializerSettings? settings = null) { _settings = settings ?? new JsonSerializerSettings { diff --git a/src/Genocs.MessageBrokers.RabbitMQ/Serializers/SystemTextJsonJsonRabbitMqSerializer.cs b/src/Genocs.MessageBrokers.RabbitMQ/Serializers/SystemTextJsonJsonRabbitMqSerializer.cs index 78352ac8..3f68966b 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/Serializers/SystemTextJsonJsonRabbitMqSerializer.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/Serializers/SystemTextJsonJsonRabbitMqSerializer.cs @@ -3,11 +3,11 @@ namespace Genocs.MessageBrokers.RabbitMQ.Serializers; -public sealed class SystemTextJsonJsonRabbitMqSerializer : IRabbitMqSerializer +public sealed class SystemTextJsonJsonRabbitMQSerializer : IRabbitMQSerializer { private readonly JsonSerializerOptions _options; - public SystemTextJsonJsonRabbitMqSerializer(JsonSerializerOptions options = null) + public SystemTextJsonJsonRabbitMQSerializer(JsonSerializerOptions options = null) { _options = options ?? new JsonSerializerOptions { diff --git a/src/Genocs.MessageBrokers.RabbitMQ/Subscribers/RabbitMqSubscriber.cs b/src/Genocs.MessageBrokers.RabbitMQ/Subscribers/RabbitMqSubscriber.cs index be7306e3..0fa54798 100644 --- a/src/Genocs.MessageBrokers.RabbitMQ/Subscribers/RabbitMqSubscriber.cs +++ b/src/Genocs.MessageBrokers.RabbitMQ/Subscribers/RabbitMqSubscriber.cs @@ -1,10 +1,10 @@ namespace Genocs.MessageBrokers.RabbitMQ.Subscribers; -internal sealed class RabbitMqSubscriber : IBusSubscriber +internal sealed class RabbitMQSubscriber : IBusSubscriber { private readonly MessageSubscribersChannel _messageSubscribersChannel; - public RabbitMqSubscriber(MessageSubscribersChannel messageSubscribersChannel) + public RabbitMQSubscriber(MessageSubscribersChannel messageSubscribersChannel) { _messageSubscribersChannel = messageSubscribersChannel; } @@ -13,8 +13,10 @@ public IBusSubscriber Subscribe(Func handl where T : class { var type = typeof(T); - _messageSubscribersChannel.Writer.TryWrite(MessageSubscriber.Subscribe(type, - (serviceProvider, message, context) => handle(serviceProvider, (T)message, context))); + + _messageSubscribersChannel.Writer.TryWrite(MessageSubscriber.Subscribe(type, (serviceProvider, message, context) + => handle(serviceProvider, (T)message, context))); + return this; } diff --git a/src/Genocs.MessageBrokers/Genocs.MessageBrokers.csproj b/src/Genocs.MessageBrokers/Genocs.MessageBrokers.csproj index 69fde5a1..d3bf1f90 100644 --- a/src/Genocs.MessageBrokers/Genocs.MessageBrokers.csproj +++ b/src/Genocs.MessageBrokers/Genocs.MessageBrokers.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.Metrics/Genocs.Metrics.csproj b/src/Genocs.Metrics/Genocs.Metrics.csproj index 348ea903..b6a8cde2 100644 --- a/src/Genocs.Metrics/Genocs.Metrics.csproj +++ b/src/Genocs.Metrics/Genocs.Metrics.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.Monitoring/Genocs.Monitoring.csproj b/src/Genocs.Monitoring/Genocs.Monitoring.csproj index ab4afe99..28ef554a 100644 --- a/src/Genocs.Monitoring/Genocs.Monitoring.csproj +++ b/src/Genocs.Monitoring/Genocs.Monitoring.csproj @@ -40,9 +40,9 @@ - - - + + + diff --git a/src/Genocs.Persistence.MongoDb.UnitTests/Genocs.Persistence.MongoDB.UnitTests.csproj b/src/Genocs.Persistence.MongoDb.UnitTests/Genocs.Persistence.MongoDB.UnitTests.csproj index a4380106..65343529 100644 --- a/src/Genocs.Persistence.MongoDb.UnitTests/Genocs.Persistence.MongoDB.UnitTests.csproj +++ b/src/Genocs.Persistence.MongoDb.UnitTests/Genocs.Persistence.MongoDB.UnitTests.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/Genocs.Persistence.MongoDb/Genocs.Persistence.MongoDb.csproj b/src/Genocs.Persistence.MongoDb/Genocs.Persistence.MongoDb.csproj index f02a1ef6..a3e9acfc 100644 --- a/src/Genocs.Persistence.MongoDb/Genocs.Persistence.MongoDb.csproj +++ b/src/Genocs.Persistence.MongoDb/Genocs.Persistence.MongoDb.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.Persistence.Redis/Genocs.Persistence.Redis.csproj b/src/Genocs.Persistence.Redis/Genocs.Persistence.Redis.csproj index f653099f..fce5256d 100644 --- a/src/Genocs.Persistence.Redis/Genocs.Persistence.Redis.csproj +++ b/src/Genocs.Persistence.Redis/Genocs.Persistence.Redis.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.QueryBuilder.UnitTests/Genocs.QueryBuilder.UnitTests.csproj b/src/Genocs.QueryBuilder.UnitTests/Genocs.QueryBuilder.UnitTests.csproj index 24a8d342..59a58922 100644 --- a/src/Genocs.QueryBuilder.UnitTests/Genocs.QueryBuilder.UnitTests.csproj +++ b/src/Genocs.QueryBuilder.UnitTests/Genocs.QueryBuilder.UnitTests.csproj @@ -13,7 +13,7 @@ - + all @@ -31,8 +31,8 @@ - - + + diff --git a/src/Genocs.Secrets.AzureKeyVault/Genocs.Secrets.AzureKeyVault.csproj b/src/Genocs.Secrets.AzureKeyVault/Genocs.Secrets.AzureKeyVault.csproj index 74abf1cc..1a38cff7 100644 --- a/src/Genocs.Secrets.AzureKeyVault/Genocs.Secrets.AzureKeyVault.csproj +++ b/src/Genocs.Secrets.AzureKeyVault/Genocs.Secrets.AzureKeyVault.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.Secrets.Vault/Extensions.cs b/src/Genocs.Secrets.Vault/Extensions.cs index 6fa05898..b9f26277 100644 --- a/src/Genocs.Secrets.Vault/Extensions.cs +++ b/src/Genocs.Secrets.Vault/Extensions.cs @@ -86,10 +86,6 @@ private static IServiceCollection AddVault(this IServiceCollection services, str } VaultOptions options = configuration.GetOptions(sectionName); - if (!options.Enabled) - { - return services; - } VerifyOptions(options); services.AddSingleton(options); diff --git a/src/Genocs.Secrets.Vault/Genocs.Secrets.Vault.csproj b/src/Genocs.Secrets.Vault/Genocs.Secrets.Vault.csproj index 4f6bc8d5..f8233639 100644 --- a/src/Genocs.Secrets.Vault/Genocs.Secrets.Vault.csproj +++ b/src/Genocs.Secrets.Vault/Genocs.Secrets.Vault.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.Security/Genocs.Security.csproj b/src/Genocs.Security/Genocs.Security.csproj index d92a361f..cea9af1f 100644 --- a/src/Genocs.Security/Genocs.Security.csproj +++ b/src/Genocs.Security/Genocs.Security.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.ServiceBusAzure/Genocs.ServiceBusAzure.csproj b/src/Genocs.ServiceBusAzure/Genocs.ServiceBusAzure.csproj index a9af0299..9f6bfec2 100644 --- a/src/Genocs.ServiceBusAzure/Genocs.ServiceBusAzure.csproj +++ b/src/Genocs.ServiceBusAzure/Genocs.ServiceBusAzure.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.Tracing.Jaeger.RabbitMQ/Genocs.Tracing.Jaeger.RabbitMQ.csproj b/src/Genocs.Tracing.Jaeger.RabbitMQ/Genocs.Tracing.Jaeger.RabbitMQ.csproj index 97844c73..11fd2ba0 100644 --- a/src/Genocs.Tracing.Jaeger.RabbitMQ/Genocs.Tracing.Jaeger.RabbitMQ.csproj +++ b/src/Genocs.Tracing.Jaeger.RabbitMQ/Genocs.Tracing.Jaeger.RabbitMQ.csproj @@ -23,8 +23,8 @@ - - + + diff --git a/src/Genocs.Tracing/Genocs.Tracing.csproj b/src/Genocs.Tracing/Genocs.Tracing.csproj index 58890d57..d34d0661 100644 --- a/src/Genocs.Tracing/Genocs.Tracing.csproj +++ b/src/Genocs.Tracing/Genocs.Tracing.csproj @@ -24,16 +24,16 @@ - - - + + + - - - + + + diff --git a/src/Genocs.WebApi.CQRS/Genocs.WebApi.CQRS.csproj b/src/Genocs.WebApi.CQRS/Genocs.WebApi.CQRS.csproj index d48a85c7..5ee4c0d0 100644 --- a/src/Genocs.WebApi.CQRS/Genocs.WebApi.CQRS.csproj +++ b/src/Genocs.WebApi.CQRS/Genocs.WebApi.CQRS.csproj @@ -23,8 +23,8 @@ - - + + diff --git a/src/Genocs.WebApi.Security/Genocs.WebApi.Security.csproj b/src/Genocs.WebApi.Security/Genocs.WebApi.Security.csproj index 6ad6611d..51d3f1ef 100644 --- a/src/Genocs.WebApi.Security/Genocs.WebApi.Security.csproj +++ b/src/Genocs.WebApi.Security/Genocs.WebApi.Security.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Genocs.WebApi.Swagger/Genocs.WebApi.Swagger.csproj b/src/Genocs.WebApi.Swagger/Genocs.WebApi.Swagger.csproj index 78b7f717..38c8cd00 100644 --- a/src/Genocs.WebApi.Swagger/Genocs.WebApi.Swagger.csproj +++ b/src/Genocs.WebApi.Swagger/Genocs.WebApi.Swagger.csproj @@ -22,15 +22,15 @@ - + - - - - - + + + + + diff --git a/src/Genocs.WebApi/Configurations/WebApiOptions.cs b/src/Genocs.WebApi/Configurations/WebApiOptions.cs index 677c055e..db71d0d2 100644 --- a/src/Genocs.WebApi/Configurations/WebApiOptions.cs +++ b/src/Genocs.WebApi/Configurations/WebApiOptions.cs @@ -5,5 +5,8 @@ namespace Genocs.WebApi.Configurations; /// public class WebApiOptions { + /// + /// It defines whether the request body should be bound from the route or from body. + /// public bool BindRequestFromRoute { get; set; } } \ No newline at end of file diff --git a/src/Genocs.WebApi/Extensions.cs b/src/Genocs.WebApi/Extensions.cs index 18e8c96c..c5d53f63 100644 --- a/src/Genocs.WebApi/Extensions.cs +++ b/src/Genocs.WebApi/Extensions.cs @@ -303,7 +303,7 @@ public static async Task WriteJsonAsync(this HttpResponse response, T value) await serializer.SerializeAsync(response.Body, value); } - public static async Task ReadJsonAsync(this HttpContext httpContext) + public static async Task ReadJsonAsync(this HttpContext httpContext) { var logger = httpContext.RequestServices.GetService(); @@ -323,18 +323,31 @@ public static async Task ReadJsonAsync(this HttpContext httpContext) if (_bindRequestFromRoute && request.HasRouteData()) { var values = request.HttpContext.GetRouteData().Values; + + if (values is null) + { + return payload; + } + foreach (var (key, value) in values) { - var field = payload.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic) - .SingleOrDefault(f => f.Name.ToLowerInvariant().StartsWith($"<{key}>", - StringComparison.InvariantCultureIgnoreCase)); + var field = payload?.GetType() + .GetFields(BindingFlags.Instance | BindingFlags.NonPublic) + .SingleOrDefault(f => f.Name.ToLowerInvariant().StartsWith( + $"<{key}>", + StringComparison.InvariantCultureIgnoreCase)); if (field is null) { continue; } - var fieldValue = TypeDescriptor.GetConverter(field.FieldType) + if (value is null) + { + continue; + } + + object? fieldValue = TypeDescriptor.GetConverter(field.FieldType) .ConvertFromInvariantString(value.ToString()); field.SetValue(payload, fieldValue); } diff --git a/src/Genocs.WebApi/Genocs.WebApi.csproj b/src/Genocs.WebApi/Genocs.WebApi.csproj index ac93a765..6d3e30cb 100644 --- a/src/Genocs.WebApi/Genocs.WebApi.csproj +++ b/src/Genocs.WebApi/Genocs.WebApi.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/apps/.dockerignore b/src/apps/.dockerignore new file mode 100644 index 00000000..52d5e163 --- /dev/null +++ b/src/apps/.dockerignore @@ -0,0 +1,26 @@ +**/[Oo]bj +**/[Bb]in +**/[Ll]ogs +TestResults/ +.nuget/ +_ReSharper.*/ +packages/ +artifacts/ +PublishProfiles/ +*.user +*.suo +*.cache +*.docstates +_ReSharper.* +nuget.exe +*net45.csproj +*k10.csproj +*.psess +*.vsp +*.pidb +*.userprefs +*DS_Store +*.ncrunchsolution +*.*sdf +*.ipch +.vs/ diff --git a/src/apps/api-gateway/Genocs.APIGateway/Framework/MessagingMiddleware.cs b/src/apps/api-gateway/Genocs.APIGateway/Framework/MessagingMiddleware.cs index 9c97684a..e737416a 100644 --- a/src/apps/api-gateway/Genocs.APIGateway/Framework/MessagingMiddleware.cs +++ b/src/apps/api-gateway/Genocs.APIGateway/Framework/MessagingMiddleware.cs @@ -76,13 +76,16 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next) string content = await new StreamReader(context.Request.Body).ReadToEndAsync(); object? message = JsonConvert.DeserializeObject(content); - _rabbitMQClient.Send( - message, - conventions, - messageId, - correlationId, - spanContext, - correlationContext); + if (message is not null) + { + await _rabbitMQClient.SendAsync( + message, + conventions, + messageId, + correlationId, + spanContext, + correlationContext); + } context.Response.StatusCode = StatusCodes.Status202Accepted; return; diff --git a/src/apps/api-gateway/Genocs.APIGateway/Genocs.APIGateway.csproj b/src/apps/api-gateway/Genocs.APIGateway/Genocs.APIGateway.csproj index 99064554..76e0cb44 100644 --- a/src/apps/api-gateway/Genocs.APIGateway/Genocs.APIGateway.csproj +++ b/src/apps/api-gateway/Genocs.APIGateway/Genocs.APIGateway.csproj @@ -19,15 +19,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/src/apps/api-gateway/Genocs.APIGateway/Properties/launchSettings.json b/src/apps/api-gateway/Genocs.APIGateway/Properties/launchSettings.json index ecf16bca..7c5232dd 100644 --- a/src/apps/api-gateway/Genocs.APIGateway/Properties/launchSettings.json +++ b/src/apps/api-gateway/Genocs.APIGateway/Properties/launchSettings.json @@ -1,23 +1,9 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:5000" - } - }, "profiles": { - "Genocs.APIGateway": { + "Local": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5000", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "development" - } - }, - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, + "applicationUrl": "https://localhost:5500;http://localhost:5501", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "development" } diff --git a/src/apps/api-gateway/Genocs.APIGateway/Startup.cs b/src/apps/api-gateway/Genocs.APIGateway/Startup.cs index 0433677e..379c37d9 100644 --- a/src/apps/api-gateway/Genocs.APIGateway/Startup.cs +++ b/src/apps/api-gateway/Genocs.APIGateway/Startup.cs @@ -21,6 +21,12 @@ public Startup(IConfiguration configuration) } public void ConfigureServices(IServiceCollection services) + { + // Find a more elegant way to do this + Task.Run(async () => await ConfigureServicesAsync(services)).Wait(); + } + + private async Task ConfigureServicesAsync(IServiceCollection services) { services.AddScoped(); services.AddScoped(); @@ -33,13 +39,16 @@ public void ConfigureServices(IServiceCollection services) services.AddReverseProxy() .LoadFromConfig(Configuration.GetSection("ReverseProxy")); services.AddSingleton(); - services - .AddGenocs() - .AddOpenTelemetry() - .AddJwt() - .AddPrometheus() - .AddRabbitMq() - .AddSecurity() + + IGenocsBuilder builder = services + .AddGenocs() + .AddOpenTelemetry() + .AddJwt() + .AddPrometheus(); + + await builder.AddRabbitMQAsync(); + + builder.AddSecurity() .AddWebApi() .Build(); @@ -75,7 +84,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UsePrometheus(); app.UseAccessTokenValidator(); app.UseAuthentication(); - app.UseRabbitMq(); + app.UseRabbitMQ(); app.UseMiddleware(); app.UseMiddleware(); app.UseRouting(); diff --git a/src/apps/api-gateway/Genocs.APIGateway/appsettings.development.json b/src/apps/api-gateway/Genocs.APIGateway/appsettings.development.json deleted file mode 100644 index 12ee80a7..00000000 --- a/src/apps/api-gateway/Genocs.APIGateway/appsettings.development.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "logger": { - "level": "information", - "file": { - "enabled": true - }, - "seq": { - "enabled": true - } - }, - "jaeger": { - "enabled": true - }, - "prometheus": { - "enabled": false - }, - "vault": { - "enabled": false, - "kv": { - "enabled": false - }, - "pki": { - "enabled": false - }, - "lease": { - "mongo": { - "enabled": false - } - } - } -} \ No newline at end of file diff --git a/src/apps/api-gateway/Genocs.APIGateway/appsettings.json b/src/apps/api-gateway/Genocs.APIGateway/appsettings.json index fc009e6c..4b117e2c 100644 --- a/src/apps/api-gateway/Genocs.APIGateway/appsettings.json +++ b/src/apps/api-gateway/Genocs.APIGateway/appsettings.json @@ -7,28 +7,41 @@ "displayBanner": true, "displayVersion": true }, - "jaeger": { + "consul": { "enabled": true, - "serviceName": "api-gateway", - "udpHost": "localhost", - "maxPacketSize": 65000 + "url": "http://localhost:8500", + "service": "api-gateway", + "address": "docker.for.mac.localhost", + "port": "5501", + "pingEnabled": true, + "pingEndpoint": "healthz", + "pingInterval": 3, + "removeAfterInterval": 3, + "requestRetries": 3 }, - "jwt": { - "certificate": { - "location": "certs/localhost.cer" + "fabio": { + "enabled": true, + "url": "http://localhost:9999", + "service": "api-gateway", + "requestRetries": 3 + }, + "httpClient": { + "type": "", + "retries": 3, + "services": { }, - "issuer": "genocs-identity-service", - "validIssuer": "genocs-identity-service", - "validateAudience": false, - "validateIssuer": true, - "validateLifetime": true, - "expiry": "01:00:00" + "requestMasking": { + "enabled": true, + "maskTemplate": "*****" + }, + "correlationIdHeader": "x-correlation-id" }, "logger": { "level": "debug", "excludePaths": [ "/", - "/ping", + "/healthz", + "/alive", "/metrics" ], "excludeProperties": [ @@ -48,6 +61,10 @@ "console": { "enabled": true }, + "azure": { + "enabled": true, + "connectionString": "InstrumentationKey=1496274b-bda7-4ac6-88ab-9f73b4d3c7b8;IngestionEndpoint=https://italynorth-0.in.applicationinsights.azure.com/;LiveEndpoint=https://italynorth.livediagnostics.monitor.azure.com/;ApplicationId=c417f66d-3611-48a2-80fe-5a6d302bed4f" + }, "elk": { "enabled": false, "url": "http://localhost:9200" @@ -64,34 +81,72 @@ }, "tags": {} }, - "messaging": { + "jaeger": { "enabled": true, - "endpoints": [ - { - "method": "post", - "path": "stories-service/stories/async", - "exchange": "stories", - "routingKey": "send_story" - }, - { - "method": "post", - "path": "stories-service/stories/{storyId}/rate/async", - "exchange": "stories", - "routingKey": "rate_story" - } - ] + "serviceName": "api-gateway", + "endpoint": "http://localhost:4317", + "protocol": "Grpc", + "processorType": "Batch", + "maxQueueSize": 2048, + "scheduledDelayMilliseconds": 5000, + "exporterTimeoutMilliseconds": 30000, + "maxExportBatchSize": 512 + }, + "jwt": { + "enabled": true, + "allowAnonymousEndpoints": [], + "certificate": { + "location": "certs/localhost.cer", + "password": "test", + "rawData": "" + }, + "expiryMinutes": 30, + "issuer": "genocs-identity-service", + "validIssuer": "genocs-identity-service", + "validateAudience": false, + "validateIssuer": true, + "validateLifetime": true, + "expiry": "01:00:00" + }, + "metrics": { + "enabled": true, + "influxEnabled": false, + "prometheusEnabled": false, + "prometheusFormatter": null, + "influxUrl": "http://localhost:8086", + "database": "test", + "env": "local", + "interval": 5 + }, + "mongodb": { + "connectionString": "mongodb://localhost:27017", + "database": "api-gateway", + "seed": false, + "enableTracing": true }, "prometheus": { "enabled": false, "endpoint": "/metrics" }, + "outbox": { + "enabled": true, + "type": "sequential", + "expiry": 3600, + "intervalMilliseconds": 2000, + "inboxCollection": "inbox", + "outboxCollection": "outbox", + "disableTransactions": true + }, "rabbitMq": { "connectionName": "api-gateway", + "messagesPersisted": true, "retries": 3, "retryInterval": 2, "conventionsCasing": "snakeCase", "logger": { - "enabled": true + "enabled": true, + "logConnectionStatus": true, + "logMessagePayload": true }, "username": "guest", "password": "guest", @@ -120,13 +175,66 @@ "durable": true, "exclusive": false, "autoDelete": false, - "template": "api-gateway/{{exchange}}.{{message}}" + "template": "{{assembly}}/{{exchange}}.{{message}}" }, "context": { "enabled": true, "header": "message_context" }, - "spanContextHeader": "span_context" + "spanContextHeader": "span_context", + "deadLetter": { + "enabled": true, + "prefix": "dlx-", + "declare": true + }, + "maxProducerChannels": 1000 + }, + "elk": { + "enabled": false, + "url": "http://localhost:9200", + "indexFormat": "signalr-service-{0:yyyy.MM.dd}", + "basicAuthEnabled": false, + "username": "user", + "password": "secret" + }, + "redis": { + "connectionString": "localhost", + "instance": "api-gateway:", + "database": 0 + }, + "restEase": { + "loadBalancer": "", + "services": [] + }, + "swagger": { + "enabled": true, + "reDocEnabled": false, + "name": "Gateway", + "title": "API Gateway", + "version": "v01", + "description": "API Gateway Service", + "routePrefix": "swagger", + "includeSecurity": true, + "contactName": "Giovanni Nocco", + "contactEmail": "giovanni.nocco@genocs.com", + "contactUrl": "https://www.genocs.com", + "licenseName": "MIT", + "licenseUrl": "https://www.genocs.com/license.html", + "termsOfService": "https://www.genocs.com/terms_and_conditions.html", + "serializeAsOpenApiV2": true, + "servers": [ + { + "url": "http://localhost:5501", + "description": "Local version to be used for development" + } + ] + }, + "security": { + "certificate": { + "enabled": false, + "header": "Certificate", + "allowedHosts": [ "localhost", "identity" ] + } }, "reverseProxy": { "routes": { @@ -179,28 +287,28 @@ "identity-cluster": { "destinations": { "destination1": { - "address": "https://localhost:5011" + "address": "https://localhost:5510" } } }, "products-cluster": { "destinations": { "destination1": { - "address": "http://localhost:5002" + "address": "https://localhost:5520" } } }, "orders-cluster": { "destinations": { "destination1": { - "address": "http://localhost:5003" + "address": "https://localhost:5530" } } }, "signalr-cluster": { "destinations": { "destination1": { - "address": "http://localhost:5004" + "address": "https://localhost:5540" } } } @@ -214,13 +322,13 @@ "username": "user", "password": "secret", "kv": { - "enabled": true, + "enabled": false, "engineVersion": 2, "mountPoint": "kv", "path": "api-gateway/settings" }, "pki": { - "enabled": true, + "enabled": false, "roleName": "api-gateway", "commonName": "api-gateway.demo.io" }, @@ -228,7 +336,7 @@ "mongo": { "type": "database", "roleName": "api-gateway", - "enabled": true, + "enabled": false, "autoRenewal": true, "templates": { "connectionString": "mongodb://{{username}}:{{password}}@localhost:27017" diff --git a/src/apps/apigateway.dockerfile b/src/apps/apigateway.dockerfile index fcc5007e..3a2ae1de 100644 --- a/src/apps/apigateway.dockerfile +++ b/src/apps/apigateway.dockerfile @@ -1,11 +1,11 @@ #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build-env WORKDIR /src COPY ["api-gateway/Genocs.APIGateway", "Genocs.APIGateway/"] diff --git a/src/apps/docker-compose.override.yml b/src/apps/docker-compose.override.yml index a0517f95..d0f46c92 100644 --- a/src/apps/docker-compose.override.yml +++ b/src/apps/docker-compose.override.yml @@ -1,5 +1,3 @@ -version: '3.9' - services: api-gateway: build: diff --git a/src/apps/docker-compose.yml b/src/apps/docker-compose.yml index 8b03d97d..20ee5733 100644 --- a/src/apps/docker-compose.yml +++ b/src/apps/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.9' - services: api-gateway: image: genocs/apigateway:${IMAGE_VERSION} @@ -22,7 +20,7 @@ services: environment: - ASPNETCORE_ENVIRONMENT=Docker ports: - - 5501:80 + - 5500:80 networks: - genocs # network_mode: bridge @@ -36,7 +34,7 @@ services: environment: - ASPNETCORE_ENVIRONMENT=Docker ports: - - 5502:80 + - 5510:80 #ports: networks: - genocs @@ -51,7 +49,7 @@ services: environment: - ASPNETCORE_ENVIRONMENT=Docker ports: - - 5503:80 + - 5530:80 #ports: networks: - genocs @@ -66,7 +64,7 @@ services: environment: - ASPNETCORE_ENVIRONMENT=Docker ports: - - 5504:80 + - 5540:80 #ports: networks: - genocs diff --git a/src/apps/identity-webapi.dockerfile b/src/apps/identity-webapi.dockerfile index 6ea34df3..b3c74a00 100644 --- a/src/apps/identity-webapi.dockerfile +++ b/src/apps/identity-webapi.dockerfile @@ -1,11 +1,11 @@ #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build-env WORKDIR /src COPY ["identity/Genocs.Identities.WebApi", "Genocs.Identities.WebApi/"] COPY ["identity/Genocs.Identities.Application", "Genocs.Identities.Application/"] diff --git a/src/apps/identity/Genocs.Identities.Application/Commands/CreateUser.cs b/src/apps/identity/Genocs.Identities.Application/Commands/CreateUser.cs index 39b6033d..aaa65e6c 100644 --- a/src/apps/identity/Genocs.Identities.Application/Commands/CreateUser.cs +++ b/src/apps/identity/Genocs.Identities.Application/Commands/CreateUser.cs @@ -11,8 +11,13 @@ public class CreateUser : ICommand public string Role { get; } public IEnumerable Permissions { get; } - public CreateUser(Guid userId, string email, string name, string password, string role, - IEnumerable permissions) + public CreateUser( + Guid userId, + string email, + string name, + string password, + string role, + IEnumerable permissions) { UserId = userId == Guid.Empty ? Guid.NewGuid() : userId; Email = email; diff --git a/src/apps/identity/Genocs.Identities.Application/Decorators/LoggingCommandHandlerDecorator.cs b/src/apps/identity/Genocs.Identities.Application/Decorators/LoggingCommandHandlerDecorator.cs index d639f66b..104a5e30 100644 --- a/src/apps/identity/Genocs.Identities.Application/Decorators/LoggingCommandHandlerDecorator.cs +++ b/src/apps/identity/Genocs.Identities.Application/Decorators/LoggingCommandHandlerDecorator.cs @@ -15,8 +15,10 @@ internal sealed class LoggingCommandHandlerDecorator : ICommandHandler private readonly ICorrelationIdFactory _correlationIdFactory; private readonly ILogger> _logger; - public LoggingCommandHandlerDecorator(ICommandHandler handler, - ICorrelationIdFactory correlationIdFactory, ILogger> logger) + public LoggingCommandHandlerDecorator( + ICommandHandler handler, + ICorrelationIdFactory correlationIdFactory, + ILogger> logger) { _handler = handler; _correlationIdFactory = correlationIdFactory; @@ -25,10 +27,10 @@ public LoggingCommandHandlerDecorator(ICommandHandler handler, public async Task HandleAsync(TCommand command, CancellationToken cancellationToken = default) { - var correlationId = _correlationIdFactory.Create(); + string? correlationId = _correlationIdFactory.Create(); using (LogContext.PushProperty("CorrelationId", correlationId)) { - var name = command.GetType().Name.Underscore(); + string? name = command.GetType().Name.Underscore(); _logger.LogInformation($"Handling a command: '{name}'..."); await _handler.HandleAsync(command); } diff --git a/src/apps/identity/Genocs.Identities.Application/Decorators/LoggingEventHandlerDecorator.cs b/src/apps/identity/Genocs.Identities.Application/Decorators/LoggingEventHandlerDecorator.cs index daf00909..91ab62d0 100644 --- a/src/apps/identity/Genocs.Identities.Application/Decorators/LoggingEventHandlerDecorator.cs +++ b/src/apps/identity/Genocs.Identities.Application/Decorators/LoggingEventHandlerDecorator.cs @@ -15,8 +15,10 @@ internal sealed class LoggingEventHandlerDecorator : IEventHandler> _logger; - public LoggingEventHandlerDecorator(IEventHandler handler, ICorrelationIdFactory correlationIdFactory, - ILogger> logger) + public LoggingEventHandlerDecorator( + IEventHandler handler, + ICorrelationIdFactory correlationIdFactory, + ILogger> logger) { _handler = handler; _correlationIdFactory = correlationIdFactory; @@ -25,10 +27,10 @@ public LoggingEventHandlerDecorator(IEventHandler handler, ICorrelationI public async Task HandleAsync(TEvent @event, CancellationToken cancellationToken = default) { - var correlationId = _correlationIdFactory.Create(); + string? correlationId = _correlationIdFactory.Create(); using (LogContext.PushProperty("CorrelationId", correlationId)) { - var name = @event.GetType().Name.Underscore(); + string? name = @event.GetType().Name.Underscore(); _logger.LogInformation($"Handling an event: '{name}'..."); await _handler.HandleAsync(@event); } diff --git a/src/apps/identity/Genocs.Identities.Application/Decorators/OutboxCommandHandlerDecorator.cs b/src/apps/identity/Genocs.Identities.Application/Decorators/OutboxCommandHandlerDecorator.cs index 5401d00c..c50312be 100644 --- a/src/apps/identity/Genocs.Identities.Application/Decorators/OutboxCommandHandlerDecorator.cs +++ b/src/apps/identity/Genocs.Identities.Application/Decorators/OutboxCommandHandlerDecorator.cs @@ -15,8 +15,11 @@ internal sealed class OutboxCommandHandlerDecorator : ICommandHandler< private readonly string _messageId; private readonly bool _enabled; - public OutboxCommandHandlerDecorator(ICommandHandler handler, IMessageOutbox outbox, - OutboxOptions outboxOptions, IMessagePropertiesAccessor messagePropertiesAccessor) + public OutboxCommandHandlerDecorator( + ICommandHandler handler, + IMessageOutbox outbox, + OutboxOptions outboxOptions, + IMessagePropertiesAccessor messagePropertiesAccessor) { _handler = handler; _outbox = outbox; @@ -24,8 +27,8 @@ public OutboxCommandHandlerDecorator(ICommandHandler handler, IMessage var messageProperties = messagePropertiesAccessor.MessageProperties; _messageId = string.IsNullOrWhiteSpace(messageProperties?.MessageId) - ? Guid.NewGuid().ToString("N") - : messageProperties.MessageId; + ? Guid.NewGuid().ToString("N") + : messageProperties.MessageId; } public Task HandleAsync(TCommand command, CancellationToken cancellationToken = default) diff --git a/src/apps/identity/Genocs.Identities.Application/Decorators/OutboxEventHandlerDecorator.cs b/src/apps/identity/Genocs.Identities.Application/Decorators/OutboxEventHandlerDecorator.cs index 0bad3e59..92b702c6 100644 --- a/src/apps/identity/Genocs.Identities.Application/Decorators/OutboxEventHandlerDecorator.cs +++ b/src/apps/identity/Genocs.Identities.Application/Decorators/OutboxEventHandlerDecorator.cs @@ -15,8 +15,11 @@ internal sealed class OutboxEventHandlerDecorator : IEventHandler handler, IMessageOutbox outbox, - OutboxOptions outboxOptions, IMessagePropertiesAccessor messagePropertiesAccessor) + public OutboxEventHandlerDecorator( + IEventHandler handler, + IMessageOutbox outbox, + OutboxOptions outboxOptions, + IMessagePropertiesAccessor messagePropertiesAccessor) { _handler = handler; _outbox = outbox; diff --git a/src/apps/identity/Genocs.Identities.Application/Extensions.cs b/src/apps/identity/Genocs.Identities.Application/Extensions.cs index 1fe24b00..660697cc 100644 --- a/src/apps/identity/Genocs.Identities.Application/Extensions.cs +++ b/src/apps/identity/Genocs.Identities.Application/Extensions.cs @@ -1,3 +1,4 @@ +using System.Text; using Genocs.Auth; using Genocs.Common.Configurations; using Genocs.Core.Builders; @@ -23,7 +24,6 @@ using Genocs.Persistence.MongoDb.Extensions; using Genocs.Persistence.Redis; using Genocs.Tracing; -using Genocs.Tracing.Jaeger; using Genocs.WebApi; using Genocs.WebApi.CQRS; using Genocs.WebApi.Swagger; @@ -33,13 +33,12 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; -using System.Text; namespace Genocs.Identities.Application; public static class Extensions { - public static IGenocsBuilder AddCore(this IGenocsBuilder builder) + public static async Task AddCoreAsync(this IGenocsBuilder builder) { builder.Services .AddScoped() @@ -62,12 +61,15 @@ public static IGenocsBuilder AddCore(this IGenocsBuilder builder) .AddInMemoryEventDispatcher() .AddInMemoryQueryDispatcher() .AddJwt() - .AddHttpClient() - .AddRabbitMq() + .AddHttpClient(); + + await builder.AddRabbitMQAsync(); + + builder + .AddOpenTelemetry() .AddMessageOutbox(o => o.AddMongo()) .AddMongo() .AddRedis() - .AddOpenTelemetry() .AddMetrics() .AddMongoRepository("refreshTokens") .AddMongoRepository("users") @@ -98,7 +100,7 @@ public static IApplicationBuilder UseCore(this IApplicationBuilder app) .UsePublicContracts() .UseAuthentication() .UseMetrics() - .UseRabbitMq() + .UseRabbitMQ() .SubscribeCommand(); return app; diff --git a/src/apps/identity/Genocs.Identities.Application/Genocs.Identities.Application.csproj b/src/apps/identity/Genocs.Identities.Application/Genocs.Identities.Application.csproj index 4e3c8dca..95c70587 100644 --- a/src/apps/identity/Genocs.Identities.Application/Genocs.Identities.Application.csproj +++ b/src/apps/identity/Genocs.Identities.Application/Genocs.Identities.Application.csproj @@ -8,6 +8,7 @@ + @@ -20,16 +21,17 @@ - - - - - - - - - - + + + + + + + + + + + diff --git a/src/apps/identity/Genocs.Identities.WebApi/Genocs.Identities.WebApi.csproj b/src/apps/identity/Genocs.Identities.WebApi/Genocs.Identities.WebApi.csproj index 99432ecb..2547ab54 100644 --- a/src/apps/identity/Genocs.Identities.WebApi/Genocs.Identities.WebApi.csproj +++ b/src/apps/identity/Genocs.Identities.WebApi/Genocs.Identities.WebApi.csproj @@ -10,6 +10,7 @@ + diff --git a/src/apps/identity/Genocs.Identities.WebApi/Program.cs b/src/apps/identity/Genocs.Identities.WebApi/Program.cs index c6b2994c..37e23570 100644 --- a/src/apps/identity/Genocs.Identities.WebApi/Program.cs +++ b/src/apps/identity/Genocs.Identities.WebApi/Program.cs @@ -4,11 +4,13 @@ using Genocs.Identities.Application.DTO; using Genocs.Identities.Application.Queries; using Genocs.Identities.Application.Services; +using Genocs.LoadBalancing.Fabio; using Genocs.Logging; using Genocs.Secrets.Vault; using Genocs.WebApi; using Genocs.WebApi.CQRS; using Serilog; +using Genocs.Discovery.Consul; StaticLogger.EnsureInitialized(); @@ -18,24 +20,21 @@ .UseLogging() .UseVault(); -var services = builder.Services; - -builder.Logging.AddOpenTelemetry(logging => -{ - logging.IncludeFormattedMessage = true; - logging.IncludeScopes = true; -}); - -services.AddGenocs(builder.Configuration) - .AddWebApi() - .AddCore() - .Build(); +IGenocsBuilder gnxBuilder = await builder + .AddGenocs() + .AddWebApi() + .AddConsul() + .AddFabio() + .AddCoreAsync(); +gnxBuilder.Build(); var app = builder.Build(); +app.MapDefaultEndpoints(); + app.UseCore(); + app.UseDispatcherEndpoints(endpoints => endpoints - .Get(string.Empty, ctx => ctx.GetAppName()) .Post("sign-in", afterDispatch: (cmd, ctx) => { var auth = ctx.RequestServices.GetRequiredService().Get(cmd.Id); diff --git a/src/apps/identity/Genocs.Identities.WebApi/Properties/launchSettings.json b/src/apps/identity/Genocs.Identities.WebApi/Properties/launchSettings.json index f207a302..e1d97584 100644 --- a/src/apps/identity/Genocs.Identities.WebApi/Properties/launchSettings.json +++ b/src/apps/identity/Genocs.Identities.WebApi/Properties/launchSettings.json @@ -1,27 +1,12 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:61699/", - "sslPort": 44323 - } - }, "profiles": { - "Genocs.Core.Demo.Users.WebApi": { + "Local": { "commandName": "Project", "launchBrowser": true, + "applicationUrl": "https://localhost:5510;http://localhost:5511", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - }, - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "applicationUrl": "https://localhost:5011;http://localhost:5001" + } } } } \ No newline at end of file diff --git a/src/apps/identity/Genocs.Identities.WebApi/appsettings.Development.json b/src/apps/identity/Genocs.Identities.WebApi/appsettings.Development.json deleted file mode 100644 index 2c63c085..00000000 --- a/src/apps/identity/Genocs.Identities.WebApi/appsettings.Development.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/src/apps/identity/Genocs.Identities.WebApi/appsettings.json b/src/apps/identity/Genocs.Identities.WebApi/appsettings.json index e08e5fc8..0f06a4c6 100644 --- a/src/apps/identity/Genocs.Identities.WebApi/appsettings.json +++ b/src/apps/identity/Genocs.Identities.WebApi/appsettings.json @@ -1,22 +1,4 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Information", - "Microsoft": "Information", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "AllowedHosts": "*", - "mongodb": { - "connectionString": "mongodb://localhost:27017", - "database": "genocs-identity-service", - "seed": false, - "enableTracing": true - }, - "Monitoring": { - "Jaeger": "localhost" - }, "app": { "name": "Identity Service", "service": "identity-service", @@ -26,25 +8,27 @@ "displayVersion": true }, "consul": { - "enabled": false, + "enabled": true, "url": "http://localhost:8500", "service": "identity-service", - "address": "docker.for.win.localhost", - "port": "5070", + "address": "docker.for.mac.localhost", + "port": "5511", "pingEnabled": true, - "pingEndpoint": "ping", + "pingEndpoint": "healthz", "pingInterval": 3, "removeAfterInterval": 3 }, "fabio": { - "enabled": false, + "enabled": true, "url": "http://localhost:9999", - "service": "identity-service" + "service": "identity-service", + "requestRetries": 3 }, "httpClient": { "type": "fabio", "retries": 3, - "services": {}, + "services": { + }, "requestMasking": { "enabled": true, "maskTemplate": "*****" @@ -52,10 +36,11 @@ "correlationIdHeader": "x-correlation-id" }, "logger": { - "level": "information", + "level": "debug", "excludePaths": [ "/", - "/ping", + "/healthz", + "/alive", "/metrics" ], "excludeProperties": [ @@ -73,7 +58,11 @@ "Token" ], "console": { - "enabled": false + "enabled": true + }, + "azure": { + "enabled": false, + "connectionString": "" }, "elk": { "enabled": false, @@ -85,26 +74,23 @@ "interval": "day" }, "seq": { - "enabled": false, + "enabled": true, "url": "http://localhost:5341", "apiKey": "secret" }, - "azure": { - "enabled": false, - "connectionString": "" - }, "tags": {} }, "jaeger": { "enabled": true, - "serviceName": "identity-service", + "serviceName": "identity", "udpHost": "localhost", "udpPort": 6831, "maxPacketSize": 65000, "sampler": "const", "excludePaths": [ "/", - "/ping", + "/healthz", + "/alive", "/metrics" ] }, @@ -125,11 +111,18 @@ "enabled": true, "influxEnabled": false, "prometheusEnabled": false, + "prometheusFormatter": null, "influxUrl": "http://localhost:8086", "database": "test", "env": "local", "interval": 5 }, + "mongodb": { + "connectionString": "mongodb://localhost:27017", + "database": "identities", + "seed": false, + "enableTracing": true + }, "prometheus": { "enabled": false, "endpoint": "/metrics" @@ -145,11 +138,14 @@ }, "rabbitMq": { "connectionName": "identity-service", + "messagesPersisted": true, "retries": 3, "retryInterval": 2, "conventionsCasing": "snakeCase", "logger": { - "enabled": true + "enabled": true, + "logConnectionStatus": true, + "logMessagePayload": true }, "username": "guest", "password": "guest", @@ -171,38 +167,46 @@ "durable": true, "autoDelete": false, "type": "topic", - "name": "identity" + "name": "identities" }, "queue": { "declare": true, "durable": true, "exclusive": false, "autoDelete": false, - "template": "identity-service/{{exchange}}.{{message}}" + "template": "{{assembly}}/{{exchange}}.{{message}}" }, "context": { "enabled": true, "header": "message_context" }, - "spanContextHeader": "span_context" + "spanContextHeader": "span_context", + "deadLetter": { + "enabled": true, + "prefix": "dlx-", + "declare": true + }, + "maxProducerChannels": 1000 }, "redis": { "connectionString": "localhost", - "instance": "identity-service:", + "instance": "identity:", "database": 0 }, "swagger": { "enabled": true, "reDocEnabled": false, "name": "v1", - "title": "API", + "title": "Identities", "version": "v1", "routePrefix": "swagger", "includeSecurity": true }, "security": { "certificate": { - "header": "Certificate" + "enabled": false, + "header": "Certificate", + "allowedHosts": [ "localhost", "identity" ] } }, "vault": { @@ -213,13 +217,13 @@ "username": "user", "password": "secret", "kv": { - "enabled": true, + "enabled": false, "engineVersion": 2, "mountPoint": "kv", "path": "identity-service/settings" }, "pki": { - "enabled": true, + "enabled": false, "roleName": "identity-service", "commonName": "identity-service.demo.io" }, @@ -234,5 +238,8 @@ } } } + }, + "webApi": { + "bindRequestFromRoute": true } } \ No newline at end of file diff --git a/src/apps/order-webapi.dockerfile b/src/apps/order-webapi.dockerfile index c0554e39..ad956d91 100644 --- a/src/apps/order-webapi.dockerfile +++ b/src/apps/order-webapi.dockerfile @@ -1,11 +1,11 @@ #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build-env WORKDIR /src COPY ["orders/Genocs.Orders.WebApi", "Genocs.Orders.WebApi/"] diff --git a/src/apps/orders/Genocs.Orders.WebApi/Controllers/OrdersController.cs b/src/apps/orders/Genocs.Orders.WebApi/Controllers/OrdersController.cs index f940a9b3..fc1cca32 100644 --- a/src/apps/orders/Genocs.Orders.WebApi/Controllers/OrdersController.cs +++ b/src/apps/orders/Genocs.Orders.WebApi/Controllers/OrdersController.cs @@ -24,12 +24,7 @@ public OrdersController(ICommandDispatcher commandDispatcher, IQueryDispatcher q public async Task> Get([FromRoute] GetOrder query) { var order = await _queryDispatcher.QueryAsync(query); - if (order is null) - { - return NotFound(); - } - - return order; + return order is null ? (ActionResult)NotFound() : (ActionResult)order; } [HttpPost] diff --git a/src/apps/orders/Genocs.Orders.WebApi/Genocs.Orders.WebApi.csproj b/src/apps/orders/Genocs.Orders.WebApi/Genocs.Orders.WebApi.csproj index f161c38d..2481452e 100644 --- a/src/apps/orders/Genocs.Orders.WebApi/Genocs.Orders.WebApi.csproj +++ b/src/apps/orders/Genocs.Orders.WebApi/Genocs.Orders.WebApi.csproj @@ -29,22 +29,22 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/src/apps/orders/Genocs.Orders.WebApi/Program.cs b/src/apps/orders/Genocs.Orders.WebApi/Program.cs index bc5ed90f..c74adb39 100644 --- a/src/apps/orders/Genocs.Orders.WebApi/Program.cs +++ b/src/apps/orders/Genocs.Orders.WebApi/Program.cs @@ -37,35 +37,29 @@ .UseLogging() .UseVault(); -builder.Logging.AddOpenTelemetry(logging => -{ - logging.IncludeFormattedMessage = true; - logging.IncludeScopes = true; -}); +IGenocsBuilder gnxBuilder = await builder + .AddGenocs() + .AddErrorHandler() + .AddServices() + .AddHttpClient() + .AddCorrelationContextLogging() + .AddConsul() + .AddFabio() + .AddOpenTelemetry() + .AddMetrics() + .AddMongo() + .AddMongoRepository("orders") + .AddCommandHandlers() + .AddEventHandlers() + .AddQueryHandlers() + .AddInMemoryCommandDispatcher() + .AddInMemoryEventDispatcher() + .AddInMemoryQueryDispatcher() + .AddPrometheus() + .AddRedis() + .AddRabbitMQAsync(); -var services = builder.Services; - -services.AddGenocs() - .AddErrorHandler() - .AddServices() - .AddHttpClient() - .AddCorrelationContextLogging() - .AddConsul() - .AddFabio() - .AddOpenTelemetry() - .AddMetrics() - .AddMongo() - .AddMongoRepository("orders") - .AddCommandHandlers() - .AddEventHandlers() - .AddQueryHandlers() - .AddInMemoryCommandDispatcher() - .AddInMemoryEventDispatcher() - .AddInMemoryQueryDispatcher() - .AddPrometheus() - .AddRedis() - .AddRabbitMq() - .AddMessageOutbox(o => o.AddMongo()) +gnxBuilder.AddMessageOutbox(o => o.AddMongo()) .AddWebApi() .AddSwaggerDocs() .AddWebApiSwaggerDocs() @@ -81,14 +75,14 @@ .UseCertificateAuthentication() .UseEndpoints(r => r.MapControllers()) .UseDispatcherEndpoints(endpoints => endpoints - .Get(string.Empty, ctx => ctx.Response.WriteAsync("Orders Service")) - .Get("ping", ctx => ctx.Response.WriteAsync("pong")) .Get("orders/{orderId}") - .Post("orders", afterDispatch: (cmd, ctx) => ctx.Response.Created($"orders/{cmd.OrderId}"))) + .Post("orders", afterDispatch: (cmd, ctx) => ctx.Response.Created($"orders/{cmd.OrderId}"))) .UseSwaggerDocs() - .UseRabbitMq() + .UseRabbitMQ() .SubscribeEvent(); +app.MapDefaultEndpoints(); + app.Run(); Log.CloseAndFlush(); \ No newline at end of file diff --git a/src/apps/orders/Genocs.Orders.WebApi/Properties/launchSettings.json b/src/apps/orders/Genocs.Orders.WebApi/Properties/launchSettings.json index 32efa418..24d9a114 100644 --- a/src/apps/orders/Genocs.Orders.WebApi/Properties/launchSettings.json +++ b/src/apps/orders/Genocs.Orders.WebApi/Properties/launchSettings.json @@ -1,26 +1,12 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:5003;https://localhost:5013" - } - }, "profiles": { - "Genocs.Services.Orders": { + "Local": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5003;https://localhost:5013", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "development" - } - }, - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, + "applicationUrl": "https://localhost:5530;http://localhost:5531", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "development" } } } -} \ No newline at end of file +} diff --git a/src/apps/orders/Genocs.Orders.WebApi/Services/ProductServiceClient.cs b/src/apps/orders/Genocs.Orders.WebApi/Services/ProductServiceClient.cs index 4530716a..c2754e4b 100644 --- a/src/apps/orders/Genocs.Orders.WebApi/Services/ProductServiceClient.cs +++ b/src/apps/orders/Genocs.Orders.WebApi/Services/ProductServiceClient.cs @@ -32,21 +32,11 @@ public ProductServiceClient( { _client = client ?? throw new ArgumentNullException(nameof(client)); + ArgumentNullException.ThrowIfNull(httpClientOptions); - if (httpClientOptions is null) - { - throw new ArgumentNullException(nameof(httpClientOptions)); - } + ArgumentNullException.ThrowIfNull(vaultOptions); - if (vaultOptions is null) - { - throw new ArgumentNullException(nameof(vaultOptions)); - } - - if (securityOptions is null) - { - throw new ArgumentNullException(nameof(securityOptions)); - } + ArgumentNullException.ThrowIfNull(securityOptions); string? url = httpClientOptions?.Services?["products"]; diff --git a/src/apps/orders/Genocs.Orders.WebApi/appsettings.json b/src/apps/orders/Genocs.Orders.WebApi/appsettings.json index 36916f8e..a2ad9a9e 100644 --- a/src/apps/orders/Genocs.Orders.WebApi/appsettings.json +++ b/src/apps/orders/Genocs.Orders.WebApi/appsettings.json @@ -8,34 +8,67 @@ "displayVersion": true }, "consul": { - "enabled": false, + "enabled": true, "url": "http://localhost:8500", "service": "orders-service", - "address": "docker.for.win.localhost", - "port": "5002", + "address": "docker.for.mac.localhost", + "port": "5531", "pingEnabled": true, - "pingEndpoint": "ping", + "pingEndpoint": "healthz", "pingInterval": 3, - "removeAfterInterval": 3 + "removeAfterInterval": 3, + "requestRetries": 3 }, "fabio": { - "enabled": false, + "enabled": true, "url": "http://localhost:9999", - "service": "orders-service" + "service": "orders-service", + "requestRetries": 3 }, "httpClient": { "type": "", - "retries": 2, + "retries": 3, "services": { - "products": "localhost:5002" - } + "products": "https://localhost:5520" + }, + "requestMasking": { + "enabled": true, + "maskTemplate": "*****" + }, + "correlationIdHeader": "x-correlation-id" }, "logger": { - "applicationName": "orders-service", - "excludePaths": [ "/ping", "/metrics" ], - "level": "information", + "level": "debug", + "excludePaths": [ + "/", + "/healthz", + "/alive", + "/metrics" + ], + "excludeProperties": [ + "api_key", + "access_key", + "ApiKey", + "ApiSecret", + "ClientId", + "ClientSecret", + "ConnectionString", + "Password", + "Email", + "Login", + "Secret", + "Token" + ], "console": { - "enabled": false + "enabled": true + }, + "azure": { + "enabled": false, + "connectionString": "" + }, + "elk": { + "enabled": false, + "url": "http://localhost:9200" }, "file": { "enabled": true, @@ -45,8 +78,9 @@ "seq": { "enabled": true, "url": "http://localhost:5341", - "token": "secret" - } + "apiKey": "secret" + }, + "tags": {} }, "jaeger": { "enabled": true, @@ -59,6 +93,22 @@ "exporterTimeoutMilliseconds": 30000, "maxExportBatchSize": 512 }, + "jwt": { + "enabled": true, + "allowAnonymousEndpoints": [], + "certificate": { + "location": "certs/localhost.pfx", + "password": "test", + "rawData": "" + }, + "expiryMinutes": 30, + "issuer": "genocs-identity-service", + "validIssuer": "genocs-identity-service", + "validateAudience": false, + "validateIssuer": true, + "validateLifetime": true, + "expiry": "01:00:00" + }, "metrics": { "enabled": true, "influxEnabled": false, @@ -76,7 +126,17 @@ "enableTracing": true }, "prometheus": { - "enabled": false + "enabled": false, + "endpoint": "/metrics" + }, + "outbox": { + "enabled": true, + "type": "sequential", + "expiry": 3600, + "intervalMilliseconds": 2000, + "inboxCollection": "inbox", + "outboxCollection": "outbox", + "disableTransactions": true }, "rabbitMq": { "connectionName": "orders-service", @@ -130,50 +190,55 @@ }, "maxProducerChannels": 1000 }, + "elk": { + "enabled": false, + "url": "http://localhost:9200", + "indexFormat": "signalr-service-{0:yyyy.MM.dd}", + "basicAuthEnabled": false, + "username": "user", + "password": "secret" + }, + "redis": { + "connectionString": "localhost", + "instance": "orders:", + "database": 0 + }, + "restEase": { + "loadBalancer": "", + "services": [] + }, "swagger": { "enabled": true, "reDocEnabled": false, "name": "Orders", "title": "Orders Service", - "version": "v002", + "version": "v01", "description": "Orders Service", "routePrefix": "swagger", + "includeSecurity": true, "contactName": "Giovanni Nocco", "contactEmail": "giovanni.nocco@genocs.com", "contactUrl": "https://www.genocs.com", "licenseName": "MIT", "licenseUrl": "https://www.genocs.com/license.html", "termsOfService": "https://www.genocs.com/terms_and_conditions.html", - "includeSecurity": true, "serializeAsOpenApiV2": true, "servers": [ { - "url": "http://localhost:5300", + "url": "http://localhost:5531", "description": "Local version to be used for development" - }, - { - "url": "http://fiscanner-api", - "description": "Containerized version to be used into with docker or k8s" - }, - { - "url": "https://fiscanner-api.azurewebsites.net", - "description": "Production deployed on Azure" } ] }, - "redis": { - "connectionString": "localhost", - "instance": "orders:" - }, "security": { "certificate": { - "enabled": true, + "enabled": false, "header": "Certificate", - "allowedHosts": [ "localhost", "order" ] + "allowedHosts": [ "localhost", "identity" ] } }, "vault": { - "enabled": true, + "enabled": false, "url": "http://localhost:8200", "authType": "token", "token": "secret", @@ -188,7 +253,7 @@ "pki": { "enabled": false, "roleName": "orders-service", - "commonName": "orders-service.convey.io" + "commonName": "orders-service.demo.io" }, "lease": { "mongo": { diff --git a/src/apps/product-webapi.dockerfile b/src/apps/product-webapi.dockerfile index ee7efb2f..0ca2c5f9 100644 --- a/src/apps/product-webapi.dockerfile +++ b/src/apps/product-webapi.dockerfile @@ -1,11 +1,11 @@ #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build-env WORKDIR /src COPY ["products/Genocs.Products.WebApi", "Genocs.Products.WebApi/"] diff --git a/src/apps/products/Genocs.Products.WebApi/Genocs.Products.WebApi.csproj b/src/apps/products/Genocs.Products.WebApi/Genocs.Products.WebApi.csproj index d54c84eb..ce33a868 100644 --- a/src/apps/products/Genocs.Products.WebApi/Genocs.Products.WebApi.csproj +++ b/src/apps/products/Genocs.Products.WebApi/Genocs.Products.WebApi.csproj @@ -28,22 +28,22 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/src/apps/products/Genocs.Products.WebApi/Program.cs b/src/apps/products/Genocs.Products.WebApi/Program.cs index ff5381d3..d3982b3b 100644 --- a/src/apps/products/Genocs.Products.WebApi/Program.cs +++ b/src/apps/products/Genocs.Products.WebApi/Program.cs @@ -35,40 +35,36 @@ .UseLogging() .UseVault(); -var services = builder.Services; +IGenocsBuilder gnxBuilder = await builder + .AddGenocs() + .AddErrorHandler() + .AddServices() + .AddHttpClient() + .AddCorrelationContextLogging() + .AddConsul() + .AddFabio() + .AddOpenTelemetry() + .AddMetrics() + .AddMongo() + .AddMongoRepository("products") + .AddCommandHandlers() + .AddEventHandlers() + .AddQueryHandlers() + .AddInMemoryCommandDispatcher() + .AddInMemoryEventDispatcher() + .AddInMemoryQueryDispatcher() + .AddPrometheus() + .AddRedis() + .AddMessageOutbox(o => o.AddMongo()) + .AddWebApi() + .AddSwaggerDocs() + .AddWebApiSwaggerDocs() + .AddRabbitMQAsync(); -builder.Logging.AddOpenTelemetry(logging => -{ - logging.IncludeFormattedMessage = true; - logging.IncludeScopes = true; -}); - -services.AddGenocs() - .AddErrorHandler() - .AddServices() - .AddHttpClient() - .AddCorrelationContextLogging() - .AddConsul() - .AddFabio() - .AddOpenTelemetry() - .AddMetrics() - .AddMongo() - .AddMongoRepository("products") - .AddCommandHandlers() - .AddEventHandlers() - .AddQueryHandlers() - .AddInMemoryCommandDispatcher() - .AddInMemoryEventDispatcher() - .AddInMemoryQueryDispatcher() - .AddPrometheus() - .AddRedis() - .AddRabbitMq() - .AddMessageOutbox(o => o.AddMongo()) - .AddWebApi() - .AddSwaggerDocs() - .AddWebApiSwaggerDocs() - .Build(); +// Build the Genocs builder +gnxBuilder.Build(); +// Build the Application var app = builder.Build(); app.UseGenocs() @@ -79,13 +75,13 @@ .UseCertificateAuthentication() .UseEndpoints(r => r.MapControllers()) .UseDispatcherEndpoints(endpoints => endpoints - .Get(string.Empty, ctx => ctx.Response.WriteAsync("Products Service")) - .Get("ping", ctx => ctx.Response.WriteAsync("pong")) .Get>("products") .Get("products/{productId}") .Post("products", afterDispatch: (cmd, ctx) => ctx.Response.Created($"products/{cmd.ProductId}"))) .UseSwaggerDocs() - .UseRabbitMq(); + .UseRabbitMQ(); + +app.MapDefaultEndpoints(); app.Run(); diff --git a/src/apps/products/Genocs.Products.WebApi/Properties/launchSettings.json b/src/apps/products/Genocs.Products.WebApi/Properties/launchSettings.json index 579660f2..d6e07839 100644 --- a/src/apps/products/Genocs.Products.WebApi/Properties/launchSettings.json +++ b/src/apps/products/Genocs.Products.WebApi/Properties/launchSettings.json @@ -1,26 +1,12 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:5002;https://localhost:5012" - } - }, "profiles": { - "Genocs.Services.Products": { + "Local": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5002;https://localhost:5012", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "development" - } - }, - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, + "applicationUrl": "https://localhost:5520;http://localhost:5521", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "development" } } } -} \ No newline at end of file +} diff --git a/src/apps/products/Genocs.Products.WebApi/appsettings.json b/src/apps/products/Genocs.Products.WebApi/appsettings.json index b8b59a9f..b27baedf 100644 --- a/src/apps/products/Genocs.Products.WebApi/appsettings.json +++ b/src/apps/products/Genocs.Products.WebApi/appsettings.json @@ -8,35 +8,67 @@ "displayVersion": true }, "consul": { - "enabled": false, + "enabled": true, "url": "http://localhost:8500", "service": "products-service", - "address": "localhost", - "port": "5002", + "address": "docker.for.mac.localhost", + "port": "5521", "pingEnabled": true, - "pingEndpoint": "ping", + "pingEndpoint": "healthz", "pingInterval": 3, - "removeAfterInterval": 3 + "removeAfterInterval": 3, + "requestRetries": 3 }, "fabio": { - "enabled": false, + "enabled": true, "url": "http://localhost:9999", "service": "products-service", "requestRetries": 3 }, "httpClient": { - "type": "", - "retries": 2, + "type": "fabio", + "retries": 3, "services": { - } + }, + "requestMasking": { + "enabled": true, + "maskTemplate": "*****" + }, + "correlationIdHeader": "x-correlation-id" }, "logger": { - "level": "information", - "applicationName": "products-service", - "excludePaths": [ "/ping", "/metrics" ], + "level": "debug", + "excludePaths": [ + "/", + "/healthz", + "/alive", + "/metrics" + ], + "excludeProperties": [ + "api_key", + "access_key", + "ApiKey", + "ApiSecret", + "ClientId", + "ClientSecret", + "ConnectionString", + "Password", + "Email", + "Login", + "Secret", + "Token" + ], "console": { "enabled": true }, + "azure": { + "enabled": false, + "connectionString": "" + }, + "elk": { + "enabled": false, + "url": "http://localhost:9200" + }, "file": { "enabled": true, "path": "logs/logs.txt", @@ -45,17 +77,36 @@ "seq": { "enabled": true, "url": "http://localhost:5341", - "token": "secret" - } + "apiKey": "secret" + }, + "tags": {} }, "jaeger": { "enabled": true, "serviceName": "products", - "udpHost": "localhost", - "udpPort": 6831, - "maxPacketSize": 0, - "sampler": "const", - "excludePaths": [ "/ping", "/metrics" ] + "endpoint": "http://localhost:4317", + "protocol": "Grpc", + "processorType": "Batch", + "maxQueueSize": 2048, + "scheduledDelayMilliseconds": 5000, + "exporterTimeoutMilliseconds": 30000, + "maxExportBatchSize": 512 + }, + "jwt": { + "enabled": true, + "allowAnonymousEndpoints": [], + "certificate": { + "location": "certs/localhost.pfx", + "password": "test", + "rawData": "" + }, + "expiryMinutes": 30, + "issuer": "genocs-identity-service", + "validIssuer": "genocs-identity-service", + "validateAudience": false, + "validateIssuer": true, + "validateLifetime": true, + "expiry": "01:00:00" }, "metrics": { "enabled": true, @@ -69,12 +120,22 @@ }, "mongodb": { "connectionString": "mongodb://localhost:27017", - "database": "products-service", + "database": "products", "seed": false, "enableTracing": true }, "prometheus": { - "enabled": false + "enabled": false, + "endpoint": "/metrics" + }, + "outbox": { + "enabled": true, + "type": "sequential", + "expiry": 3600, + "intervalMilliseconds": 2000, + "inboxCollection": "inbox", + "outboxCollection": "outbox", + "disableTransactions": true }, "rabbitMq": { "connectionName": "products-service", @@ -107,7 +168,7 @@ "durable": true, "autoDelete": false, "type": "topic", - "name": "orders" + "name": "products" }, "queue": { "declare": true, @@ -128,27 +189,55 @@ }, "maxProducerChannels": 1000 }, + "elk": { + "enabled": false, + "url": "http://localhost:9200", + "indexFormat": "signalr-service-{0:yyyy.MM.dd}", + "basicAuthEnabled": false, + "username": "user", + "password": "secret" + }, + "redis": { + "connectionString": "localhost", + "instance": "products:", + "database": 0 + }, + "restEase": { + "loadBalancer": "", + "services": [] + }, "swagger": { "enabled": true, "reDocEnabled": false, - "name": "v1", + "name": "Products", "title": "Products Service", - "version": "v1", - "routePrefix": "swagger" - }, - "redis": { - "connectionString": "localhost", - "instance": "products:" + "version": "v01", + "description": "Product Service", + "routePrefix": "swagger", + "includeSecurity": true, + "contactName": "Giovanni Nocco", + "contactEmail": "giovanni.nocco@genocs.com", + "contactUrl": "https://www.genocs.com", + "licenseName": "MIT", + "licenseUrl": "https://www.genocs.com/license.html", + "termsOfService": "https://www.genocs.com/terms_and_conditions.html", + "serializeAsOpenApiV2": true, + "servers": [ + { + "url": "http://localhost:5521", + "description": "Local version to be used for development" + } + ] }, "security": { "certificate": { - "enabled": true, + "enabled": false, "header": "Certificate", - "allowedHosts": [ "localhost", "product" ] + "allowedHosts": [ "localhost", "identity" ] } }, "vault": { - "enabled": true, + "enabled": false, "url": "http://localhost:8200", "authType": "token", "token": "secret", @@ -163,7 +252,7 @@ "pki": { "enabled": false, "roleName": "products-service", - "commonName": "products-service.convey.io" + "commonName": "products-service.demo.io" }, "lease": { "mongo": { diff --git a/src/apps/signalr-webapi.dockerfile b/src/apps/signalr-webapi.dockerfile index a7dd7061..22706da1 100644 --- a/src/apps/signalr-webapi.dockerfile +++ b/src/apps/signalr-webapi.dockerfile @@ -6,7 +6,8 @@ # FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim # FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine # FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +# FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base WORKDIR /app EXPOSE 80 @@ -17,7 +18,8 @@ EXPOSE 443 # FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS build-env # FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build-env # FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build-env -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +# FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build-env WORKDIR /src COPY ["signalr/Genocs.SignalR.WebApi", "Genocs.SignalR.WebApi/"] diff --git a/src/apps/signalr/Genocs.SignalR.WebApi/Events/NotificationPosted.cs b/src/apps/signalr/Genocs.SignalR.WebApi/Events/NotificationPosted.cs index 78d68fa8..635d01bc 100644 --- a/src/apps/signalr/Genocs.SignalR.WebApi/Events/NotificationPosted.cs +++ b/src/apps/signalr/Genocs.SignalR.WebApi/Events/NotificationPosted.cs @@ -2,7 +2,6 @@ public class NotificationPosted { - public Guid NotificationId { get; } public NotificationPosted(Guid notificationId) diff --git a/src/apps/signalr/Genocs.SignalR.WebApi/Genocs.SignalR.WebApi.csproj b/src/apps/signalr/Genocs.SignalR.WebApi/Genocs.SignalR.WebApi.csproj index cd7c71e7..43408df3 100644 --- a/src/apps/signalr/Genocs.SignalR.WebApi/Genocs.SignalR.WebApi.csproj +++ b/src/apps/signalr/Genocs.SignalR.WebApi/Genocs.SignalR.WebApi.csproj @@ -29,23 +29,23 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/src/apps/signalr/Genocs.SignalR.WebApi/Program.cs b/src/apps/signalr/Genocs.SignalR.WebApi/Program.cs index 816d944c..16f701fc 100644 --- a/src/apps/signalr/Genocs.SignalR.WebApi/Program.cs +++ b/src/apps/signalr/Genocs.SignalR.WebApi/Program.cs @@ -30,32 +30,32 @@ .UseLogging() .UseVault(); -var services = builder.Services; +IGenocsBuilder gnxBuilder = await builder + .AddGenocs() + .AddCorrelationContextLogging() + .AddJwt() + .AddErrorHandler() + .AddOpenTelemetry() + .AddMetrics() + .AddMongo() + .AddCommandHandlers() + .AddEventHandlers() + .AddQueryHandlers() + .AddInMemoryCommandDispatcher() + .AddInMemoryEventDispatcher() + .AddInMemoryQueryDispatcher() + .AddMessageOutbox(o => o.AddMongo()) + .AddWebApi() + .AddSwaggerDocs() + .AddWebApiSwaggerDocs() + .AddRabbitMQAsync(); +var services = builder.Services; services.AddSignalR(); - services.AddTransient(); services.AddTransient(); -services.AddGenocs() - .AddCorrelationContextLogging() - .AddJwt() - .AddErrorHandler() - .AddOpenTelemetry() - .AddMetrics() - .AddMongo() - .AddCommandHandlers() - .AddEventHandlers() - .AddQueryHandlers() - .AddInMemoryCommandDispatcher() - .AddInMemoryEventDispatcher() - .AddInMemoryQueryDispatcher() - .AddRabbitMq() - .AddMessageOutbox(o => o.AddMongo()) - .AddWebApi() - .AddSwaggerDocs() - .AddWebApiSwaggerDocs() - .Build(); +gnxBuilder.Build(); var app = builder.Build(); @@ -69,11 +69,11 @@ r.MapHub("/notificationHub"); }) .UseDispatcherEndpoints(endpoints => endpoints - .Get("", ctx => ctx.Response.WriteAsync("SignalR Service")) - .Get("ping", ctx => ctx.Response.WriteAsync("pong")) .Post("notifications", afterDispatch: (cmd, ctx) => ctx.Response.Created($"notifications/{cmd.NotificationId}"))) .UseSwaggerDocs() - .UseRabbitMq(); + .UseRabbitMQ(); + +app.MapDefaultEndpoints(); app.UseHttpsRedirection(); app.UseStaticFiles(); diff --git a/src/apps/signalr/Genocs.SignalR.WebApi/Properties/launchSettings.json b/src/apps/signalr/Genocs.SignalR.WebApi/Properties/launchSettings.json index af3e485f..b2b66217 100644 --- a/src/apps/signalr/Genocs.SignalR.WebApi/Properties/launchSettings.json +++ b/src/apps/signalr/Genocs.SignalR.WebApi/Properties/launchSettings.json @@ -1,23 +1,9 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:5004;https://localhost:5014" - } - }, "profiles": { - "Genocs.Services.SignalR": { + "Local": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5004;https://localhost:5014", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "development" - } - }, - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, + "applicationUrl": "https://localhost:5540;http://localhost:5541", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "development" } diff --git a/src/apps/signalr/Genocs.SignalR.WebApi/appsettings.json b/src/apps/signalr/Genocs.SignalR.WebApi/appsettings.json index dead120e..87a5e43f 100644 --- a/src/apps/signalr/Genocs.SignalR.WebApi/appsettings.json +++ b/src/apps/signalr/Genocs.SignalR.WebApi/appsettings.json @@ -8,73 +8,68 @@ "displayVersion": true }, "consul": { - "enabled": false, + "enabled": true, "url": "http://localhost:8500", "service": "signalr-service", - "address": "localhost", - "port": "5007", - "pingEnabled": false, - "pingEndpoint": "ping", - "pingInterval": 5, - "removeAfterInterval": 10, + "address": "docker.for.mac.localhost", + "port": "5541", + "pingEnabled": true, + "pingEndpoint": "healthz", + "pingInterval": 3, + "removeAfterInterval": 3, "requestRetries": 3 }, - "elk": { - "enabled": false, - "url": "http://localhost:9200", - "indexFormat": "signalr-service-{0:yyyy.MM.dd}", - "basicAuthEnabled": false, - "username": "user", - "password": "secret" - }, "fabio": { - "enabled": false, + "enabled": true, "url": "http://localhost:9999", "service": "signalr-service", "requestRetries": 3 }, "httpClient": { "type": "", - "retries": 2, + "retries": 3, "services": { "pricing": "localhost:5003" - } - }, - "jaeger": { - "enabled": true, - "serviceName": "signalR", - "udpHost": "localhost", - "udpPort": 6831, - "maxPacketSize": 0, - "sampler": "const", - "excludePaths": [ - "/ping", - "/metrics" - ] - }, - "jwt": { - "certificate": { - "location": "certs/localhost.cer" }, - "secretKey": "JLBMU2VbJZmt42sUwByUpJJF6Y5mG2gPNU9sQFUpJFcGFJdyKxskR3bxh527kax2UcXHvB", - "expiryMinutes": 30, - "issuer": "genocs-identity-service", - "validIssuer": "genocs-identity-service", - "validateAudience": false, - "validateIssuer": true, - "validateLifetime": true, - "expiry": "01:00:00" + "requestMasking": { + "enabled": true, + "maskTemplate": "*****" + }, + "correlationIdHeader": "x-correlation-id" }, "logger": { - "level": "information", - "applicationName": "signalr-service", + "level": "debug", "excludePaths": [ - "/ping", + "/", + "/healthz", + "/alive", "/metrics" ], + "excludeProperties": [ + "api_key", + "access_key", + "ApiKey", + "ApiSecret", + "ClientId", + "ClientSecret", + "ConnectionString", + "Password", + "Email", + "Login", + "Secret", + "Token" + ], "console": { "enabled": true }, + "azure": { + "enabled": false, + "connectionString": "" + }, + "elk": { + "enabled": false, + "url": "http://localhost:9200" + }, "file": { "enabled": true, "path": "logs/logs.txt", @@ -83,13 +78,42 @@ "seq": { "enabled": true, "url": "http://localhost:5341", - "token": "secret" - } + "apiKey": "secret" + }, + "tags": {} + }, + "jaeger": { + "enabled": true, + "serviceName": "signalR", + "endpoint": "http://localhost:4317", + "protocol": "Grpc", + "processorType": "Batch", + "maxQueueSize": 2048, + "scheduledDelayMilliseconds": 5000, + "exporterTimeoutMilliseconds": 30000, + "maxExportBatchSize": 512 + }, + "jwt": { + "enabled": true, + "allowAnonymousEndpoints": [], + "certificate": { + "location": "certs/localhost.cer", + "password": "test", + "rawData": "" + }, + "expiryMinutes": 30, + "issuer": "genocs-identity-service", + "validIssuer": "genocs-identity-service", + "validateAudience": false, + "validateIssuer": true, + "validateLifetime": true, + "expiry": "01:00:00" }, "metrics": { "enabled": true, "influxEnabled": false, "prometheusEnabled": false, + "prometheusFormatter": null, "influxUrl": "http://localhost:8086", "database": "test", "env": "local", @@ -97,15 +121,24 @@ }, "mongodb": { "connectionString": "mongodb://localhost:27017", - "database": "orders-service", + "database": "signalr-service", "seed": false, "enableTracing": true }, "prometheus": { - "enabled": false + "enabled": false, + "endpoint": "/metrics" + }, + "outbox": { + "enabled": true, + "type": "sequential", + "expiry": 3600, + "intervalMilliseconds": 2000, + "inboxCollection": "inbox", + "outboxCollection": "outbox", + "disableTransactions": true }, "rabbitMq": { - "namespace": "signalr", "connectionName": "signalr-service", "messagesPersisted": true, "retries": 3, @@ -157,30 +190,52 @@ }, "maxProducerChannels": 1000 }, + "elk": { + "enabled": false, + "url": "http://localhost:9200", + "indexFormat": "signalr-service-{0:yyyy.MM.dd}", + "basicAuthEnabled": false, + "username": "user", + "password": "secret" + }, "redis": { "connectionString": "localhost", - "instance": "signalr:" + "instance": "signalr:", + "database": 0 }, "restEase": { "loadBalancer": "", "services": [] }, - "security": { - "certificate": { - "enabled": true, - "header": "Certificate", - "allowedHosts": [ - "localhost" - ] - } - }, "swagger": { "enabled": true, "reDocEnabled": false, - "name": "v1", + "name": "SignalR", "title": "SignalR Service", - "version": "v1", - "routePrefix": "swagger" + "version": "v01", + "description": "SignalR Service", + "routePrefix": "swagger", + "includeSecurity": true, + "contactName": "Giovanni Nocco", + "contactEmail": "giovanni.nocco@genocs.com", + "contactUrl": "https://www.genocs.com", + "licenseName": "MIT", + "licenseUrl": "https://www.genocs.com/license.html", + "termsOfService": "https://www.genocs.com/terms_and_conditions.html", + "serializeAsOpenApiV2": true, + "servers": [ + { + "url": "http://localhost:5541", + "description": "Local version to be used for development" + } + ] + }, + "security": { + "certificate": { + "enabled": false, + "header": "Certificate", + "allowedHosts": [ "localhost", "identity" ] + } }, "vault": { "enabled": false, @@ -198,7 +253,7 @@ "pki": { "enabled": false, "roleName": "signalr-service", - "commonName": "signalr-service.convey.io" + "commonName": "signalr-service.demo.io" }, "lease": { "mongo": {