La pagina "Client Versions" (/ClientVersions) mostrava sempre versioni hardcoded obsolete:
Latest version: 1.0.0.0 | Minimum supported: 1.0.0.0
Anche dopo aver aggiornato SecureBootDashboard.Api\appsettings.json con:
{
"ClientUpdate": {
"LatestVersion": "1.5.0.0",
"MinimumVersion": "1.0.0.0"
}
}Il ClientVersionsModel.OnGetAsync() leggeva la configurazione dalla Web app locale:
// ? SBAGLIATO: Legge dalla Web app, non dall'API
LatestVersion = _configuration["ClientUpdate:LatestVersion"] ?? "1.0.0.0";
MinimumVersion = _configuration["ClientUpdate:MinimumVersion"] ?? "1.0.0.0";La sezione ClientUpdate non esiste in SecureBootDashboard.Web\appsettings.json, quindi venivano usati i valori di fallback hardcoded (1.0.0.0).
File: SecureBootDashboard.Web\Pages\ClientVersions.cshtml.cs
private readonly IHttpClientFactory _httpClientFactory;
public ClientVersionsModel(
ISecureBootApiClient apiClient,
IConfiguration configuration,
IHttpClientFactory httpClientFactory) // ? Nuovo parametro
{
_apiClient = apiClient;
_configuration = configuration;
_httpClientFactory = httpClientFactory; // ? Nuovo campo
}private async Task LoadVersionInfoFromApiAsync()
{
try
{
var apiBaseUrl = _configuration["ApiSettings:BaseUrl"];
if (string.IsNullOrEmpty(apiBaseUrl))
{
// Fallback to hardcoded values if API URL not configured
return;
}
var httpClient = _httpClientFactory.CreateClient();
var response = await httpClient.GetFromJsonAsync<ClientUpdateVersionInfo>(
$"{apiBaseUrl}/api/ClientUpdate/version",
HttpContext.RequestAborted);
if (response != null)
{
LatestVersion = response.LatestVersion;
MinimumVersion = response.MinimumVersion;
}
}
catch (Exception)
{
// If API call fails, use fallback values (already set)
}
}public async Task OnGetAsync()
{
try
{
// ? CORRETTO: Recupera da API endpoint
await LoadVersionInfoFromApiAsync();
var latestVer = Version.Parse(LatestVersion);
var minimumVer = Version.Parse(MinimumVersion);
// ... resto del codice
}
catch (Exception ex)
{
ErrorMessage = $"Error loading client versions: {ex.Message}";
}
}// DTO for API response
internal class ClientUpdateVersionInfo
{
public string LatestVersion { get; set; } = "1.0.0.0";
public string MinimumVersion { get; set; } = "1.0.0.0";
public DateTime ReleaseDate { get; set; }
public string? DownloadUrl { get; set; }
public bool IsUpdateRequired { get; set; }
public string? ReleaseNotes { get; set; }
public string? Checksum { get; set; }
public long FileSize { get; set; }
}Configurazione Web (SecureBootDashboard.Web\appsettings.json):
{
"ApiSettings": {
"BaseUrl": "https://localhost:5001"
}
}Configurazione API (SecureBootDashboard.Api\appsettings.json):
{
"ClientUpdate": {
"LatestVersion": "1.5.0.0",
"MinimumVersion": "1.0.0.0"
}
}Risultato:
Latest version: 1.5.0.0 | Minimum supported: 1.0.0.0 ?
Flusso:
- Utente naviga a
/ClientVersions OnGetAsync()chiamaLoadVersionInfoFromApiAsync()- HTTP GET a
https://localhost:5001/api/ClientUpdate/version - API restituisce
{ "latestVersion": "1.5.0.0", "minimumVersion": "1.0.0.0" } - Versioni aggiornate nella pagina
Se l'API è offline o non risponde:
Risultato:
Latest version: 1.0.0.0 | Minimum supported: 1.0.0.0 ?? Fallback
Flusso:
LoadVersionInfoFromApiAsync()tenta la chiamata- Timeout o errore HTTP
- Catch block cattura l'eccezione
- Valori di fallback rimangono (
1.0.0.0) - Pagina funziona comunque (graceful degradation)
Se ApiSettings:BaseUrl è vuoto:
{
"ApiSettings": {
"BaseUrl": "" // ?? Vuoto
}
}Risultato:
Latest version: 1.0.0.0 | Minimum supported: 1.0.0.0 ?? Fallback
Flusso:
LoadVersionInfoFromApiAsync()controllaapiBaseUrl- È
nullo vuoto ?returnanticipato - Nessuna chiamata API
- Valori di fallback usati
Prerequisiti:
- API in esecuzione su
https://localhost:5001 appsettings.jsonAPI conLatestVersion: "1.5.0.0"- Web app configurata con
ApiSettings:BaseUrl: "https://localhost:5001"
Passi:
# 1. Avvia API
cd SecureBootDashboard.Api
dotnet run
# 2. Avvia Web
cd SecureBootDashboard.Web
dotnet run
# 3. Naviga a https://localhost:7001/ClientVersionsVerifica:
- Header mostra "Latest version: 1.5.0.0"
- Header mostra "Minimum supported: 1.0.0.0"
- Nessun errore nella console browser
- Nessun errore nei log Web app
Verifica Network (F12 ? Network):
Request: GET https://localhost:5001/api/ClientUpdate/version
Status: 200 OK
Response: { "latestVersion": "1.5.0.0", "minimumVersion": "1.0.0.0", ... }
Prerequisiti:
- API non in esecuzione
- Web app in esecuzione
Passi:
# 1. Ferma API (se in esecuzione)
# Ctrl+C nel terminale API
# 2. Avvia solo Web
cd SecureBootDashboard.Web
dotnet run
# 3. Naviga a https://localhost:7001/ClientVersionsVerifica:
- Pagina carica senza crash
- Header mostra "Latest version: 1.0.0.0" (fallback)
- Nessun errore visibile all'utente
- Log Web app mostra errore di connessione (normale)
Verifica Network (F12 ? Network):
Request: GET https://localhost:5001/api/ClientUpdate/version
Status: Failed (ERR_CONNECTION_REFUSED o Timeout)
Passi:
# 1. Modifica API appsettings.json
# "LatestVersion": "1.6.0.0" (da 1.5.0.0)
# 2. Riavvia API
# Ctrl+C, poi dotnet run
# 3. Refresh pagina Client Versions (F5)Verifica:
- Header mostra "Latest version: 1.6.0.0" (aggiornato)
- Device con versione
1.5.0.48182ora mostrati come "Outdated" (giallo)
Scenario: Client con versioni diverse
Devices nel DB:
INSERT INTO Devices (MachineName, ClientVersion, ...)
VALUES
('PC-001', '1.5.0.48182', ...), -- Outdated (< 1.5.0.0 API latest? No, >= quindi Up-to-Date se latest fosse 1.5.0.0)
('PC-002', '1.0.0.47500', ...), -- Unsupported (< 1.0.0.0 minimum? No, quindi Outdated se minimum fosse 1.5.0.0)
('PC-003', NULL, ...); -- UnknownCon API config:
{
"LatestVersion": "1.5.0.0",
"MinimumVersion": "1.0.0.0"
}Risultato Atteso:
???????????????????????????????????????????????
? Total: 3 | Up-to-Date: 1 | Outdated: 1 | Unsupported: 0 | Unknown: 1
???????????????????????????????????????????????
Version: 1.5.0.48182 [Up-to-Date ?]
- PC-001
Version: 1.0.0.47500 [Outdated ??]
- PC-002
Version: Unknown [Unsupported ?]
- PC-003
Verifica:
- PC-001 con versione
1.5.0.48182è Up-to-Date (>= 1.5.0.0) - PC-002 con versione
1.0.0.47500è Outdated (< 1.5.0.0 ma >= 1.0.0.0) - PC-003 con versione
nullè Unknown (e considerato Unsupported)
var currentVer = Version.Parse(group.Version); // Es. "1.5.0.48182"
group.IsLatest = currentVer >= latestVer; // >= 1.5.0.0 ? true
group.IsOutdated = currentVer < latestVer; // < 1.5.0.0 ? false
group.IsUnsupported = currentVer < minimumVer; // < 1.0.0.0 ? false| Device Version | Latest (API) | Minimum (API) | IsLatest | IsOutdated | IsUnsupported | Badge |
|---|---|---|---|---|---|---|
| 1.6.0.50000 | 1.5.0.0 | 1.0.0.0 | ? True | ? False | ? False | Green (Up-to-Date) |
| 1.5.0.48182 | 1.5.0.0 | 1.0.0.0 | ? True | ? False | ? False | Green (Up-to-Date) |
| 1.4.0.48000 | 1.5.0.0 | 1.0.0.0 | ? False | ? True | ? False | Yellow (Outdated) |
| 1.0.0.47500 | 1.5.0.0 | 1.0.0.0 | ? False | ? True | ? False | Yellow (Outdated) |
| 0.9.0.47000 | 1.5.0.0 | 1.0.0.0 | ? False | ? True | ? True | Red (Unsupported) |
| NULL | 1.5.0.0 | 1.0.0.0 | ? False | ? True | ? True | Red (Unknown) |
Aggiungere (se non presente):
{
"ApiSettings": {
"BaseUrl": "https://localhost:5001"
}
}Produzione (Azure App Service):
{
"ApiSettings": {
"BaseUrl": "https://your-api.azurewebsites.net"
}
}Già configurato (dalla fix precedente):
{
"ClientUpdate": {
"LatestVersion": "1.5.0.0",
"ReleaseDate": "2025-01-11T00:00:00Z",
"MinimumVersion": "1.0.0.0",
"DownloadUrl": "https://yourstorageaccount.blob.core.windows.net/client-packages/SecureBootWatcher-Client-latest.zip",
"IsUpdateRequired": false,
"ReleaseNotes": "Version 1.5.0 - WebAPI Sink Retry & Failover Fix...",
"Checksum": "",
"FileSize": 0,
"PackagePath": ""
}
}a) Build e Package:
cd SecureBootWatcher.Client
dotnet publish -c Release -o ./publish
Compress-Archive -Path ./publish/* -DestinationPath "./SecureBootWatcher-Client-1.6.0.zip"b) Upload a Storage (opzionale):
az storage blob upload `
--account-name "yourstorageaccount" `
--container-name "client-packages" `
--name "SecureBootWatcher-Client-1.6.0.zip" `
--file "./SecureBootWatcher-Client-1.6.0.zip"c) Aggiorna API appsettings.json:
{
"ClientUpdate": {
"LatestVersion": "1.6.0.0", // ? Aggiornato
"ReleaseDate": "2025-01-15T00:00:00Z",
"DownloadUrl": "https://yourstorageaccount.blob.core.windows.net/client-packages/SecureBootWatcher-Client-1.6.0.zip",
"ReleaseNotes": "Version 1.6.0 - New Features: XYZ"
}
}d) Riavvia API:
# Se su IIS
iisreset
# Se servizio Windows
Restart-Service "SecureBootDashboard.Api"
# Se in sviluppo
# Ctrl+C, poi dotnet runa) Naviga a /ClientVersions:
https://localhost:7001/ClientVersions
b) Verifica Header:
Latest version: 1.6.0.0 ? (aggiornato automaticamente)
c) Verifica Badge Device:
- Device con
1.5.0.48182? Ora mostrati come Outdated (?? giallo) - Device con
1.6.0.50000? Mostrati come Up-to-Date (? verde)
Implementazione Attuale:
catch (Exception)
{
// If API call fails, use fallback values (already set)
}Logging Avanzato (opzionale):
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to load version info from API. Using fallback values.");
// Continua con valori di fallback
}Se l'API è molto lenta, considera il caching:
// In Program.cs della Web app
builder.Services.AddMemoryCache();
// In ClientVersionsModel
private readonly IMemoryCache _cache;
private async Task LoadVersionInfoFromApiAsync()
{
const string cacheKey = "ClientVersionInfo";
if (_cache.TryGetValue(cacheKey, out ClientUpdateVersionInfo? cached))
{
LatestVersion = cached.LatestVersion;
MinimumVersion = cached.MinimumVersion;
return;
}
// Chiamata API...
if (response != null)
{
_cache.Set(cacheKey, response, TimeSpan.FromMinutes(5));
LatestVersion = response.LatestVersion;
MinimumVersion = response.MinimumVersion;
}
}Per retry automatici su errori transitori:
// In Program.cs della Web app
builder.Services.AddHttpClient()
.AddTransientHttpErrorPolicy(builder =>
builder.WaitAndRetryAsync(3, retryAttempt =>
TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))));
// La chiamata API userà automaticamente retryVerifica che l'API sia raggiungibile:
// In Program.cs della Web app
builder.Services.AddHealthChecks()
.AddUrlGroup(new Uri($"{apiBaseUrl}/health"), "API Health");- ?
SecureBootDashboard.Web\Pages\ClientVersions.cshtml.cs
GET /api/ClientUpdate/version(definito inClientUpdateController.cs)
- Web App:
ApiSettings:BaseUrlinappsettings.json - API:
ClientUpdatesection inappsettings.json
docs\CLIENT_VERSION_API_CONFIG_FIX.md- Fix precedente configurazione APIdocs\CLIENT_VERSION_TRACKING.md- Sistema tracking versionidocs\CLIENT_VERSIONS_DASHBOARD.md- Documentazione pagina dashboard
Build & Compile:
- Build riuscita senza errori
- Nessun warning di compilazione
- Dependency injection
IHttpClientFactoryregistrata
Funzionalità:
- Pagina
/ClientVersionscarica senza errori - Header mostra versione corretta dall'API
- Fallback funziona se API offline
- Badge versione corretti (verde/giallo/rosso)
Testing:
- Test Case 1: API Online e Configurata
- Test Case 2: API Offline (Fallback)
- Test Case 3: Cambio Versione API
- Test Case 4: Verifica Calcolo Status
Configurazione:
-
ApiSettings:BaseUrlconfigurato in Webappsettings.json -
ClientUpdate:LatestVersionaggiornato in APIappsettings.json - API in esecuzione e raggiungibile
? Problema Risolto: Pagina Client Versions ora mostra versione corretta dall'API
Prima: Hardcoded 1.0.0.0 (lettura da config locale Web)
Dopo: Dinamico 1.5.0.0 (lettura da endpoint API /api/ClientUpdate/version)
Modifiche:
- Aggiunto
IHttpClientFactorya dependency injection - Creato metodo
LoadVersionInfoFromApiAsync() - Aggiunto DTO
ClientUpdateVersionInfoper risposta API - Implementato graceful degradation (fallback se API offline)
Vantaggi:
- ? Versione sempre sincronizzata con API
- ? Single source of truth (API
appsettings.json) - ? Nessun deployment Web app necessario per cambio versione
- ? Fallback funzionale se API temporaneamente offline
Testing Necessario: Verificare con API online e offline
Fix Applicata: 2025-01-11
Status: ? COMPLETO E PRONTO PER TESTING
Breaking Changes: ? None
Backward Compatible: ? Yes (fallback a 1.0.0.0)