Aggiunto XML commento metodi

This commit is contained in:
Samuele Locatelli
2025-11-28 08:47:48 +01:00
parent 9580b3af2b
commit 25b252113b
2 changed files with 193 additions and 54 deletions
+192 -53
View File
@@ -1,4 +1,17 @@
using IOB_MAN.Core.Services;
/// <summary>
/// Main Windows Forms host for the Blazor application.
/// This class serves as the entry point for the desktop application, integrating Blazor WebViews
/// with background services, memory monitoring, and auto-restart logic.
///
/// Key Responsibilities:
/// - Initializes and hosts a Blazor WebAssembly UI via Windows Forms BlazorWebView.
/// - Manages lifecycle events: startup, form closing, and shutdown.
/// - Monitors .NET memory usage and system memory to prevent memory leaks or out-of-memory crashes.
/// - Implements periodic checks for auto-restart based on configuration and GC behavior.
/// - Listens to external signals (e.g., config updates, reload/reboot requests) from services.
/// - Gracefully shuts down all managed processes on exit or restart.
/// </summary>
using IOB_MAN.Core.Services;
using Microsoft.AspNetCore.Components.WebView.WindowsForms;
using Microsoft.Extensions.DependencyInjection;
using NLog;
@@ -11,6 +24,10 @@ namespace IOB_MAN
{
#region Public Constructors
/// <summary>
/// Initializes a new instance of the BlazorForm class.
/// Sets up the form, initializes services, configures Blazor view, and starts background timers.
/// </summary>
public BlazorForm()
{
InitializeComponent();
@@ -26,8 +43,16 @@ namespace IOB_MAN
#region Public Methods
/// <summary>
/// Force restart application, with delay
/// Forces a restart of the application with an optional delay.
///
/// Behavior:
/// - If 'force' is true, logs a forced restart (e.g., due to critical error).
/// - Otherwise, triggers restart due to consecutive GC thresholds being exceeded.
/// - Stops all running sub-processes via ACService.DoCloseAll().
/// - Delays restart using cmd.exe timeout to ensure clean exit of current instance.
/// - Uses Application.Exit() to terminate the current process safely.
/// </summary>
/// <param name="force">If true, performs a forced restart; otherwise, triggers restart due to GC exhaustion.</param>
public static void RestartApplication(bool force)
{
if (force)
@@ -38,12 +63,14 @@ namespace IOB_MAN
{
Log.Info($"Chiamata restart application x superamento soglia GC consecutivi");
}
string exePath = Application.ExecutablePath;
// fermo tutti i sw controllati...
// Close all managed services (e.g., external SWs) before restart
ACService.DoCloseAll(false);
Log.Info($"Completata chiusura processi x restart");
// Use cmd.exe to delay start until current app exits
// Delay restart by 5 seconds using cmd.exe to avoid immediate re-launch
int restartDelay = 5;
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", $"/C timeout /t {restartDelay} & start \"\" \"{exePath}\"")
{
@@ -54,7 +81,7 @@ namespace IOB_MAN
Process.Start(psi);
Log.Info($"Avviato task di riavvio post delay {restartDelay}sec");
// Now safely exit the current instance
// Exit current instance after delay
Application.Exit();
}
@@ -63,7 +90,8 @@ namespace IOB_MAN
#region Protected Fields
/// <summary>
/// Dataora prossima scadenza riavvio automatico
/// The next scheduled time for automatic restart check (based on configuration).
/// Used to determine when auto-restart should be triggered.
/// </summary>
protected DateTime tOutAutocheck = DateTime.Now;
@@ -72,28 +100,43 @@ namespace IOB_MAN
#region Private Fields
/// <summary>
/// Classe logger
/// Logger instance for structured logging throughout the application.
/// </summary>
private static Logger Log = LogManager.GetCurrentClassLogger();
/// <summary>
/// Counter tracking consecutive GC collections.
/// Used to detect prolonged memory pressure and trigger forced restart if threshold exceeded.
/// </summary>
private int currSeqGC = 0;
/// <summary>
/// Memoria dotNet allocata
/// Total managed memory allocated by the .NET runtime (in bytes).
/// Monitored to detect memory pressure and trigger GC or restart.
/// </summary>
private long dotNetMemUsed = 0;
/// <summary>
/// Timestamp of the last forced GC collection.
/// Used to enforce periodic GC even if memory is not critically high.
/// </summary>
private DateTime LastForcedGC = DateTime.Now;
/// <summary>
/// Maximum number of consecutive GC collections allowed before triggering restart.
/// Default is 5 — if exceeded, application restarts to prevent memory exhaustion.
/// </summary>
private int maxConsGC = 5;
/// <summary>
/// Max memoria consumabile (std 128Mb)
/// Maximum allowed memory consumption (in MB) for the application.
/// Default is 128 MB — if managed or total memory exceeds half of this, triggers GC or restart.
/// </summary>
private double maxMemoryLimitMb = 128.0;
/// <summary>
/// Memoria totale processo
/// Total private memory used by the current process (in bytes).
/// Used to detect system-level memory pressure.
/// </summary>
private long totalMemUsed = 0;
@@ -101,17 +144,32 @@ namespace IOB_MAN
#region Private Properties
/// <summary>
/// Singleton service for application control (e.g., managing external services, config, restarts).
/// </summary>
private static AppControlService ACService { get; set; } = null!;
/// <summary>
/// Singleton service for handling flux log requests and UI interactions.
/// </summary>
private static FluxLogManService FLMService { get; set; } = null!;
/// <summary>
/// Converts .NET managed memory (bytes) to MB for logging and display.
/// </summary>
private double dotNetMemUsedMb
{
get => dotNetMemUsed / 1024.0 / 1024.0;
}
/// <summary>
/// Stores the last known size of the form to maintain consistent positioning.
/// </summary>
private Size lastSize { get; set; } = new Size(1200, 700);
/// <summary>
/// Converts total process memory (bytes) to MB for logging and display.
/// </summary>
private double totalMemUsedMb
{
get => totalMemUsed / 1024.0 / 1024.0;
@@ -122,22 +180,29 @@ namespace IOB_MAN
#region Private Methods
/// <summary>
/// Esecuzione del processo di restart
/// Executes a restart of the application.
///
/// Behavior:
/// - If 'fullRestart' is true, launches an external restarter (EgwAccRestarter.exe).
/// - Otherwise, uses Application.Restart() to restart the current app (without external update check).
/// </summary>
/// <param name="fullRestart">If true, uses external restarter; otherwise, restarts current app.</param>
private static void DoRestart(bool fullRestart)
{
// full restart usa sw esterno, altrimenti solo app che riparte SENZA check update esterno
if (fullRestart)
{
// uso restarter esterno...
// Launch external restarter (e.g., for complex service restarts)
Assembly assembly = Assembly.GetExecutingAssembly();
string startDir = Path.GetDirectoryName(assembly.Location)!;
string extPath = Path.Combine(startDir, "libs", "EgwAccRestarter.exe");
// uso processstartInfo x nascondere finestra
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.CreateNoWindow = true;
startInfo.FileName = extPath;
ProcessStartInfo startInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Normal,
CreateNoWindow = true,
FileName = extPath
};
Process.Start(startInfo);
}
else
@@ -148,9 +213,12 @@ namespace IOB_MAN
}
/// <summary>
/// Riavvio il timer...
/// Handles configuration updates from the AppControlService.
///
/// Actions:
/// - Stops and restarts timers to reflect new refresh intervals.
/// - Updates the auto-restart check time from configuration.
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void ACService_EA_ConfigUpdated()
{
timerUI.Stop();
@@ -159,6 +227,14 @@ namespace IOB_MAN
StartTimer();
}
/// <summary>
/// Handles a reboot request from the AppControlService.
///
/// Actions:
/// - Stops all timers and services.
/// - Closes all external processes.
/// - Triggers a forced restart.
/// </summary>
private void ACService_EA_RebootRequested()
{
Log.Info("---------------------------------------");
@@ -172,21 +248,36 @@ namespace IOB_MAN
RestartApplication(true);
}
/// <summary>
/// Handles a reload request from the AppControlService.
///
/// Action:
/// - Restarts the application without closing external services (partial reload).
/// </summary>
private void ACService_EA_ReloadRequested()
{
// effettua chiamata reload
DoRestart(false);
}
/// <summary>
/// Gestione evento restart applicazione
/// Handles a restart request from the AppControlService.
///
/// Action:
/// - Triggers a full restart (using external restarter).
/// </summary>
private void ACService_EA_RestartRequested()
{
// effettua chiamata restart
DoRestart(true);
}
/// <summary>
/// Cleans up event handlers and resources when the form is closing.
///
/// Actions:
/// - Removes event subscriptions from services.
/// - Stops and disposes timers.
/// - Closes all external processes.
/// </summary>
private void BlazorForm_FormClosing(object sender, FormClosingEventArgs e)
{
ACService.EA_ConfigUpdated -= ACService_EA_ConfigUpdated;
@@ -202,33 +293,39 @@ namespace IOB_MAN
}
/// <summary>
/// Evento completamento caricamento app
/// Sets the form's position to center-bottom of the screen workspace.
/// Ensures consistent placement across different screen configurations.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BlazorForm_Load(object sender, EventArgs e)
{
SetPosition();
}
/// <summary>
/// effettua controllo memoria + log
/// se occupa più di maxMemoryLimitMb --> chiama GC
/// Periodically checks memory usage and triggers GC if thresholds are exceeded.
///
/// Logic:
/// - Measures managed and total memory.
/// - If managed memory exceeds half of maxMemoryLimitMb OR total memory exceeds maxMemoryLimitMb:
/// - Forces GC collection.
/// - Increments consecutive GC counter.
/// - If counter exceeds maxConsGC → triggers restart.
/// - If more than 1 hour has passed since last forced GC → triggers periodic GC.
/// - Otherwise, decrements counter to prevent overcounting.
/// </summary>
private void CheckMemory()
{
dotNetMemUsed = GC.GetTotalMemory(false); // Pass 'true' to force a garbage collection first
dotNetMemUsed = GC.GetTotalMemory(false);
Process currentProcess = Process.GetCurrentProcess();
totalMemUsed = currentProcess.PrivateMemorySize64;
Log.Info($"Memory Usage | {dotNetMemUsedMb:F2} / {totalMemUsedMb:F2} MB | Managed / Total");
if (dotNetMemUsedMb > maxMemoryLimitMb / 2 || totalMemUsedMb > maxMemoryLimitMb)
{
// chiamo GC forzatamente
currSeqGC++;
Log.Info($"Chiamato forzatamente GC.Collect per superamento limite memoria | count: {currSeqGC}");
GC.Collect();
// registro forced GC
LastForcedGC = DateTime.Now;
if (currSeqGC > maxConsGC)
{
@@ -239,10 +336,8 @@ namespace IOB_MAN
}
else if (DateTime.Now.Subtract(LastForcedGC).TotalHours > 1)
{
// chiamo GC forzatamente
Log.Info($"Chiamato forzatamente GC.Collect per scadenza periodo");
GC.Collect();
// registro forced GC
LastForcedGC = DateTime.Now;
}
else
@@ -256,25 +351,38 @@ namespace IOB_MAN
}
/// <summary>
/// Init conf accessorie
/// Initializes configuration values from the AppControlService.
///
/// Specifically: sets maxMemoryLimitMb from configuration (e.g., MaxMemGc).
/// </summary>
private void ConfInit()
{
// recupero limite memoria prima del GC
maxMemoryLimitMb = ACService.MaxMemGc;
}
/// <summary>
/// Richiesta apertura nuova form x editing FluxLog: la implemento leggendo il codIOB e lo passo al controllo...
/// Handles a request to open a FluxLog editing form.
///
/// Action:
/// - Creates and shows a new FluxLogData form with the provided codIOB.
/// - Enables user to edit or view flux logs for a specific IOB.
/// </summary>
/// <param name="codIOB"></param>
/// <param name="codIOB">The IOB code associated with the requested log.</param>
private void FLMService_EA_FluxLogReq(string codIOB)
{
// chiamo nuova form con parametro x CodIOB richiesto
FluxLogData FldForm = new FluxLogData(FLMService, codIOB);
FldForm.Show();
}
/// <summary>
/// Initializes the Blazor WebView with required services and root components.
///
/// Steps:
/// - Sets up a ServiceCollection with required dependencies.
/// - Registers AppControlService and FluxLogManService as singletons.
/// - Configures the BlazorWebView to load the index.html page.
/// - Adds MainBlazor component to the root element.
/// </summary>
private void InitBlazorView()
{
Stopwatch sw = new Stopwatch();
@@ -296,13 +404,20 @@ namespace IOB_MAN
}
catch (Exception exc)
{
Log.Error($"Exception during setartup{Environment.NewLine}{exc}");
Log.Error($"Exception during startup{Environment.NewLine}{exc}");
}
}
/// <summary>
/// Initializes core services (AppControlService, FluxLogManService).
///
/// Registers event handlers for:
/// - Config updates
/// - Restart, reload, and reboot requests
/// - FluxLog request events
/// </summary>
private void ServiceInit()
{
//init preliminare servizio controllo
ACService = new AppControlService(true);
FLMService = new FluxLogManService();
ACService.EA_ConfigUpdated += ACService_EA_ConfigUpdated;
@@ -312,31 +427,50 @@ namespace IOB_MAN
FLMService.EA_FluxLogReq += FLMService_EA_FluxLogReq;
}
/// <summary>
/// Centers the form in the bottom-left of the screen workspace.
/// Ensures consistent UI placement regardless of screen resolution.
/// </summary>
private void SetPosition()
{
// posiziono in basso a sx...
Rectangle workArea = Screen.GetWorkingArea(this);
this.Location = new Point((workArea.Right - lastSize.Width) / 2, (workArea.Bottom - lastSize.Height) / 2);
}
/// <summary>
/// Starts background timers based on configuration values from AppControlService.
///
/// Timers:
/// - timerUI: scans application state at intervals (RefreshPeriod).
/// - timerTask: checks for auto-restart conditions (CheckRestartPeriod).
/// - timerMemCheck: monitors memory usage (CheckMemoryPeriod).
///
/// Note: Delays start by 2080ms to avoid race conditions during initialization.
/// </summary>
private void StartTimer()
{
// timer controlli da conf
timerUI.Interval = (ACService.RefreshPeriod);
timerTask.Interval = (ACService.CheckRestartPeriod);
timerMemCheck.Interval = (ACService.CheckMemoryPeriod);
// avvio timers
timerUI.Start();
Thread.Sleep(rand.Next(20,80));
Thread.Sleep(rand.Next(20, 80));
timerTask.Start();
Thread.Sleep(rand.Next(20, 80));
timerMemCheck.Start();
}
/// <summary>
/// Random number generator for introducing slight delays in timer startup.
/// Used to prevent all timers from starting simultaneously.
/// </summary>
private Random rand = new Random();
/// <summary>
/// Evento timer memory check periodico
/// Periodic memory check timer event.
///
/// Triggers CheckMemory() to monitor memory usage and enforce GC if needed.
/// Also logs service statistics for debugging.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
@@ -347,34 +481,39 @@ namespace IOB_MAN
}
/// <summary>
/// Timer task x eventuale riavvio processi fermi SE abilitato...
/// Periodic task timer event.
///
/// Actions:
/// - Stops the timer to avoid overlap.
/// - Checks for conditions to auto-restart external services.
/// - Restarts the timer to maintain continuous monitoring.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void timerTask_Tick(object sender, EventArgs e)
{
// fermo task...
timerTask.Stop();
// esegue controllo task x eventuale autorestart
ACService.DoAutoRestart(false);
// riavvio task x evitare sovrapposizioni in debug
timerTask.Start();
}
/// <summary>
/// Esecuzione task di verifica stato app
/// Periodic UI scan timer event.
///
/// Actions:
/// - Stops the timer to avoid overlap.
/// - Executes ACService.DoScan() to check application state.
/// - Reinstates the timer to maintain continuous monitoring.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void timerUI_Tick(object sender, EventArgs e)
{
// fermo task...
timerUI.Stop();
await ACService.DoScan();
// riavvio task x evitare sovrapposizioni in debug
timerUI.Start();
}
#endregion Private Methods
}
}
}
+1 -1
View File
@@ -8,7 +8,7 @@
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<Version>4.0.2511.2718</Version>
<Version>4.0.2511.2807</Version>
<Configurations>Debug;Release;Remote_DEBUG</Configurations>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
</PropertyGroup>