feat(config): embed credentials for ClickOnce and improve HRMS error messages
Adds embedded AppSecrets configuration so Release/ClickOnce builds work without appsettings.Development.json or a Public Documents config file. Includes AppSecrets.example.cs as a template; copy to gitignored AppSecrets.cs and fill in credentials before publishing. Improves dashboard messages when HRMS is missing vs unreachable.main
parent
252e1b0b80
commit
7cb1ffd65b
|
|
@ -0,0 +1,12 @@
|
|||
namespace HikvisionAttendanceManager.App.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Copy this file to AppSecrets.cs and fill in values before publishing ClickOnce.
|
||||
/// AppSecrets.cs is gitignored and compiled into the application — no external config file required.
|
||||
/// </summary>
|
||||
internal static class AppSecretsExample
|
||||
{
|
||||
internal const string HrmsConnectionString = "";
|
||||
internal const string HikvisionUsername = "";
|
||||
internal const string HikvisionPassword = "";
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using System.IO;
|
||||
|
||||
namespace HikvisionAttendanceManager.App.Services;
|
||||
|
||||
/// <summary>Resolves app settings from embedded AppSecrets, then optional appsettings JSON files.</summary>
|
||||
internal static class AppSettingsConfiguration
|
||||
{
|
||||
public static IConfigurationRoot Build()
|
||||
{
|
||||
var embedded = new Dictionary<string, string?>();
|
||||
if (AppSecrets.HasHrmsConnection)
|
||||
embedded["ConnectionStrings:Hrms"] = AppSecrets.HrmsConnectionString.Trim();
|
||||
if (AppSecrets.HasHikvisionCredentials)
|
||||
{
|
||||
embedded["Hikvision:Username"] = AppSecrets.HikvisionUsername.Trim();
|
||||
embedded["Hikvision:Password"] = AppSecrets.HikvisionPassword.Trim();
|
||||
}
|
||||
|
||||
return new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(embedded)
|
||||
.SetBasePath(AppContext.BaseDirectory)
|
||||
.AddJsonFile("appsettings.json", optional: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true)
|
||||
.Build();
|
||||
}
|
||||
|
||||
public static string? GetConnectionString() => Build().GetConnectionString("Hrms")?.Trim();
|
||||
|
||||
public static string? GetSetting(string key) => Build()[key]?.Trim();
|
||||
|
||||
public static void LogStartupConfigurationStatus()
|
||||
{
|
||||
AppLogger.Info($"Configuration sources: {DescribeConfigSources()}");
|
||||
if (!AppSecrets.HasHrmsConnection && string.IsNullOrWhiteSpace(GetConnectionString()))
|
||||
AppLogger.Warning("HRMS connection is not configured. Set values in Services/AppSecrets.cs before publishing.");
|
||||
if (!AppSecrets.HasHikvisionCredentials && string.IsNullOrWhiteSpace(GetSetting("Hikvision:Username")))
|
||||
AppLogger.Warning("Hikvision default credentials are not configured in AppSecrets.cs.");
|
||||
}
|
||||
|
||||
public static string DescribeConfigSources()
|
||||
{
|
||||
var sources = new List<string>();
|
||||
if (AppSecrets.HasHrmsConnection)
|
||||
sources.Add("embedded AppSecrets");
|
||||
if (File.Exists(Path.Combine(AppContext.BaseDirectory, "appsettings.json")))
|
||||
sources.Add("application appsettings.json");
|
||||
if (File.Exists(Path.Combine(AppContext.BaseDirectory, "appsettings.Development.json")))
|
||||
sources.Add("application appsettings.Development.json");
|
||||
return sources.Count == 0 ? "none" : string.Join(", ", sources);
|
||||
}
|
||||
}
|
||||
|
|
@ -64,18 +64,20 @@ public sealed class DashboardService
|
|||
return null;
|
||||
|
||||
if (!HrmsConnectionFactory.TryGetConnectionString(out _))
|
||||
return "Unable to load device data.\nCheck the HRMS connection.";
|
||||
return "Unable to load device data.\nHRMS is not configured. Set connection values in Services/AppSecrets.cs before publishing.";
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = HrmsConnectionFactory.CreateConnection();
|
||||
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
|
||||
return null;
|
||||
return devices.Count == 0
|
||||
? "Connected to HRMS, but no active Hikvision devices were returned."
|
||||
: null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppLogger.Error("Dashboard: HRMS connection check failed.", ex);
|
||||
return "Unable to load device data.\nCheck the HRMS connection.";
|
||||
return "Unable to connect to the HRMS database.\nCheck server, credentials, and network access.";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using HikvisionAttendanceManager.App.Models;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace HikvisionAttendanceManager.App.Services;
|
||||
|
||||
|
|
@ -37,42 +36,15 @@ public static class HikvisionCredentialsFactory
|
|||
|
||||
public static void LogDevelopmentCredentialStatus()
|
||||
{
|
||||
if (!IsDevelopment())
|
||||
return;
|
||||
AppSettingsConfiguration.LogStartupConfigurationStatus();
|
||||
|
||||
var username = GetDevelopmentSetting("Hikvision:Username");
|
||||
var hasPassword = !string.IsNullOrWhiteSpace(GetDevelopmentSetting("Hikvision:Password"));
|
||||
var username = AppSettingsConfiguration.GetSetting("Hikvision:Username");
|
||||
var hasPassword = !string.IsNullOrWhiteSpace(AppSettingsConfiguration.GetSetting("Hikvision:Password"));
|
||||
if (!string.IsNullOrWhiteSpace(username) && hasPassword)
|
||||
AppLogger.Info($"Hikvision default credentials loaded for user '{username}'.");
|
||||
else
|
||||
AppLogger.Warning("Hikvision default credentials were not found in Development settings.");
|
||||
AppLogger.Warning("Hikvision default credentials were not found in appsettings.");
|
||||
}
|
||||
|
||||
private static string? GetDevelopmentSetting(string key)
|
||||
{
|
||||
if (!IsDevelopment())
|
||||
return null;
|
||||
|
||||
return BuildDevelopmentConfiguration()[key]?.Trim();
|
||||
}
|
||||
|
||||
private static IConfiguration BuildDevelopmentConfiguration() =>
|
||||
new ConfigurationBuilder()
|
||||
.SetBasePath(AppContext.BaseDirectory)
|
||||
.AddJsonFile("appsettings.json", optional: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true)
|
||||
.Build();
|
||||
|
||||
private static bool IsDevelopment()
|
||||
{
|
||||
var environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT")?.Trim();
|
||||
if (!string.IsNullOrWhiteSpace(environment))
|
||||
return string.Equals(environment, "Development", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
#if DEBUG
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
private static string? GetDevelopmentSetting(string key) => AppSettingsConfiguration.GetSetting(key);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public static class HrmsConnectionFactory
|
|||
AppLogger.Info($"Environment = {environment}");
|
||||
AppLogger.Info($"Development config loaded = {(IsDevelopment() && developmentConfigExists ? "YES" : "NO")}");
|
||||
|
||||
if (IsDevelopment() && TryGetDevelopmentConnectionString(out connectionString))
|
||||
if (IsDevelopment() && TryGetJsonConnectionString(out connectionString))
|
||||
{
|
||||
AppLogger.Info("HRMS connection configuration loaded from Development settings.");
|
||||
AppLogger.Info("HRMS connection configuration found = YES");
|
||||
|
|
@ -53,12 +53,19 @@ public static class HrmsConnectionFactory
|
|||
{
|
||||
AppLogger.Info("HRMS connection configuration loaded from service database environment settings.");
|
||||
AppLogger.Info("HRMS connection configuration found = YES");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
||||
if (TryGetJsonConnectionString(out connectionString))
|
||||
{
|
||||
AppLogger.Warning("HRMS connection configuration found = NO");
|
||||
AppLogger.Info($"HRMS connection configuration loaded from appsettings ({AppSettingsConfiguration.DescribeConfigSources()}).");
|
||||
AppLogger.Info("HRMS connection configuration found = YES");
|
||||
return true;
|
||||
}
|
||||
return resolved;
|
||||
|
||||
AppLogger.Warning("HRMS connection configuration found = NO");
|
||||
connectionString = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
public static MySqlConnection CreateConnection()
|
||||
|
|
@ -125,14 +132,9 @@ public static class HrmsConnectionFactory
|
|||
#endif
|
||||
}
|
||||
|
||||
private static bool TryGetDevelopmentConnectionString(out string connectionString)
|
||||
private static bool TryGetJsonConnectionString(out string connectionString)
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.SetBasePath(AppContext.BaseDirectory)
|
||||
.AddJsonFile("appsettings.json", optional: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true)
|
||||
.Build();
|
||||
connectionString = configuration.GetConnectionString("Hrms")?.Trim() ?? "";
|
||||
connectionString = AppSettingsConfiguration.GetConnectionString() ?? "";
|
||||
return !string.IsNullOrWhiteSpace(connectionString);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue