Aggiunta metodo EvListJson

This commit is contained in:
Samuele Locatelli
2026-04-15 19:19:06 +02:00
parent 69db4bed94
commit 7a4d5cbe2f
3 changed files with 317 additions and 73 deletions
+11
View File
@@ -0,0 +1,11 @@
namespace MP.Core.DTO
{
public class EvJsonPayloadDto
{
#region Public Properties
public List<EvDataDto> eventList { get; set; } = new();
#endregion Public Properties
}
}
+159 -2
View File
@@ -103,6 +103,122 @@ namespace MP.IOC.Controllers
}
}
/// <summary>
/// Processa una chiamata POST per l'invio di un array Json di oggetti input (EVENTI)
/// POST: IOB/evListJson/SIMUL_03
/// </summary>
/// <param name="id">ID dell'IOB</param>
/// <returns></returns>
[HttpPost("evListJson/{id}")]
public async Task<IActionResult> EvListJson(string id, [FromBody] string content = "")
{
if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID");
string answ = "-";
try
{
// se ho dati...
if (content != "")
{
answ = await processEvListJsonAsync(id, content);
}
else
{
Log.Error($"Errore in EvListJson - no content");
return StatusCode(StatusCodes.Status500InternalServerError, "NO");
}
}
catch (Exception exc)
{
Log.Error($"Errore in EvListJson{Environment.NewLine}{exc}");
return StatusCode(StatusCodes.Status500InternalServerError, "NO");
}
return Ok(answ);
}
#if false
/// <summary>
/// Sistema Dossier/Snapshot giornalieri x impianto indicato, andando a generare 1 Dossier
/// giornaliero x ogni giornata dall'ultimo registrato alla data corrente
/// es: http://url_site/MP/IO/IOB/fixDailyDossier/SIMUL_03
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public string fixDailyDossier(string id)
{
string answ = "";
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
id = id.Replace("|", "#");
// effettuo processing
try
{
DataLayer DataLayerObj = new DataLayer();
// verifico se si possa processare, ovvero tab ConfFlux x macchina sia valorizzata...
var confDataMach = DataLayerObj.confFluxMach(id);
if (confDataMach.Count > 0)
{
// determino ultima data da processare (inizio oggi, a mezzanotte)
DateTime dtTo = DateTime.Today;
DateTime dtFrom = dtTo;
// determino data di partenza, prima da dossier esistenti
var listaDoss = DataLayerObj.dossierLastByMach(id);
if (listaDoss.Count > 0)
{
// primo giorno DOPO ultima registrazione
dtFrom = listaDoss.OrderByDescending(x => x).FirstOrDefault().AddDays(1);
}
else
{
// ...o da fluxLog acquisiti...
var listaFL = DataLayerObj.fluxLogFirstByMach(id);
if (listaFL.Count > 0)
{
// giorno successivo a prima registrazione
dtFrom = listaFL.OrderBy(x => x).FirstOrDefault().AddDays(1);
}
}
string caller = $"takeFlogSnapshot({id})";
DateTime dtStart = dtFrom.Date;
DateTime dtEnd = dtFrom;
// max 10 dossier alla volta (se non configurato diversamente)
int maxAdd = memLayer.ML.CRI("IO_numDossMaxCreate");
if (dtStart < dtTo)
{
// verifico di avere almeno 1 dossier da produrre ciclo fino ad esaurire le
// date da processare
while (dtStart < dtTo && maxAdd > 0)
{
// sistemo end
dtEnd = dtStart.AddDays(1);
// effettuo chiamata registrazione snapshot!
answ = doSaveFLSnapshot(id, dtStart, dtEnd, caller);
// incremento START...
dtStart = dtEnd;
// riduco il numero di chiamate ammesse x singolo task
maxAdd--;
}
// reset cache dossier...
DataLayerObj.dossierLastByMachReset(id);
}
else
{
answ = "NO more to add";
}
}
else
{
answ = "NO ConfFluxData";
}
}
catch (Exception exc)
{
logger.lg.scriviLog($"Eccezione in recupero fixDailyDossier{Environment.NewLine}{exc}", tipoLog.EXCEPTION);
}
return answ;
}
#endif
/// <summary>
/// Sistema ODL giornalieri x impianto indicato, andando a generare 1 ODL giornaliero x ogni
/// giornata dall'ultimo ODL aperto alla data corrente
@@ -609,12 +725,12 @@ namespace MP.IOC.Controllers
DateTime dataOraEvento = DateTime.Now;
try
{
answ = DService.processInput(id, valore, dtEve, dtCurr, cnt);
answ = await DService.ProcessInputAsync(id, valore, dtEve, dtCurr, cnt);
return Ok(answ);
}
catch (Exception exc)
{
Log.Error($"Errore in processInput{Environment.NewLine}{exc}");
Log.Error($"Errore in ProcessInputAsync{Environment.NewLine}{exc}");
return StatusCode(StatusCodes.Status500InternalServerError, "NO");
}
}
@@ -1233,6 +1349,47 @@ namespace MP.IOC.Controllers
return answ;
}
/// <summary>
/// Processing effettivo EvListJson
/// </summary>
/// <param name="idxMacc"></param>
/// <param name="content"></param>
/// <returns></returns>
private async Task<string> processEvListJsonAsync(string idxMacc, string content)
{
string answ = "";
int insDone = 0;
// procedo a deserializzare in blocco l'oggetto...
EvJsonPayloadDto receivedData = JsonConvert.DeserializeObject<EvJsonPayloadDto>(content) ?? new();
// se ho qualcosa da processare...
if (receivedData != null)
{
// per ogni valore --> processo!
try
{
foreach (var item in receivedData.eventList)
{
// formato datetime come yyyyMMddHHmmssfff -->es: 20181223180600000
answ = await DService.ProcessInputAsync(idxMacc, item.valore, item.dtEve.ToString("yyyyMMddHHmmssfff"), item.dtCurr.ToString("yyyyMMddHHmmssfff"), item.cnt.ToString());
insDone++;
}
// se vuoto --> OK!
if (string.IsNullOrEmpty(answ))
{
answ = $"OK {insDone} processed";
}
}
catch (Exception exc)
{
Log.Error($"Errore in fase invio valori inputJson{Environment.NewLine}{exc}");
answ = "NO";
}
}
return answ;
}
/// <summary>
/// Effettua processing UserLog
/// </summary>
+147 -71
View File
@@ -264,66 +264,6 @@ namespace MP.IOC.Data
return answ;
}
/// <summary>
/// Restituisce l'anagrafica STATI per intero
/// </summary>
/// <returns></returns>
public async Task<List<AnagStatiModel>> AnagStatiGetAllAsync()
{
List<AnagStatiModel> dbResult = new List<AnagStatiModel>();
// cerco in redis...
var currKey = Utils.redisAnagStati;
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
dbResult = JsonConvert.DeserializeObject<List<AnagStatiModel>>($"{rawData}") ?? new();
}
else
{
dbResult = await IocDbController.AnagStatiGetAllAsync();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(dbResult);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
}
return dbResult;
}
/// <summary>
/// MS max age x dato MSE
/// </summary>
private int maxAge = 2000;
/// <summary>
/// Elenco da tabella MappaStatoExplModel
/// </summary>
/// <returns></returns>
public async Task<List<MappaStatoExplModel>> MseGetAllAsync(bool forceDb = false)
{
Stopwatch sw = new Stopwatch();
string source = "DB";
sw.Start();
List<MappaStatoExplModel>? result = new List<MappaStatoExplModel>();
// cerco in _redisConn...
RedisValue rawData = await redisDb.StringGetAsync(Constants.redisMseKey);
if (rawData.HasValue && !forceDb)
{
result = JsonConvert.DeserializeObject<List<MappaStatoExplModel>>($"{rawData}") ?? new();
source = "REDIS";
}
else
{
result = await IocDbController.MseGetAllAsync(maxAge);
// serializzp e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(Constants.redisMseKey, rawData, getRandTOut(redisShortTimeCache / 2));
}
if (result == null)
{
result = new List<MappaStatoExplModel>();
}
sw.Stop();
Log.Debug($"MseGetAllAsync | {source} | {sw.Elapsed.TotalMilliseconds}ms");
return result;
}
public async Task<List<ListValuesModel>> AnagStatiComm()
{
Stopwatch stopWatch = new Stopwatch();
@@ -355,6 +295,30 @@ namespace MP.IOC.Data
return result;
}
/// <summary>
/// Restituisce l'anagrafica STATI per intero
/// </summary>
/// <returns></returns>
public async Task<List<AnagStatiModel>> AnagStatiGetAllAsync()
{
List<AnagStatiModel> dbResult = new List<AnagStatiModel>();
// cerco in redis...
var currKey = Utils.redisAnagStati;
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
dbResult = JsonConvert.DeserializeObject<List<AnagStatiModel>>($"{rawData}") ?? new();
}
else
{
dbResult = await IocDbController.AnagStatiGetAllAsync();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(dbResult);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
}
return dbResult;
}
public async Task<List<ListValuesModel>> AnagTipoArtLV()
{
Stopwatch stopWatch = new Stopwatch();
@@ -562,10 +526,10 @@ namespace MP.IOC.Data
/// <param name="dtEve">data-ora evento (server)</param>
/// <param name="contatore">sequenza dati inviati</param>
/// <returns></returns>
public inputComandoMapo checkMicroStato(string idxMacchina, string valore, DateTime dtEve, string contatore)
public async Task<inputComandoMapo> CheckMicroStatoAsync(string idxMacchina, string valore, DateTime dtEve, string contatore)
{
// recupero SE IMPIEGATO REDIS i valori del Dictionary della macchina...
Dictionary<string, string> datiMacc = mDatiMacchine(idxMacchina);
Dictionary<string, string> datiMacc = await mDatiMacchineAsync(idxMacchina);
// processing
inputComandoMapo answ = new inputComandoMapo();
@@ -577,7 +541,7 @@ namespace MP.IOC.Data
string CodArticolo = datiMacc["CodArticolo"];
if (string.IsNullOrEmpty(CodArticolo))
{
var allDatiMacch = IocDbController.DatiMacchineGetAll();
var allDatiMacch = await IocDbController.DatiMacchineGetAllAsync();
var recMacc = allDatiMacch.FirstOrDefault(x => x.IdxMacchina == idxMacchina);
if (recMacc != null)
{
@@ -632,7 +596,7 @@ namespace MP.IOC.Data
InizioStato = dtEve,
Value = valore
};
IocDbController.MicroStatoMacchinaUpsert(newRec);
await IocDbController.MicroStatoMacchinaUpsertAsync(newRec);
if (idxTipoEv > 0)
{
try
@@ -651,7 +615,7 @@ namespace MP.IOC.Data
Value = valEsteso
};
// salva e processa
answ = scriviRigaEvento(newRecEv);
answ = await scriviRigaEventoAsync(newRecEv);
//currTask = scriviRigaEvento(idxMacchina, idxTipoEv, codArticolo, valEsteso, 0, "-", dtEve, DateTime.Now);
// forzo RESET dati macchina...
ResetDatiMacchina(idxMacchina);
@@ -1679,6 +1643,33 @@ namespace MP.IOC.Data
return answ;
}
/// <summary>
/// Restitusice elenco KVP dei campi DatiMacchine + StatoMacchine per l'impianto indicato
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<Dictionary<string, string>> mDatiMacchineAsync(string idxMacchina)
{
// hard coded dimensione vettore DatiMacchine
Dictionary<string, string> answ = new Dictionary<string, string>();
// ORA recupero da memoria redis...
try
{
var currHash = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
answ = await RedisGetHashDictAsync(currHash);
// se è vuoto... leggo da DB e popolo!
if (answ.Count == 0)
{
answ = ResetDatiMacchina(idxMacchina);
}
}
catch (Exception exc)
{
Log.Error($"Errore in compilazione dati Macchine x Redis - idxMacchina {idxMacchina}:{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato
/// </summary>
@@ -1723,6 +1714,39 @@ namespace MP.IOC.Data
return answ;
}
/// <summary>
/// Elenco da tabella MappaStatoExplModel
/// </summary>
/// <returns></returns>
public async Task<List<MappaStatoExplModel>> MseGetAllAsync(bool forceDb = false)
{
Stopwatch sw = new Stopwatch();
string source = "DB";
sw.Start();
List<MappaStatoExplModel>? result = new List<MappaStatoExplModel>();
// cerco in _redisConn...
RedisValue rawData = await redisDb.StringGetAsync(Constants.redisMseKey);
if (rawData.HasValue && !forceDb)
{
result = JsonConvert.DeserializeObject<List<MappaStatoExplModel>>($"{rawData}") ?? new();
source = "REDIS";
}
else
{
result = await IocDbController.MseGetAllAsync(maxAge);
// serializzp e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(Constants.redisMseKey, rawData, getRandTOut(redisShortTimeCache / 2));
}
if (result == null)
{
result = new List<MappaStatoExplModel>();
}
sw.Stop();
Log.Debug($"MseGetAllAsync | {source} | {sw.Elapsed.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Restitusice elenco KVP
/// currKey: IdxMacchina
@@ -2315,7 +2339,7 @@ namespace MP.IOC.Data
/// <param name="dtCurr"></param>
/// <param name="contatore"></param>
/// <returns></returns>
public string processInput(string idxMacchina, string valore, string dtEve, string dtCurr, string contatore)
public async Task<string> ProcessInputAsync(string idxMacchina, string valore, string dtEve, string dtCurr, string contatore)
{
string answ = "";
// 2018.10.26 controllo dtEve e dtCurr
@@ -2346,7 +2370,7 @@ namespace MP.IOC.Data
// se ho meno decimali x evento rispetto dtCorrente...
if (dtEve.Length < dtCurr.Length)
{
Log.Info($"processInput: fix valore dtEve: {dtEve} | dtCurr: {dtCurr}");
Log.Info($"ProcessInputAsync: fix valore dtEve: {dtEve} | dtCurr: {dtCurr}");
dtEve = dtEve.PadRight(dtCurr.Length, '0');
}
delta = Convert.ToInt64(dtCurr) - Convert.ToInt64(dtEve);
@@ -2403,13 +2427,13 @@ namespace MP.IOC.Data
{
int cntVal = 0;
int.TryParse(contatore, out cntVal);
saveSigLog(idxMacchina, valore, dataOraEvento, cntVal);
await saveSigLogAsync(idxMacchina, valore, dataOraEvento, cntVal);
}
// continuo col resto
try
{
// scrivo keep alive!!! (se necessario, altrimenti è in cache...)
ScriviKeepAlive(idxMacchina, DateTime.Now);
await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
// verifico se sia una macchina MULTI ed in tal caso calcolo i
// SUB-systems e CHIAMERO' alla fine pure loro....
if (isMulti(idxMacchina))
@@ -2422,14 +2446,14 @@ namespace MP.IOC.Data
newVal = preProcInput(item.Key, valore);
// ora processo e salvo il valore del microstato...
// INTERNAMENTE gestisce i casi DB/REDIS secondo necessità
checkMicroStato(item.Key, newVal, dataOraEvento, contatore);
await CheckMicroStatoAsync(item.Key, newVal, dataOraEvento, contatore);
}
}
else
{
// ora processo e salvo il valore del microstato... INTERNAMENTE
// gestisce i casi DB/REDIS secondo necessità
checkMicroStato(idxMacchina, valore, dataOraEvento, contatore);
await CheckMicroStatoAsync(idxMacchina, valore, dataOraEvento, contatore);
}
// registro in risposta che è andato tutto bene...
answ = "OK";
@@ -3349,6 +3373,27 @@ namespace MP.IOC.Data
return IocDbController.SignalLogInsert(newRec);
}
/// <summary>
/// salva il segnale di "microstato" (segnale) ASYNC
/// </summary>
/// <param name="idxMacchina">idx macchina</param>
/// <param name="valore">valore ingresso</param>
/// <param name="dtEve">data-ora evento (server)</param>
/// <param name="contatore">contatore sequenza dati inviati</param>
/// <returns></returns>
public async Task<bool> saveSigLogAsync(string idxMacchina, string valore, DateTime dtEve, int contatore)
{
SignalLogModel newRec = new SignalLogModel()
{
IdxMacchina = idxMacchina,
DtCurr = DateTime.Now,
DtEve = dtEve,
Contatore = contatore,
Valore = valore
};
return await IocDbController.SignalLogInsertAsync(newRec);
}
/// <summary>
/// scrive un evento di keepalive sulla tabella
/// </summary>
@@ -3733,6 +3778,11 @@ namespace MP.IOC.Data
private static Logger Log = LogManager.GetCurrentClassLogger();
/// <summary>
/// MS max age x dato MSE
/// </summary>
private int maxAge = 2000;
private string MpIoNS = "";
/// <summary>
@@ -4072,6 +4122,32 @@ namespace MP.IOC.Data
return answ;
}
/// <summary>
/// Scrive una riga di evento nel db + check cambio stato DiarioDiBordo
/// </summary>
/// <param name="newRec">codice macchina</param>
/// <returns></returns>
private async Task<inputComandoMapo> scriviRigaEventoAsync(EventListModel newRec)
{
bool inserito = false;
try
{
// inserisco evento
inserito = await IocDbController.EvListInsertAsync(newRec);
// faccio controllo per eventuale cambio stato da tab transizioni...
checkCambiaStatoBatch(tipoInputEvento.hw, newRec.IdxMacchina, newRec.InizioStato ?? DateTime.Now, newRec.IdxTipo, newRec.CodArticolo, newRec.Value, newRec.MatrOpr, newRec.pallet);
}
catch (Exception exc)
{
Log.Error($"Errore in scriviRigaEvento | IdxMacchina {newRec.IdxMacchina} | IdxTipo {newRec.IdxTipo} | codArticolo {newRec.CodArticolo} | Value {newRec.Value} | MatrOpr {newRec.MatrOpr} | Pallet {newRec.pallet} | dTime {newRec.InizioStato}{Environment.NewLine}{exc}");
}
// formatto output
inputComandoMapo answ = new inputComandoMapo();
answ.outValue = inserito.ToString();
answ.needStatusRefresh = true;
return answ;
}
/// <summary>
/// Restituisce il valore booleano se la macchina sia abilitata all'inserimento COMPLETO nel
/// Signal Log