From 3ee34c0300a1412616d250f806581438d923bb70 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Mon, 15 Jun 2026 11:23:08 +0200 Subject: [PATCH] Fix reset cache anche di InsEnabled da reload --- MP.Data/Services/IOC/IocService.cs | 4 +- MP.Data/Services/Utils/IStatsDetailService.cs | 7 + MP.Data/Services/Utils/StatsDetailService.cs | 10 +- MP.IOC/Components/Pages/CallStats.razor.cs | 10 + MP.IOC/MP.IOC.csproj | 2 +- MP.IOC/Resources/ChangeLog.html | 2 +- MP.IOC/Resources/VersNum.txt | 2 +- MP.IOC/Resources/manifest.xml | 2 +- MP.IOC/refactor_migration.md | 377 ++++++++++++++++++ 9 files changed, 409 insertions(+), 7 deletions(-) create mode 100644 MP.IOC/refactor_migration.md diff --git a/MP.Data/Services/IOC/IocService.cs b/MP.Data/Services/IOC/IocService.cs index 5db8d93a..8669e3e1 100644 --- a/MP.Data/Services/IOC/IocService.cs +++ b/MP.Data/Services/IOC/IocService.cs @@ -152,7 +152,6 @@ namespace MP.Data.Services.IOC // 3. Conversione efficiente da RedisValue a string (evita l'interpolazione $"{val}") string? sRedisVal = val; return IsStringTrue(sRedisVal); - #if false var rKey = MP.Data.Utils.RedKeyDatiMacc(idxMacchina, MpIoNS); var val = await _redisDb.HashGetAsync(rKey, "insEnabled"); @@ -170,7 +169,8 @@ namespace MP.Data.Services.IOC return !string.IsNullOrEmpty(sVal) && (sVal == "1" || sVal.ToLower() == "true"); #endif }, - expiration: GetRandTOut(30), + expiration: GetRandTOut(60), + //expiration: GetRandTOut(30), tagList: ["IOC_IobInsEnab", cKey, idxMacchina] ); } diff --git a/MP.Data/Services/Utils/IStatsDetailService.cs b/MP.Data/Services/Utils/IStatsDetailService.cs index 751f003b..6f84b5af 100644 --- a/MP.Data/Services/Utils/IStatsDetailService.cs +++ b/MP.Data/Services/Utils/IStatsDetailService.cs @@ -63,6 +63,13 @@ namespace MP.Data.Services.Utils /// Task ResetCache(); + /// + /// Forza il reset della cache REDIS x il pattern richiesto + /// + /// + /// + Task ResetCache(string pattern); + /// /// Inserisce o aggiorna in batch le statistiche di dettaglio nel database. /// Opzionalmente elimina i record precedenti nel periodo specificato. diff --git a/MP.Data/Services/Utils/StatsDetailService.cs b/MP.Data/Services/Utils/StatsDetailService.cs index b637b33d..3c10ad2b 100644 --- a/MP.Data/Services/Utils/StatsDetailService.cs +++ b/MP.Data/Services/Utils/StatsDetailService.cs @@ -22,7 +22,7 @@ namespace MP.Data.Services.Utils IConnectionMultiplexer redis, IFusionCache cache, IStatsDetailRepository repo - ) : base(config,cache, redis) + ) : base(config, cache, redis) { _className = "StatsDetail"; _repo = repo; @@ -134,6 +134,14 @@ namespace MP.Data.Services.Utils await ClearCacheAsync($"{_redisBaseKey}:*"); } + /// + public async Task ResetCache(string pattern) + { + // tolgo eventuali ":" finali + pattern = pattern.EndsWith(":") ? pattern.Substring(0, pattern.Length - 1) : pattern; + await ClearCacheAsync($"{pattern}:*"); + } + /// public async Task UpsertManyAsync(List listRecords, bool removeOld) { diff --git a/MP.IOC/Components/Pages/CallStats.razor.cs b/MP.IOC/Components/Pages/CallStats.razor.cs index 427f7037..c8cfbc54 100644 --- a/MP.IOC/Components/Pages/CallStats.razor.cs +++ b/MP.IOC/Components/Pages/CallStats.razor.cs @@ -14,6 +14,7 @@ namespace MP.IOC.Components.Pages protected override async Task OnInitializedAsync() { + MpIoNS = Config.GetValue("ServerConf:MpIoNS") ?? "MP"; await ReloadData(); } @@ -105,6 +106,9 @@ namespace MP.IOC.Components.Pages [Inject] private IIocService IocService { get; set; } = null!; + [Inject] + private IConfiguration Config { get; set; } = null!; + #endregion Private Properties #region Private Methods @@ -114,8 +118,14 @@ namespace MP.IOC.Components.Pages return currStatSel != null && currStatSel.Title == curKey ? "active" : ""; } + private string MpIoNS = ""; + private async Task DoForceReload() { + // svuoto cache dati IoNS... + var dtMaccKey = Utils.RedKeyDatiMacc("", MpIoNS); + await SDetService.ResetCache(dtMaccKey); + // resto delle cache await SDetService.ResetCache(); await IocService.ClearFusionCache(); DoReset(); diff --git a/MP.IOC/MP.IOC.csproj b/MP.IOC/MP.IOC.csproj index 25647da6..202183d5 100644 --- a/MP.IOC/MP.IOC.csproj +++ b/MP.IOC/MP.IOC.csproj @@ -4,7 +4,7 @@ net8.0 enable enable - 8.16.2606.1312 + 8.16.2606.1511 diff --git a/MP.IOC/Resources/ChangeLog.html b/MP.IOC/Resources/ChangeLog.html index 7ed31778..8bf6f1c5 100644 --- a/MP.IOC/Resources/ChangeLog.html +++ b/MP.IOC/Resources/ChangeLog.html @@ -1,6 +1,6 @@ Modulo MP-IOC -

