using Core; using Core.DTO; using Liman.CadCam.DbModel; using LiMan.DB.Controllers; using LiMan.DB.DBModels; using LiMan.DB.DTO; using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using NLog; using Org.BouncyCastle.Asn1.Pkcs; using StackExchange.Redis; using System; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Linq; using System.Runtime; using System.Text; using System.Threading.Tasks; using static Core.Enum; namespace LiMan.UI.Data { public class LiManDataService : IDisposable { #region Public Fields public static GLS.Controllers.LicManController dbControllerGLS; public static DB.Controllers.DbController dbControllerNext; #endregion Public Fields #region Public Constructors public LiManDataService(IConfiguration configuration, ILogger logger, IMemoryCache memoryCache, IDistributedCache distributedCache, IConnectionMultiplexer redisConnMult, IEmailSender emailSender) { _logger = logger; _configuration = configuration; // Conf cache redisConn = redisConnMult; redisDb = this.redisConn.GetDatabase(); // json serializer... FIX errore loop circolare https://www.ryadel.com/en/jsonserializationexception-self-referencing-loop-detected-error-fix-entity-framework-asp-net-core/ JSSettings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }; _emailSender = emailSender; // conf cache this.memoryCache = memoryCache; this.distributedCache = distributedCache; // conf DB string connStrGLS = _configuration.GetConnectionString("LiMan.GLS"); string connStrDB = _configuration.GetConnectionString("LiMan.DB"); if (string.IsNullOrEmpty(connStrDB) || string.IsNullOrEmpty(connStrGLS)) { _logger.LogError("Almost one ConnString empty!"); } else { dbControllerGLS = new LiMan.GLS.Controllers.LicManController(configuration); dbControllerNext = new LiMan.DB.Controllers.DbController(configuration); _logger.LogInformation("DbControllers OK"); } } #endregion Public Constructors #region Public Methods public async Task> ApplicazioniGLSGetAll() { List dbResult = new List(); string cacheKey = mHash("GLS:Applicazioni"); string rawData; var redisDataList = await distributedCache.GetAsync(cacheKey); if (redisDataList != null) { rawData = Encoding.UTF8.GetString(redisDataList); dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbControllerGLS.GetApplicazioni(); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per ApplicazioniGLSGetAll: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); } public async Task ApplicazioniGLSUpdate(GLS.DatabaseModels.AnagApplicazioni currItem) { bool done = false; try { done = dbControllerGLS.UpdateApplicazioni(currItem); await InvalidateAllCache(); } catch (Exception exc) { Log.Error($"Eccezione in ApplicazioniGLSUpdate:{Environment.NewLine}{exc}"); } return await Task.FromResult(done); } public async Task> ApplicazioniNextGetAll() { List dbResult = new List(); string cacheKey = mHash("Next:Applicazioni"); string rawData; var redisDataList = await distributedCache.GetAsync(cacheKey); if (redisDataList != null) { rawData = Encoding.UTF8.GetString(redisDataList); dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbControllerNext.GetApplicazioni(); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per ApplicazioniNextGetAll: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); } public async Task ApplicazioniNextUpdate(ApplicativoModel currItem) { bool done = false; try { done = dbControllerNext.ApplicazioniNextUpdate(currItem); await InvalidateAllCache(); } catch (Exception exc) { Log.Error($"Eccezione in ApplicazioniNextUpdate:{Environment.NewLine}{exc}"); } return done; } public async Task ApplicazioniHasChild(string CodApp) { bool dbResult = false; string cacheKey = mHash($"Next:Applicazioni:hasChild:{CodApp}"); string rawData; var redisDataList = await distributedCache.GetAsync(cacheKey); if (redisDataList != null) { rawData = Encoding.UTF8.GetString(redisDataList); dbResult = JsonConvert.DeserializeObject(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbControllerNext.ApplicazioniHasChild(CodApp); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per ApplicazioniHasChild: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); } /// /// Elimina il record indicato (se non ci sono record correlati...) /// /// /// public async Task ApplicazioniNextDelete(ApplicativoModel currItem) { bool done = false; try { // controllo NON ci siano record figli... bool hasCHild = dbControllerNext.ApplicazioniHasChild(currItem.CodApp); if (!hasCHild) { done = dbControllerNext.ApplicazioniNextDelete(currItem); await InvalidateAllCache(); } } catch (Exception exc) { Log.Error($"Eccezione in ApplicazioniNextDelete:{Environment.NewLine}{exc}"); } return done; } /// /// Effettua sblocco di una licenza impostando data veto a oggi /// /// /// public async Task AttivazioneUnlock(int idxSubLic) { bool fatto = dbControllerNext.AttivazioniUnlock(idxSubLic); await Task.Delay(1); return fatto; } /// /// Recupera attivazioni data licenza /// /// /// public async Task> AttivazioniGetByLic(int IdxLic) { Stopwatch stopWatch = new Stopwatch(); List dbResult = new List(); stopWatch.Start(); dbResult = dbControllerNext.AttivazioniGetByLic(IdxLic); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per AttivazioniGetByLic: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Recupera elenco Claim dato UserID /// /// /// public async Task> AuthClaimByUserID(int userID) { string source = "DB"; List? dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Auth:Claims:UID:{userID}"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbControllerNext.AuthClaimByUserID(userID); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, LongCache); // per evitare loopback uso deserialize... var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult != null) { dbResult = tempResult; } } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"AuthClaimByUserID | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during AuthClaimByUserID:{Environment.NewLine}{exc}"); } return dbResult; } /// /// Recupera elenco Claim dato UserName /// /// /// public async Task> AuthClaimByUserName(string userName) { string source = "DB"; List? dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Auth:Claims:UName:{userName}"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbControllerNext.AuthClaimByUserName(userName); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); // per evitare loopback uso deserialize... var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult != null) { dbResult = tempResult; } } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"AuthClaimByUserName | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during AuthClaimByUserName:{Environment.NewLine}{exc}"); } //return await Task.FromResult(dbResult); return dbResult; } /// /// Rimozione del Claim (Role Utente) /// /// /// public async Task AuthClaimRemove(AuthClaimModel newRec) { bool fatto = dbControllerNext.AuthClaimRemove(newRec); await FlushRedisCache(); return fatto; } /// /// Upsesrt del Claim di auth utente /// /// /// public async Task AuthClaimUpsert(AuthClaimModel newRec) { bool fatto = dbControllerNext.AuthClaimUpsert(newRec); await FlushRedisCache(); return fatto; } /// /// Rimozione dei roles x utente /// /// /// public async Task AuthRoleResetUser(int UserId) { bool fatto = dbControllerNext.AuthRoleResetUser(UserId); await FlushRedisCache(); return fatto; } /// /// Recupera elenco Roles (completo) /// /// public async Task> AuthRolesGetAll() { string source = "DB"; List? dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Auth:Roles"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbControllerNext.AuthRolesGetAll(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); // per evitare loopback uso deserialize... var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult != null) { dbResult = tempResult; } } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"AuthRolesGetAll | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during AuthRolesGetAll:{Environment.NewLine}{exc}"); } //return await Task.FromResult(dbResult); return dbResult; } /// /// Upsert del ROLE /// /// /// public async Task AuthRoleUpsert(AuthRoleModel newRec) { bool fatto = dbControllerNext.AuthRoleUpsert(newRec); await FlushRedisCache(); return fatto; } /// /// Recupera elenco Utenti (tutti) /// /// public async Task> AuthUserAll() { string source = "DB"; List? dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Auth:UsersList"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbControllerNext.AuthUserAll(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); // per evitare loopback uso deserialize... var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult != null) { dbResult = tempResult; } } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"AuthUserAll | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during AuthUserAll:{Environment.NewLine}{exc}"); } return dbResult; } /// /// Recupera elenco Utenti UserName (idealmente 1...) /// /// /// public async Task> AuthUserGetFilt(string userName) { string source = "DB"; List? dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Auth:User:{userName}"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbControllerNext.AuthUserGetFilt(userName); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); // per evitare loopback uso deserialize... var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult != null) { dbResult = tempResult; } } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"AuthUserGetFilt | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during AuthUserGetFilt:{Environment.NewLine}{exc}"); } //return await Task.FromResult(dbResult); return dbResult; } /// /// Upsert AuthUser /// /// /// public async Task AuthUserUpsert(AuthUserModel newRec) { bool fatto = dbControllerNext.AuthUserUpsert(newRec); await FlushRedisCache(); return fatto; } public async Task DbForceMigrate() { return await Task.FromResult(dbControllerGLS.DbForceMigrate()); } public void Dispose() { // Clear database controller dbControllerGLS.Dispose(); } /// /// Elenco file registrati dato ticket id /// /// Identificativo del ticket /// public async Task> FileGetFilt(int idxTicket) { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbControllerNext.FileGetFilt(idxTicket); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per FileGetFilt: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Refresh globale cache redis /// /// public async Task FlushRedisCache() { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); await Task.Delay(1); RedisValue pattern = new RedisValue($"{Const.rKeyConfig}:*"); bool answ = await ExecFlushRedisPattern(pattern); UserClaimsLUT = new Dictionary(); stopWatch.Stop(); Log.Debug($"FlushRedisCache in {stopWatch.Elapsed.TotalMilliseconds} ms"); return answ; } public async Task> InstallazioniGLSGetAll() { List dbResult = new List(); string cacheKey = mHash("GLS:Installazioni"); string rawData; var redisDataList = await distributedCache.GetAsync(cacheKey); if (redisDataList != null) { rawData = Encoding.UTF8.GetString(redisDataList); dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbControllerGLS.GetInstallazioni(); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per InstallazioniGLSGetAll: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); } public async Task InstallazioniGLSUpdate(GLS.DatabaseModels.AnagInstallazioni currItem) { bool done = false; try { done = dbControllerGLS.UpdateInstallazioni(currItem); await InvalidateAllCache(); } catch (Exception exc) { Log.Error($"Eccezione in InstallazioniGLSUpdate:{Environment.NewLine}{exc}"); } return await Task.FromResult(done); } public async Task> InstallazioniNextGetAll() { List dbResult = new List(); string cacheKey = mHash("Next:Installazioni"); string rawData; var redisDataList = await distributedCache.GetAsync(cacheKey); if (redisDataList != null) { rawData = Encoding.UTF8.GetString(redisDataList); dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbControllerNext.GetInstallazioni(); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per InstallazioniNextGetAll: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); } public async Task InstallazioniNextUpdate(InstallazioneModel currItem) { bool done = false; try { done = dbControllerNext.UpsertInstallazione(currItem); await InvalidateAllCache(); } catch (Exception exc) { Log.Error($"Eccezione in InstallazioniNextUpdate:{Environment.NewLine}{exc}"); } return await Task.FromResult(done); } /// /// invalida tutta la cache in caso di update /// /// public async Task InvalidateAllCache() { await distributedCache.RemoveAsync(mHash("GLS:Applicazioni")); await distributedCache.RemoveAsync(mHash("Next:Applicazioni")); await distributedCache.RemoveAsync(mHash("GLS:Installazioni")); await distributedCache.RemoveAsync(mHash("Next:Installazioni")); await distributedCache.RemoveAsync(mHash("GLS:Licenze")); await distributedCache.RemoveAsync(mHash("Next:Licenze")); //await distributedCache.RemoveAsync(mHash("SUPPL:List")); //await distributedCache.RemoveAsync(mHash("TRANSP:List")); //await distributedCache.RemoveAsync(mHash("WEEKPLAN:List")); } /// /// Trasferisce una licenza da GLS a Next come LOG di una licenza scaduta /// /// /// public async Task LicenzaLogGlsNext(GLS.DatabaseModels.LicenzeAttive currItem, int IdxLicNext) { bool done = false; var currLicenza = dbControllerNext.GetLicenza(IdxLicNext); // step 1: converto licenza, faccio upsert var logLicNext = new LogLicenzaModel() { CodApp = currItem.ApplicativoNavigation.Applicativo, CodInst = currItem.InstallazioneNavigation.Installazione, Chiave = currItem.Licenza, NumLicenze = currItem.NumLicenze, Scadenza = currItem.Scadenza, Descrizione = currItem.ApplicativoNavigation.Descrizione, Tipo = TipoLicenza.GLS, IdxLic = IdxLicNext, Locked = true }; bool step1 = dbControllerNext.UpsertLogLic(logLicNext); if (currLicenza != null && step1) { // step 2: disattivo vecchia licenza currItem.Locked = true; done = dbControllerGLS.UpdateLicenze(currItem); } return await Task.FromResult(done); } /// /// Trasferisce una licenza da GLS a Next /// /// /// public async Task LicenzaTransferGlsNext(GLS.DatabaseModels.LicenzeAttive currItem) { bool done = false; // step 1: controllo applicazione esistente ApplicativoModel appNext = new ApplicativoModel() { CodApp = currItem.ApplicativoNavigation.Applicativo, Descrizione = currItem.ApplicativoNavigation.Descrizione }; bool step1 = dbControllerNext.ApplicazioniNextUpdate(appNext); // step 2: controllo installazione esistente var instNext = new InstallazioneModel() { Cliente = currItem.InstallazioneNavigation.Installazione, CodInst = currItem.InstallazioneNavigation.Installazione, Contatto = currItem.InstallazioneNavigation.Contatto, Email = currItem.InstallazioneNavigation.Email, Descrizione = currItem.ApplicativoNavigation.Descrizione }; bool step2 = dbControllerNext.UpsertInstallazione(instNext); // step 3: converto licenza, faccio upsert var licNext = new LicenzaModel() { CodApp = currItem.ApplicativoNavigation.Applicativo, CodInst = currItem.InstallazioneNavigation.Installazione, Chiave = currItem.Licenza, NumLicenze = currItem.NumLicenze, Scadenza = currItem.Scadenza, Descrizione = currItem.ApplicativoNavigation.Descrizione, Tipo = TipoLicenza.GLS, Enigma = "", Payload = "", DataEnigma = DateTime.Now }; bool step3 = dbControllerNext.UpsertLicenza(licNext); if (step1 && step2 && step3) { // step 4: disattivo vecchia licenza currItem.Locked = true; done = dbControllerGLS.UpdateLicenze(currItem); } return await Task.FromResult(done); } public async Task> LicenzeGLSGetAll() { List dbResult = new List(); string cacheKey = mHash("GLS:Licenze"); string rawData; var redisDataList = await distributedCache.GetAsync(cacheKey); if (redisDataList != null) { rawData = Encoding.UTF8.GetString(redisDataList); dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbControllerGLS.GetLicenze(); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per LicenzeGLSGetAll: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); } /// /// Recupera licenze SENZA cache /// /// /// public async Task> LicenzeGLSGetFilt(SelectGLS CurrFilter) { Stopwatch stopWatch = new Stopwatch(); List dbResult = new List(); stopWatch.Start(); dbResult = dbControllerGLS.GetLicenzeFilt(CurrFilter.OnlyActive, CurrFilter.OnlyUnlock, CurrFilter.ApplicazioneSel, CurrFilter.InstallazioneSel); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per LicenzeGLSGetFilt: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } public async Task LicenzeGLSUpdate(GLS.DatabaseModels.LicenzeAttive currItem) { bool done = false; #if false try { done = dbControllerGLS.UpdateApplicazioni(currItem); await InvalidateAllCache(); } catch (Exception exc) { Log.Error($"Eccezione in ApplicazioniUpdate:{Environment.NewLine}{exc}"); } #endif return await Task.FromResult(done); } public async Task> LicenzeNextGetAll() { List dbResult = new List(); string cacheKey = mHash("Next:Licenze"); string rawData; var redisDataList = await distributedCache.GetAsync(cacheKey); if (redisDataList != null) { rawData = Encoding.UTF8.GetString(redisDataList); dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbControllerNext.GetLicenze(); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per LicenzeNextGetAll: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); } /// /// Recupera licenze SENZA cache /// /// /// public async Task> LicenzeNextGetFilt(SelectNext CurrFilter) { Stopwatch stopWatch = new Stopwatch(); List dbResult = new List(); stopWatch.Start(); dbResult = dbControllerNext.GetLicenzeFilt(CurrFilter.OnlyActive, CurrFilter.ApplicazioneSel, CurrFilter.InstallazioneSel); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per LicenzeNextGetFilt: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } public async Task LicenzeNextUpdate(LicenzaModel currItem) { bool done = false; // chiamo Log licenza + update insieme try { done = dbControllerNext.UpsertLicenza(currItem); await InvalidateAllCache(); } catch (Exception exc) { Log.Error($"Eccezione in ApplicazioniUpdate:{Environment.NewLine}{exc}"); } return await Task.FromResult(done); } public async Task ReleaseDelete(ReleaseModel rec2del) { bool fatto = dbControllerNext.ReleaseDelete(rec2del); await FlushRedisCache(); return fatto; } /// /// Elenco Release dato Applicativo /// /// Codice Applicazione /// public async Task> ReleaseGetByApp(string CodApp) { string source = "DB"; List? dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:App:AllRel:{CodApp}"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbControllerNext.ReleaseGetByApp(CodApp); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, LongCache); // per evitare loopback uso deserialize... var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult != null) { dbResult = tempResult; } } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"ReleaseGetByApp | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during ReleaseGetByApp:{Environment.NewLine}{exc}"); } return dbResult; #if false await Task.Delay(1); List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbControllerNext.ReleaseGetByApp(CodApp); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per ReleaseGetByApp | {CodApp} | {ts.TotalMilliseconds} ms"); return dbResult; #endif } /// /// Ultima Release dato Applicativo VALIDA (= rilasciata) /// /// Codice Applicazione /// public async Task ReleaseLastGetByApp(string CodApp) { string answ = ""; RedisKey currKey = $"{Const.rKeyConfig}:App:CurrRel"; var rawVal = await redisDb.HashGetAsync(currKey, CodApp); if (rawVal.HasValue) { answ = $"{rawVal}"; } else { var rawList = await ReleaseGetByApp(CodApp); if (rawList != null) { var lastRel = rawList .Where(x => x.IsReleased) .OrderByDescending(x => x.VersVal) .ThenByDescending(x => x.ReleaseDate) .FirstOrDefault() ?? new ReleaseModel() { CodApp = CodApp }; answ = lastRel.VersNum; // salvo su redis tab... await redisDb.HashSetAsync(currKey, CodApp, answ); } } return answ; } /// /// Elenco Release dato Applicativo + versione minima /// /// Codice Applicazione /// Versione minima richiesta /// public async Task> ReleaseGetByAppVers(string CodApp, string VersMin) { await Task.Delay(1); List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbControllerNext.ReleaseGetByAppVers(CodApp, VersMin); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per ReleaseGetByAppVers | {CodApp} | vers >= {VersMin} | {ts.TotalMilliseconds} ms"); return dbResult; } /// /// Upsert record Release applicazione /// /// /// public async Task ReleaseUpsert(ReleaseModel currItem) { bool done = false; try { done = await dbControllerNext.ReleaseUpsert(currItem); await InvalidateAllCache(); await FlushRedisCache(); } catch (Exception exc) { Log.Error($"Eccezione in ReleaseUpsert:{Environment.NewLine}{exc}"); } return done; } public void rollBackEditGLS(object item) { dbControllerGLS.rollBackEntity(item); } public async Task SendEmail(string destEmail, string oggetto, string corpo) { bool answ = false; try { await _emailSender.SendEmailAsync(destEmail, oggetto, corpo); answ = true; } catch { } return answ; } /// /// Statistiche del LOG chiamate all'API dato filtro /// /// Data minima /// DataMax /// Valore cercato, se "" è tutti /// public async Task> StatsLogCallGetFilt(DateTime DateFrom, DateTime DateTo, string SearchVal = "") { List dbResult = new List(); string cacheKey = mHash($"StatslogCall:{DateFrom:yyyyMMdd}:{DateTo:yyyyMMdd}"); if (!string.IsNullOrEmpty(SearchVal)) { cacheKey += $":{SearchVal}"; } string rawData; var redisDataList = await distributedCache.GetAsync(cacheKey); if (redisDataList != null) { rawData = Encoding.UTF8.GetString(redisDataList); dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); var rawResult = dbControllerNext.StatsLogCallGetFilt(DateFrom, DateTo, SearchVal); dbResult = rawResult .OrderByDescending(x => x.YearRef) .ThenByDescending(x => x.TotCall) .ToList(); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per StatsLogCallGetFilt: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); } /// /// Recupera elenco Tickets filtrato /// /// /// public async Task> TicketsGetAll() { Stopwatch stopWatch = new Stopwatch(); List dbResult = new List(); stopWatch.Start(); dbResult = dbControllerNext.TicketGetAll(false, 1000); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per TicketsGetAll: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Recupera elenco Tickets filtrato /// /// /// public async Task> TicketsGetFilt(SelectNext CurrFilter) { Stopwatch stopWatch = new Stopwatch(); List dbResult = new List(); stopWatch.Start(); dbResult = dbControllerNext.TicketGetFiltAllLic(CurrFilter.OnlyActive, Core.Enum.TipologiaTicket.ND, CurrFilter.ApplicazioneSel, CurrFilter.InstallazioneSel, 1000); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per TicketsGetFilt: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Ricerca ticket filtrati /// /// /// /// /// public async Task> TicketsGetFilt(bool onlyOpen, string CodApp, string CodInst) { Stopwatch stopWatch = new Stopwatch(); List dbResult = new List(); stopWatch.Start(); dbResult = dbControllerNext.TicketGetFilt(onlyOpen, CodApp, CodInst); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per TicketsGetFilt: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Aggiornamentos tato ticket /// /// /// /// public async Task TicketUpdateState(int IdxTicket, StatoRichiesta NewStatus) { bool fatto = false; // inserimento! Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); fatto = dbControllerNext.TicketUpdateState(IdxTicket, NewStatus); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata update con TicketUpdateState: {ts.TotalMilliseconds} ms"); // restituisce elenco return await Task.FromResult(fatto); } /// /// Verifica di un role utente dall'elenco claims... /// /// /// /// public bool UserHasClaim(string userName, string role) { bool answ = false; string keyLUT = $"{userName}_{role}"; if (UserClaimsLUT.ContainsKey(keyLUT)) { answ = UserClaimsLUT[keyLUT]; } else { var pUpd = Task.Run(async () => { var userClaims = await AuthClaimByUserName(userName); if (userClaims != null && userClaims.Count > 0) { answ = userClaims.Where(x => x.RoleNav.Ruolo == role).Any(); } }); pUpd.Wait(); UserClaimsLUT.Add(keyLUT, answ); } return answ; } private Dictionary UserClaimsLUT = new Dictionary(); #endregion Public Methods #region Internal Methods /// /// Effettua sblocco di una licenza impostando data veto a oggi /// /// /// internal async Task AttivazioneDelete(int idxSubLic) { bool fatto = dbControllerNext.AttivazioniDelete(idxSubLic); await Task.Delay(1); return fatto; } #endregion Internal Methods #region Protected Fields protected static JsonSerializerSettings? JSSettings; /// /// Durata cache lunga IN SECONDI /// protected int cacheTtlLong = 60 * 5; /// /// Durata cache breve IN SECONDI /// protected int cacheTtlShort = 60 * 1; /// /// Oggetto per connessione a REDIS /// protected IConnectionMultiplexer redisConn = null!; /// /// Oggetto DB redis da impiegare x chiamate R/W /// protected IDatabase redisDb = null!; protected Random rnd = new Random(); #endregion Protected Fields #region Protected Properties /// /// Durata cache breve (1 min circa + perturbazione percentuale +/-10%) /// protected TimeSpan FastCache { get => TimeSpan.FromSeconds(cacheTtlShort * rnd.Next(900, 1100) / 1000); } /// /// Durata cache lunga (+ perturbazione percentuale +/-10%) /// protected TimeSpan LongCache { get => TimeSpan.FromSeconds(cacheTtlLong * rnd.Next(900, 1100) / 1000); } /// /// Durata cache MOLTO breve (10 sec circa + perturbazione percentuale +/-10%) /// protected TimeSpan UltraFastCache { get => TimeSpan.FromSeconds(cacheTtlShort / 6 * rnd.Next(900, 1100) / 1000); } /// /// Durata cache MOLTO lunga (+ perturbazione percentuale +/-10%) /// protected TimeSpan UltraLongCache { get => TimeSpan.FromSeconds(cacheTtlLong * 10 * rnd.Next(900, 1100) / 1000); } #endregion Protected Properties #region Protected Methods /// /// Esegue flush memoria redis dato pattern /// /// /// protected async Task ExecFlushRedisPattern(RedisValue pattern) { bool answ = false; var listEndpoints = redisConn.GetEndPoints(); foreach (var endPoint in listEndpoints) { //var server = redisConnAdmin.GetServer(listEndpoints[0]); var server = redisConn.GetServer(endPoint); if (server != null) { var keyList = server.Keys(redisDb.Database, pattern); foreach (var item in keyList) { await redisDb.KeyDeleteAsync(item); } answ = true; } } return answ; } protected string getCacheKey(string TableName, SelectData CurrFilter) { string answ = $"{TableName}:D_{CurrFilter.DateStart:yyyyMMddHHmm}_{CurrFilter.DateEnd:yyyyMMddHHmm}"; return answ; } #endregion Protected Methods #region Private Fields private static IConfiguration _configuration; private static ILogger _logger; private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); private readonly IEmailSender _emailSender; private readonly IDistributedCache distributedCache; private readonly IMemoryCache memoryCache; /// /// Durata assoluta massima della cache IN SECONDI /// private int chAbsExp = 60 * 5; /// /// Durata della cache IN SECONDI in modalità inattiva (non acceduta) prima di venire /// rimossa NON estende oltre il tempo massimo di validità della cache (chAbsExp) /// private int chSliExp = 60 * 1; #endregion Private Fields #region Private Methods /// /// Hash Redis contenente i dati MP di una specifico TYPE (es StatusMacchina, /// StateMachineIngressi, ...) /// /// /// private static string mHash(string dataType) { return $"DATA:{dataType}"; } private DistributedCacheEntryOptions cacheOpt(bool fastCache) { var numSecAbsExp = fastCache ? chAbsExp : chAbsExp * 10; var numSecSliExp = fastCache ? chSliExp : chSliExp * 10; return new DistributedCacheEntryOptions().SetAbsoluteExpiration(DateTime.Now.AddSeconds(numSecAbsExp)).SetSlidingExpiration(TimeSpan.FromSeconds(numSecSliExp)); } #endregion Private Methods } }