diff --git a/IOB-MAN/BlazorForm.cs b/IOB-MAN/BlazorForm.cs
index cff0ddc..cbd48a9 100644
--- a/IOB-MAN/BlazorForm.cs
+++ b/IOB-MAN/BlazorForm.cs
@@ -1,4 +1,17 @@
-using IOB_MAN.Core.Services;
+///
+/// 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.
+///
+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
+ ///
+ /// Initializes a new instance of the BlazorForm class.
+ /// Sets up the form, initializes services, configures Blazor view, and starts background timers.
+ ///
public BlazorForm()
{
InitializeComponent();
@@ -26,8 +43,16 @@ namespace IOB_MAN
#region Public Methods
///
- /// 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.
///
+ /// If true, performs a forced restart; otherwise, triggers restart due to GC exhaustion.
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
///
- /// 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.
///
protected DateTime tOutAutocheck = DateTime.Now;
@@ -72,28 +100,43 @@ namespace IOB_MAN
#region Private Fields
///
- /// Classe logger
+ /// Logger instance for structured logging throughout the application.
///
private static Logger Log = LogManager.GetCurrentClassLogger();
+ ///
+ /// Counter tracking consecutive GC collections.
+ /// Used to detect prolonged memory pressure and trigger forced restart if threshold exceeded.
+ ///
private int currSeqGC = 0;
///
- /// Memoria dotNet allocata
+ /// Total managed memory allocated by the .NET runtime (in bytes).
+ /// Monitored to detect memory pressure and trigger GC or restart.
///
private long dotNetMemUsed = 0;
+ ///
+ /// Timestamp of the last forced GC collection.
+ /// Used to enforce periodic GC even if memory is not critically high.
+ ///
private DateTime LastForcedGC = DateTime.Now;
+ ///
+ /// Maximum number of consecutive GC collections allowed before triggering restart.
+ /// Default is 5 — if exceeded, application restarts to prevent memory exhaustion.
+ ///
private int maxConsGC = 5;
///
- /// 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.
///
private double maxMemoryLimitMb = 128.0;
///
- /// Memoria totale processo
+ /// Total private memory used by the current process (in bytes).
+ /// Used to detect system-level memory pressure.
///
private long totalMemUsed = 0;
@@ -101,17 +144,32 @@ namespace IOB_MAN
#region Private Properties
+ ///
+ /// Singleton service for application control (e.g., managing external services, config, restarts).
+ ///
private static AppControlService ACService { get; set; } = null!;
+ ///
+ /// Singleton service for handling flux log requests and UI interactions.
+ ///
private static FluxLogManService FLMService { get; set; } = null!;
+ ///
+ /// Converts .NET managed memory (bytes) to MB for logging and display.
+ ///
private double dotNetMemUsedMb
{
get => dotNetMemUsed / 1024.0 / 1024.0;
}
+ ///
+ /// Stores the last known size of the form to maintain consistent positioning.
+ ///
private Size lastSize { get; set; } = new Size(1200, 700);
+ ///
+ /// Converts total process memory (bytes) to MB for logging and display.
+ ///
private double totalMemUsedMb
{
get => totalMemUsed / 1024.0 / 1024.0;
@@ -122,22 +180,29 @@ namespace IOB_MAN
#region Private Methods
///
- /// 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).
///
+ /// If true, uses external restarter; otherwise, restarts current app.
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
}
///
- /// 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.
///
- ///
private void ACService_EA_ConfigUpdated()
{
timerUI.Stop();
@@ -159,6 +227,14 @@ namespace IOB_MAN
StartTimer();
}
+ ///
+ /// Handles a reboot request from the AppControlService.
+ ///
+ /// Actions:
+ /// - Stops all timers and services.
+ /// - Closes all external processes.
+ /// - Triggers a forced restart.
+ ///
private void ACService_EA_RebootRequested()
{
Log.Info("---------------------------------------");
@@ -172,21 +248,36 @@ namespace IOB_MAN
RestartApplication(true);
}
+ ///
+ /// Handles a reload request from the AppControlService.
+ ///
+ /// Action:
+ /// - Restarts the application without closing external services (partial reload).
+ ///
private void ACService_EA_ReloadRequested()
{
- // effettua chiamata reload
DoRestart(false);
}
///
- /// Gestione evento restart applicazione
+ /// Handles a restart request from the AppControlService.
+ ///
+ /// Action:
+ /// - Triggers a full restart (using external restarter).
///
private void ACService_EA_RestartRequested()
{
- // effettua chiamata restart
DoRestart(true);
}
+ ///
+ /// 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.
+ ///
private void BlazorForm_FormClosing(object sender, FormClosingEventArgs e)
{
ACService.EA_ConfigUpdated -= ACService_EA_ConfigUpdated;
@@ -202,33 +293,39 @@ namespace IOB_MAN
}
///
- /// Evento completamento caricamento app
+ /// Sets the form's position to center-bottom of the screen workspace.
+ /// Ensures consistent placement across different screen configurations.
///
- ///
- ///
private void BlazorForm_Load(object sender, EventArgs e)
{
SetPosition();
}
///
- /// 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.
///
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
}
///
- /// Init conf accessorie
+ /// Initializes configuration values from the AppControlService.
+ ///
+ /// Specifically: sets maxMemoryLimitMb from configuration (e.g., MaxMemGc).
///
private void ConfInit()
{
- // recupero limite memoria prima del GC
maxMemoryLimitMb = ACService.MaxMemGc;
}
///
- /// 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.
///
- ///
+ /// The IOB code associated with the requested log.
private void FLMService_EA_FluxLogReq(string codIOB)
{
- // chiamo nuova form con parametro x CodIOB richiesto
FluxLogData FldForm = new FluxLogData(FLMService, codIOB);
FldForm.Show();
}
+ ///
+ /// 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.
+ ///
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}");
}
}
+ ///
+ /// Initializes core services (AppControlService, FluxLogManService).
+ ///
+ /// Registers event handlers for:
+ /// - Config updates
+ /// - Restart, reload, and reboot requests
+ /// - FluxLog request events
+ ///
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;
}
+ ///
+ /// Centers the form in the bottom-left of the screen workspace.
+ /// Ensures consistent UI placement regardless of screen resolution.
+ ///
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);
}
+ ///
+ /// 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 20–80ms to avoid race conditions during initialization.
+ ///
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();
}
+ ///
+ /// Random number generator for introducing slight delays in timer startup.
+ /// Used to prevent all timers from starting simultaneously.
+ ///
private Random rand = new Random();
///
- /// 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.
///
///
///
@@ -347,34 +481,39 @@ namespace IOB_MAN
}
///
- /// 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.
///
///
///
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();
}
///
- /// 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.
///
///
///
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
}
-}
\ No newline at end of file
+}
diff --git a/IOB-MAN/IOB-MAN.csproj b/IOB-MAN/IOB-MAN.csproj
index 66e75cb..0689306 100644
--- a/IOB-MAN/IOB-MAN.csproj
+++ b/IOB-MAN/IOB-MAN.csproj
@@ -8,7 +8,7 @@
enable
true
enable
- 4.0.2511.2718
+ 4.0.2511.2807
Debug;Release;Remote_DEBUG
false