Versione: 8.16.2606.1312

+

Versione: 8.16.2606.1511


Note di rilascio:
  • diff --git a/MP.IOC/Resources/VersNum.txt b/MP.IOC/Resources/VersNum.txt index 84233792..27bab3be 100644 --- a/MP.IOC/Resources/VersNum.txt +++ b/MP.IOC/Resources/VersNum.txt @@ -1 +1 @@ -8.16.2606.1312 +8.16.2606.1511 diff --git a/MP.IOC/Resources/manifest.xml b/MP.IOC/Resources/manifest.xml index 6c9ebef2..f9e64e4d 100644 --- a/MP.IOC/Resources/manifest.xml +++ b/MP.IOC/Resources/manifest.xml @@ -1,6 +1,6 @@ - 8.16.2606.1312 + 8.16.2606.1511 https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/MP.IOC.zip https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/ChangeLog.html false diff --git a/MP.IOC/refactor_migration.md b/MP.IOC/refactor_migration.md new file mode 100644 index 00000000..ab91040a --- /dev/null +++ b/MP.IOC/refactor_migration.md @@ -0,0 +1,377 @@ +# Piano Migrazione MpDataService → IIocService + +> **Obiettivo**: Standardizzare l'accesso dati su `IIocService` (con FusionCache) e pensionare `MpDataService` come service layer principale di `MP.IOC`. +> +> **Strategia**: Ogni metodo `MpDataService` usato dal controller viene migrato in `IocService`. La cache FusionCache avvolge le chiamate Redis/DB con le stesse durate e tag esistenti. I controller usano solo `IIocService`. + +--- + +## Architettura Target + +``` +IOBController + └── IIocService (scoped) + ├── FusionCache (L1 Memory + L2 Redis + L3 DB via tags) + ├── StackExchange.Redis (IDatabase) ← sorgente "live" per dati esterni + └── IIocRepository (scoped) ← DB access +``` + +**Regola chiave**: Redis diretto (scritto da IOB-WIN, altri programmi) resta accessibile via `IDatabase _redisDb` in `IocService`. FusionCache ha una durata equivalente per validare/invalidare coerentemente. + +--- + +## Stato Attuale + +### Minimal APIs — OK + +I 3 endpoint in `IobEndpoints.cs` sono stati puliti e ora contengono solo: +- `GET api/IOB` / `api/IOB/alive` — health check +- `GET api/IOB/enabled/{id}` — usa `await iocService.IobInsEnabAsync(id)` + +I metodi `setCounter` e `getCurrODL` sono stati rimossi (troppo semplici, nel controller bastano). + +### Controller — Misto + +| Usa DService | Usa IOCService | +|---|---| +| ~37 metodi | 5 metodi (`getCounterTCRec`, `getCurrODL`, `setCounter`, `input`, `getTask2Exe` in parte) | + +### MpDataService + +- Registrato come **singleton** in `Program.cs:106` +- Contiene ~80 metodi, molti con accesso Redis diretto senza FusionCache +- `IocService` è **scoped** e usa già FusionCache + +### IocService + +- Eredita da `MP.Data.Services.BaseServ` (contiene `GetOrFetchAsync`) +- 12 metodi pubblici nell'interface +- Usa FusionCache per i metodi più critici (`IobInsEnabAsync`, `GetCurrOdlAsync`, `StatoProdMacchinaAsync`) + +--- + +## Piano di Migrazione — Fasi + +### Fase 0: Preparazione (`IocService` base) + +**File**: `IIocService.cs`, `IocService.cs` + +0.1. `IocService` deve ereditare da `MP.Data.Services.BaseServ` (attuale `IocService` non lo fa) — per accedere a `GetOrFetchAsync` condiviso + +0.2. Aggiunta di `IFusionCache _cache` nel constructor (già presente in `BaseServ`) + +0.3. Verifica: `redisLongTimeCache` e `redisShortTimeCache` usati da `IocService` per le durate FusionCache + +--- + +### Fase 1: Metodi KeepAlive + Task Management + +**Priorità**: Alta — usati da quasi tutti gli altri metodi come precursori. + +| MpDataService | → IocService | NOTE | +|---|---|---| +| `ScriviKeepAliveAsync` | ✓ già duplicato in `IocService` | Unificare, aggiungere FusionCache per la check key | +| `AddOptPar4Machine` | → `AddOptPar4Machine` | Redis hash, cache per tag machine | +| `AddTask4Machine` | → `AddTask4Machine` | Redis hash + backup, cache per tag machine | +| `mOptParMacchina` | → `GetOptParMacchina` | Redis hash read | +| `mTaskMacchina` / `mTaskMacchinaAsync` | → `GetTaskMacchina` | Redis hash read | +| `RemTask2ExeMacchinaAsync` | → `RemoveTask2ExeAsync` | Redis hash write + delete | +| `mSavedTaskMacchina` | → `GetSavedTasksMacchina` | Redis hash read | +| `AddCheckTask4Machine` | → `AddCheckTask4Machine` | Redis hash read/write | +| `AddTask4MacListAsync` | → `AddTaskListAsync` | Redis hash batch write | + +**Durata cache**: `redisShortTimeCache` (2 min + jitter) per task hash (dati volatile) +**Tag cache**: `Task:{idxMacchina}`, `OptPar:{idxMacchina}`, `SavedTask:{idxMacchina}` + +--- + +### Fase 2: Metodi Process (INPUT, FLOG, ULOG) + +**Priorità**: Altissima — il cuore del sistema, alto traffico. + +| MpDataService | → IocService | NOTE | +|---|---|---| +| `ProcessInputAsync` | → `ProcessInputAsync` | GIÀ in `IocService` ✓ | +| `ProcessFluxLogAsync` | → `ProcessFluxLogAsync` | DB insert + Redis write | +| `ProcessUserLogAsync` | → `ProcessUserLogAsync` | DB insert multi-flux | +| `CheckMicroStatoAsync` | → `CheckMicroStatoAsync` | DB upsert + transizione | +| `scriviRigaEventoAsync` | → `WriteEventRecordAsync` | DB insert | +| `saveSigLogAsync` | → `SaveSignalLogAsync` | DB insert | +| `GetSrvDtEvent` | → `GetServerDateTime` | Pure logic — no cache | +| `ParseEventTime` | → `ParseEventTime` | GIÀ in `IocService` ✓ | +| `preProcInput` | → `PreProcessInput` | Pure logic — no cache | +| `ValidateInputParams` / `ValidateinputParams` | → `ValidateInputParams` | Pure logic — no cache | + +**Durata cache**: Nessuna (scrittura). Tag invalidazione per `MachineData:{idxMacchina}` sui dati che influenzano. +**Tag cache**: `Input:{idxMacchina}`, `FluxLog:{idxMacchina}`, `UserLog:{idxMacchina}`, `MicroStato:{idxMacchina}` + +--- + +### Fase 3: Metodi ODL/PODL + +**Priorità**: Alta — letture frequenti durante produzione. + +| MpDataService | → IocService | NOTE | +|---|---|---| +| `GetCurrOdlAsync` | → `GetCurrOdlAsync` | GIÀ in `IocService` ✓ | +| `GetLastOdlAsync` | → `GetLastOdlAsync` | Usare `GetOrFetchAsync` | +| `OdlCurrByMaccAsync` | → `GetCurrentOdlAsync` | Usare `GetOrFetchAsync` | +| `AutoStartOdlAsync` | → `AutoStartOdlAsync` | Complesso — Redis + DB + eventi | +| `FixDailyDossierAsync` | → `FixDailyDossierAsync` | Chiamata batch | +| `OdlAutoDayGenAsync` | → `GenerateDailyOdlAsync` | DB stored procedure | +| `OdlAutoDayGenFullAsync` | → `GenerateDailyOdlFullAsync` | DB stored procedure | +| `POdlGetByKey` | → `GetPodlByKeyAsync` | Usare `GetOrFetchAsync` | +| `POdlGetByMaccArtAsync` | → `GetPodlByMachineAsync` | Usare `GetOrFetchAsync` | + +**Durata cache**: `redisLongTimeCache` (5 min) per ODL/PODL +**Tag cache**: `Odl:{idxMacchina}`, `Podl:{idxMacchina}` + +--- + +### Fase 4: Metodi Contapezzi + +**Priorità**: Alta — traffico continuo. + +| MpDataService | → IocService | NOTE | +|---|---|---| +| `pzCounter` | → `GetPzCounterAsync` | Redis StringGet (lettura live) | +| `PzCounterTcAsync` | → `PzCounterTcAsync` | GIÀ in `IocService` ✓ | +| `saveCaricoPezzi` | → `SavePezziCaricoAsync` | Redis StringSet + DB insert | +| `SaveCounterAsync` | → `SaveCounterAsync` | GIÀ in `IocService` ✓ | + +**Durata cache**: `redisShortTimeCache` per counter (dati volatile scritti da IOB esterni) +**Tag cache**: `PzCounter:{idxMacchina}` + +--- + +### Fase 5: Metodi Parametri Macchina + +**Priorità**: Alta — metodo più chiamato (ogni richiesta legge i parametri). + +| MpDataService | → IocService | NOTE | +|---|---|---| +| `MachineParamListAsync` | → `GetMachineParamsAsync` | **CRITICO** — Redis read, aggiungere FusionCache | +| `MachineParamListPendingWriteAsync` | → `GetPendingWriteParamsAsync` | Wrapper su GetMachineParamsAsync | +| `MachineParamListSetAsync` | → `SetMachineParamsAsync` | Redis StringSet | +| `MachineParamUpsertAsync` | → `UpsertMachineParamsAsync` | Redis read + write batch | +| `UpsertCurrObjItemsAsync` | → `UpsertMachineParamsAsync` | Duplicate — unificare con UpsertMachineParamsAsync | + +**Durata cache**: `redisShortTimeCache` (2 min) per parametri macchina — dati scritti da IOB esterni ogni pochi secondi +**Tag cache**: `MachineParams:{idxMacchina}` + +--- + +### Fase 6: Metodi Anagrafica e Lookup + +**Priorità**: Media — dati relativamente statici. + +| MpDataService | → IocService | NOTE | +|---|---|---| +| `AnagStatiGetAllAsync` | → `GetAllStatiAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService | +| `ArticoliGetLastByMaccAsync` | → `GetLastArticlesByMachineAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService | +| `DossierLastByMachAsync` | → `GetLastDossiersByMachineAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService | +| `ListValuesFilt` | → `GetListValuesFilteredAsync` | Redis read (duplicare logica FusionCache) | +| `DecNumArtGetFiltAsync` | → `GetDecNumArticoliAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService | +| `MacchineGetFilt` | → `GetMachinesFilteredAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService | +| `Macchine2SlaveGetAllAsync` | → `GetMachineSlaveMapAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService | +| `MacchineRecipeArchive` | → `GetMachineRecipeArchivePathAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService | +| `ConfigGetAllAsync` | → `GetAllConfigAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService | +| `ConfFluxMach` | → `GetConfFluxByMachineAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService | +| `GetArtNumAsync` | → `GetArtNumByCodeAsync` | Interno — wrapper a DecNumArtGetFiltAsync | +| `MseGetAllAsync` | → `GetMachineStateExplAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService | + +**Durata cache**: `redisLongTimeCache` (5 min + jitter) +**Tag cache**: `AnagStati`, `Articoli:{idxMacchina}`, `Dossier:{idxMacchina}`, `Config`, `MSE`, `Macchine` + +--- + +### Fase 7: Metodi Configurazione IOB + Redis Diretto + +**Priorità**: Bassa — configurazione manuale, basso traffico. + +| MpDataService | → IocService | NOTE | +|---|---|---| +| `SetIobMemMap` | → `SetIobMemMapAsync` | Redis StringSet | +| `SetIobConfYamlAsync` | → `SetIobConfYamlAsync` | Redis StringSet | +| `SaveMachineIobConf` | → `SaveMachineIobConfAsync` | Redis HashSet | +| `SaveMachine2Iob` | → `SaveMachine2IobAsync` | Redis StringSet | +| `SaveDataItemsAsync` | → `SaveDataItemsAsync` | Mongo o DB | +| `GetCurrObjItems` | → `GetMachineParamsAsync` | **Duplicate** — usare Fase 5 | + +--- + +### Fase 8: Metodi Logging e Monitoring + +**Priorità**: Bassa — writing-only, nessun cache. + +| MpDataService | → IocService | NOTE | +|---|---|---| +| `AlarmInsertAsync` | → `InsertAlarmLogAsync` | DB insert | +| `RemRebootLogAddAsync` | → `AddRebootLogAsync` | DB insert + Redis flush | +| `WriteEventRecordAsync` (scriviRigaEventoAsync) | → `WriteEventRecordAsync` | DB insert | +| `FluxLogSaveSnapshotAsync` | → `SaveFluxSnapshotAsync` | DB stored procedure | +| `DossierLastByMachResetAsync` | → `ResetDossierCacheAsync` | Redis delete | +| `FluxLogFirstByMachAsync` | → `GetFirstFluxLogsAsync` | GIÀ usa `GetOrFetchAsync` in MpDataService | + +--- + +### Fase 9: Metodi Helper e Internal + +**Priorità**: Bassa — usati internamente. + +| MpDataService | → IocService | NOTE | +|---|---|---| +| `mDatiMacchineAsync` | → `GetMachineDataAsync` | Redis HashGetAll + reset | +| `ResetDatiMacchinaAsync` | → `ResetMachineDataAsync` | Redis transaction batch | +| `StateMachInByKeyAsync` | → `GetStateMachineIngressiAsync` | Redis Hash | +| `resetMSMIAsync` | → `ResetMultiSMIAsync` | Redis Hash write | +| `resetSMIAsync` | → `ResetSMIAsync` | Redis Hash write | +| `ValoreSmiAsync` | → `GetSMIValueAsync` | Redis HashField get | +| `isMulti` | → `IsMultiMachine` | Pure logic | +| `ListMasterAsync` / `ListSlaveAsync` | → `GetMasterListAsync` / `GetSlaveListAsync` | Redis cache | +| `getRandTOut` | → `GetRandomTimeout` | Shared in BaseServ | +| `RedisCountKey`, `RedisDelKey`, `RedisFlushPatternAsync` | → `FlushKeysByPatternAsync` | Admin only | +| `RedisGetHashDictAsync`, `RedisSetHashDictAsync` | → `RedisGet/HashDictAsync` | Wrapper utilities | + +--- + +## Fase 10: Pulizia Controller + +### 10.1. Sostituire `DService` con `IOCService` in `IOBController` + +Cambiare constructor e tutte le chiamate: + +```csharp +// PRIMA +public IOBController(IConfiguration configuration, MpDataService DataService, IIocService IService) +{ + DService = DataService; + IOCService = IService; +} + +// DOPO +public IOBController(IIocService service) +{ + _service = service; +} +``` + +Poi sostituire ogni `DService.Xxx(...)` con `_service.Xxx(...)`. + +### 10.2. Rimuovere `MpDataService` dal controller + +- Rimuovere la property `DService` +- Rimuovere il parametro dal constructor +- Unificare le chiamate miste (alcuni metodi fanno `DService.ScriviKeepAliveAsync` + `IOCService.Xxx`) + +### 10.3. Spostare i private method in `IocService` + +I metodi `processEvListJsonAsync`, `processFLogJsonAsync`, `processULogJsonAsync` contengono logica di business: + +- `processEvListJsonAsync` → `ProcessEventListJsonAsync` in `IocService` +- `processFLogJsonAsync` → `ProcessFluxLogJsonAsync` in `IocService` (complesso — usa `MachineParamListAsync` + `UpsertCurrObjItemsAsync`) +- `processULogJsonAsync` → `ProcessUserLogJsonAsync` in `IocService` + +### 10.4. Rimuovere `MpDataService` da `Program.cs` + +```csharp +// RIMUOVERE: +// builder.Services.AddSingleton(); +``` + +--- + +## Riepilogo Metodi da Migrire + +| Categoria | Metodi da aggiungere a IocService | +|---|---| +| KeepAlive + Task | ~9 metodi | +| Process (INPUT/FLOG/ULOG) | ~9 metodi | +| ODL/PODL | ~8 metodi | +| Contapezzi | ~3 metodi | +| Parametri Macchina | ~4 metodi | +| Anagrafica/Lookup | ~11 metodi | +| Config IOB | ~5 metodi | +| Logging | ~6 metodi | +| Helper/Internal | ~10 metodi | +| **TOTALE** | **~65 metodi** | + +Di questi, ~15 sono già in `IocService` o `BaseServ`. Quindi **~50 nuovi metodi** da implementare. + +--- + +## Criteri di Validazione + +1. **Build** — `./build_all_par.ps1 --agent` senza errori +2. **Functional parity** — ogni endpoint del controller restituisce lo stesso output di prima +3. **Cache behavior** — i metodi migrati registrano `data.source` come TRACE/DEBUG +4. **No `MpDataService` references** nel controller +5. **`Program.cs`** — `MpDataService` rimosso dalla DI registration + +--- + +## Sequenza di Sviluppo Consigliata + +``` +Fase 1 → Fase 4: Blocchi "hot" (keepalive, task, counter) +Fase 5: Parametri macchina (blocco più critico per perf) +Fase 2: Process (INPUT/FLOG/ULOG - cuore dell'app) +Fase 3: ODL/PODL +Fase 6: Anagrafica (dati statici, meno rischioso) +Fase 7-9: Config + Logging + Helper +Fase 10: Cleanup finale +``` + +Ogni fase va build-ata e testata prima di procedere alla successiva. + +--- + +## Note Tecniche + +### Caching su Redis diretto + +Per i dati scritti da programmi esterni (IOB-WIN, ecc.), il pattern è: + +``` +1. Lettura: _redisDb.StringGet/HashGet (dati "live") +2. Scrittura: programmi esterni scrivono in Redis direttamente +3. FusionCache: durata pari a redisShortTimeCache o redisLongTimeCache + - Il backplane Redis invalida L1 negli altri worker + - Se un programma esterno scrive, la prossima lettura dal controller fa cache-miss +``` + +Questo è coerente con l'architettura attuale: il controller legge Redis (sorgente di verità) e FusionCache avvolge per ridurre i round-trip. + +### Tagging Strategy + +``` +MachineData:{idxMacchina} — dati macchina generali (ResetDatiMacchina) +MachineParams:{idxMacchina} — parametri macchina (MachineParamListAsync) +Task:{idxMacchina} — task da eseguire +PzCounter:{idxMacchina} — contapezzi +Odl:{idxMacchina} — ODL correnti +Podl:{idxMacchina} — PODL +Input:{idxMacchina} — log input +FluxLog:{idxMacchina} — log flux +UserLog:{idxMacchina} — log user +``` + +### Transizioni di Scope + +`MpDataService` è singleton → `IIocService` è scoped. Questo va bene per le minimal APIs (che iniettano `IIocService` correttamente). Per il controller, dopo la rimozione di `MpDataService`, il controller diventerà scoped di default (già lo è per `[ApiController]`). + +### IocService constructor + +Attuale (da `MP.Data.Services.IOC.IocService`): +```csharp +public IocService(IConfiguration config, IConnectionMultiplexer redis, + IFusionCache cache, IIocRepository repo, + IServiceScopeFactory scopeFactory) +``` + +Da `MP.Data.Services.BaseServ`: +```csharp +public BaseServ(IConfiguration configuration, IFusionCache cache, IConnectionMultiplexer redConn) +``` + +La gerarchia sarà: `IocService` estende `BaseServ` e il constructor chiama `base(configuration, cache, redConn)`.