Aggiunto XML commento metodi
This commit is contained in:
+192
-53
@@ -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 20–80ms 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user