diff --git a/.gitignore b/.gitignore index 75d92e9..35ac2be 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,10 @@ Project_Readme.html # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs .idea/ +.mono/ + +# secret folder '.secrets' all over the project git controlled +.secrets/ # Build results [Dd]ebug/ @@ -226,6 +230,8 @@ Thumbs.db .idea/ # custom +# Ignore environment-specific appsettings, but allow .example files /**/**/appsettings.*.json +!/**/**/appsettings.*.json.example **/**/deployment.yml diff --git a/src/Nocr.TextMatcher.Host/Infrastructure/HostBuilderFactory.cs b/src/Nocr.TextMatcher.Host/Infrastructure/HostBuilderFactory.cs index 9339ad8..e1b683a 100644 --- a/src/Nocr.TextMatcher.Host/Infrastructure/HostBuilderFactory.cs +++ b/src/Nocr.TextMatcher.Host/Infrastructure/HostBuilderFactory.cs @@ -7,14 +7,26 @@ public class HostBuilderFactory where TStartup : class public IHostBuilder CreateHostBuilder(string[] args, string? baseDirectory = null) { var builder = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) - .ConfigureAppConfiguration((_, configurationBuilder) => + .ConfigureWebHostDefaults(host => { host.UseStartup(); }) + .ConfigureAppConfiguration((context, configurationBuilder) => { if (!string.IsNullOrWhiteSpace(baseDirectory)) configurationBuilder.SetBasePath(baseDirectory); - configurationBuilder.AddJsonFile("appsettings.protected.json", optional: true); + // Configuration priority (low to high): + // 1. appsettings.json (already loaded by CreateDefaultBuilder) + // 2. appsettings.{Environment}.json (already loaded) + // 3. User Secrets (already loaded in Development) + // 4. Environment Variables (already loaded) ← highest priority + + // Debug mode: log configuration on startup + if (Environment.GetEnvironmentVariable("NOCR_DEBUG_MODE") == "true") + { + Console.WriteLine("[NOCR_DEBUG] Configuration debug mode enabled"); + Console.WriteLine($"[NOCR_DEBUG] Environment: {context.HostingEnvironment.EnvironmentName}"); + Console.WriteLine($"[NOCR_DEBUG] Base Path: {baseDirectory ?? configurationBuilder.Build().GetValue("ContentRoot") ?? "default"}"); + } }) - .ConfigureWebHostDefaults(host => { host.UseStartup(); }) .UseSerilog((ctx, logBuilder) => { logBuilder.ReadFrom.Configuration(ctx.Configuration) diff --git a/src/Nocr.TextMatcher.Host/Infrastructure/Startup.cs b/src/Nocr.TextMatcher.Host/Infrastructure/Startup.cs index abb7d6b..000206b 100644 --- a/src/Nocr.TextMatcher.Host/Infrastructure/Startup.cs +++ b/src/Nocr.TextMatcher.Host/Infrastructure/Startup.cs @@ -21,6 +21,12 @@ public class Startup public void ConfigureServices(IServiceCollection services) { + // Debug mode: log loaded configuration + if (Environment.GetEnvironmentVariable("NOCR_DEBUG_MODE") == "true") + { + LogConfigurationDebug(); + } + services.AddSingleton(); services.AddControllers(); @@ -66,4 +72,29 @@ public class Startup bus.Advanced.Topics.Subscribe(subscription).GetAwaiter().GetResult(); } } + + private void LogConfigurationDebug() + { + Console.WriteLine("=== [NOCR_DEBUG] Configuration Values ==="); + + var rebusOptions = Configuration.GetSection(nameof(RebusRabbitMqOptions)); + Console.WriteLine($"[NOCR_DEBUG] RebusRabbitMqOptions:"); + Console.WriteLine($"[NOCR_DEBUG] ConnectionString: {MaskConnectionString(rebusOptions["ConnectionString"])}"); + Console.WriteLine($"[NOCR_DEBUG] InputQueueName: {rebusOptions["InputQueueName"]}"); + Console.WriteLine($"[NOCR_DEBUG] DirectExchangeName: {rebusOptions["DirectExchangeName"]}"); + Console.WriteLine($"[NOCR_DEBUG] TopicsExchangeName: {rebusOptions["TopicsExchangeName"]}"); + + var connString = Configuration.GetConnectionString(nameof(TextMatcherContext)); + Console.WriteLine($"[NOCR_DEBUG] TextMatcherContext ConnectionString: {MaskConnectionString(connString)}"); + + Console.WriteLine("=== [NOCR_DEBUG] End Configuration ==="); + } + + private static string MaskConnectionString(string? value) + { + if (string.IsNullOrEmpty(value)) return "(empty)"; + // Mask password in connection string + var masked = System.Text.RegularExpressions.Regex.Replace(value, @"(?i)(password|pwd)=([^;]+)", m => $"{m.Groups[1].Value}=***"); + return masked; + } } \ No newline at end of file diff --git a/src/Nocr.TextMatcher.Host/appsettings.Development.json.example b/src/Nocr.TextMatcher.Host/appsettings.Development.json.example new file mode 100644 index 0000000..8801e5f --- /dev/null +++ b/src/Nocr.TextMatcher.Host/appsettings.Development.json.example @@ -0,0 +1,13 @@ +{ + // This file provides an example configuration for local VS Code debugging. + // Copy this file to appsettings.Development.json and fill in your actual values. + + "ConnectionStrings": { + // MariaDB connection string for TextMatcher database + "TextMatcherContext": "server=localhost;port=3316;database=nocr_text_matcher;uid=root;pwd=toor" + }, + "RebusRabbitMqOptions": { + // RabbitMQ connection string for local development + "ConnectionString": "amqp://admin:admin@localhost:5672/" + } +} diff --git a/src/Nocr.TextMatcher.Host/appsettings.DockerCompose.json.example b/src/Nocr.TextMatcher.Host/appsettings.DockerCompose.json.example new file mode 100644 index 0000000..3bb8167 --- /dev/null +++ b/src/Nocr.TextMatcher.Host/appsettings.DockerCompose.json.example @@ -0,0 +1,13 @@ +{ + // This file provides an example configuration for Docker Compose deployment. + // Copy this file to appsettings.DockerCompose.json. + + "ConnectionStrings": { + // MariaDB connection - use service name from docker-compose.yml + "TextMatcherContext": "server=nocr-text-matcher-db;port=3306;database=nocr_text_matcher;uid=root;pwd=toor" + }, + "RebusRabbitMqOptions": { + // RabbitMQ connection - use service name from docker-compose.yml + "ConnectionString": "amqp://admin:admin@nocr-rabbitmq:5672/" + } +}