using Microsoft.AspNetCore.Identity.UI.Services; using Newtonsoft.Json; using NLog; using StackExchange.Redis; using System.Diagnostics; using WebDoorCreator.Data.Controllers; using WebDoorCreator.Data.DbModels; using EgwCoreLib.Razor.Data; using WebDoorCreator.Data.DTO; using WebDoorCreator.Data; namespace WebDoorCreator.UI.Data { public class WebDoorCreatorService { #region Public Fields public static WebDoorCreatorController dbController = null!; #endregion Public Fields #region Public Constructors public WebDoorCreatorService(IConfiguration configuration, IConnectionMultiplexer redisConnMult, IEmailSender emailSender) { _configuration = configuration; _emailSender = emailSender; // 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 }; // cod app CodApp = _configuration["CodApp"]; // Conf DB string connStr = _configuration.GetConnectionString("WDC.DB"); if (string.IsNullOrEmpty(connStr)) { Log.Info("ConnString empty!"); } else { dbController = new WebDoorCreatorController(configuration); } Log.Info("Avviata classe WebDoorCreatorService"); } #endregion Public Constructors #region Public Properties public string CodApp { get; set; } = ""; #endregion Public Properties #region Public Methods #region Company methods /// /// Company list /// public async Task?> CompanyGetAll() { string source = "DB"; List? dbResult = new List(); // cerco da cache string currKey = rKeyCompany; 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 = dbController.CompanyAll(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"CompanyGetAll | {source} in: {ts.TotalMilliseconds} ms"); return dbResult; } /// /// Update company /// /// /// public async Task CompanyAddMod(CompanyModel currRec) { var dbResult = await dbController.CompanyAddMod(currRec); // elimino cache redis... RedisValue pattern = new RedisValue($"{rKeyCompany}"); bool answ = await ExecFlushRedisPattern(pattern); await Task.Delay(1); return dbResult; } #endregion Company methods /*----------------------------------------------------------------------------------------------------------------------*/ #region Cache methods /// /// Esegue flush memoria redis dato pattern /// /// /// private 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; } public async Task FlushRedisCache() { await Task.Delay(1); RedisValue pattern = new RedisValue($"{redisBaseAddr}"); bool answ = await ExecFlushRedisPattern(pattern); return answ; } #endregion Cache methods /*----------------------------------------------------------------------------------------------------------------------*/ #region Security Methods public string DecriptData(string encData) { return SteamCrypto.DecryptString(encData, passPhrase); } public string EncriptData(string rawData) { return SteamCrypto.EncryptString(rawData, passPhrase); } #endregion Security Methods /*----------------------------------------------------------------------------------------------------------------------*/ #region User Methods /// /// Users roles list /// public async Task?> GetUserView() { string source = "DB"; List? dbResult = new List(); // cerco da cache string currKey = rKeyUsersView; 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 = dbController.GetUserView(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"GetUserView | {source} in: {ts.TotalMilliseconds} ms"); return dbResult; } /// /// Users roles list /// public async Task?> GetUsersAll() { string source = "DB"; List? dbResult = new List(); // cerco da cache string currKey = rKeyUsers; 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 = dbController.GetUsersAll(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"GetUsersAll | {source} in: {ts.TotalMilliseconds} ms"); return dbResult; } /// /// Users roles list /// public async Task GetUsersById(string userId) { string source = "DB"; AspNetUsers dbResult = new AspNetUsers(); // cerco da cache string currKey = $"{rKeyUsers}:{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 AspNetUsers(); } else { dbResult = tempResult; } } else { dbResult = dbController.GetUsersById(userId); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new AspNetUsers(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"GetUsersById | {source} in: {ts.TotalMilliseconds} ms"); return dbResult; } #endregion User Methods /*----------------------------------------------------------------------------------------------------------------------*/ #region Roles Methods /// /// roles list /// public async Task?> GetRolesAll() { string source = "DB"; List? dbResult = new List(); // cerco da cache string currKey = rKeyRoles; 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 = dbController.GetRolesAll(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"GetRolesAll | {source} in: {ts.TotalMilliseconds} ms"); return dbResult; } #endregion Roles Methods /*----------------------------------------------------------------------------------------------------------------------*/ #region Order status Methods public async Task?> GetOrderStatus(int companyId, int orderStatus, DateTime dataFrom, DateTime dataTo) { string source = "DB"; List? dbResult = new List(); // cerco da cache string currKey = rKeyOrderStatus; 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 = dbController.GetOrderStatus(companyId, orderStatus, dataFrom, dataTo); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"GetOrderStatus | {source} in: {ts.TotalMilliseconds} ms"); return dbResult; } #endregion Order status Methods /*----------------------------------------------------------------------------------------------------------------------*/ #region Order Methods /// /// Add new order /// /// /// public async Task OrderAdd(OrderModel currRec) { var dbResult = await dbController.OrderAdd(currRec); // elimino cache redis... RedisValue pattern = new RedisValue($"{rKeyOrderStatus}"); bool answ = await ExecFlushRedisPattern(pattern); await Task.Delay(1); return dbResult; } #endregion Order Methods /*----------------------------------------------------------------------------------------------------------------------*/ #region Door Methods /// /// Doors list by orderId /// public async Task?> DoorsGetByOrderId(int orderId) { string source = "DB"; List? dbResult = new List(); // cerco da cache string currKey = $"{rKeyDoor}:{orderId}"; 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 = dbController.DoorsGetByOrderId(orderId); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"DoorsGetByOrderId | {source} in: {ts.TotalMilliseconds} ms"); return dbResult; } /// /// Update or add door /// /// /// public async Task DoorsAddMod(DoorModel currRec) { var dbResult = await dbController.DoorUpsert(currRec); // elimino cache redis dati porta... RedisValue pattern = new RedisValue($"{rKeyDoor}"); bool answ = await ExecFlushRedisPattern(pattern); // elimino cache redis dati ordine... pattern = new RedisValue($"{rKeyOrderStatus}"); answ = await ExecFlushRedisPattern(pattern); await Task.Delay(1); return dbResult; } #endregion Door Methods #endregion Public Methods #region Protected Fields #region Private Properties /// /// Durata cache lunga (+ perturbazione percentuale +/-10%) /// private TimeSpan FastCache { get => TimeSpan.FromSeconds(cacheTtlShort * rnd.Next(900, 1100) / 1000); } /// /// Durata cache lunga (+ perturbazione percentuale +/-10%) /// private TimeSpan LongCache { get => TimeSpan.FromSeconds(cacheTtlLong * rnd.Next(900, 1100) / 1000); } /// /// Durata cache lunga (+ perturbazione percentuale +/-10%) /// private TimeSpan UltraLongCache { get => TimeSpan.FromSeconds(cacheTtlLong * 10 * rnd.Next(900, 1100) / 1000); } #endregion Private Properties protected const string passPhrase = "9eb4660f-8753-46bc-b23b-08759ba03fe9"; //#region Protected Fields protected const string redisBaseAddr = "WDC"; //#endregion Public Methods protected const string rKeyCompany = $"{redisBaseAddr}:Cache:Company"; protected const string rKeyOrderStatus = $"{redisBaseAddr}:Cache:OrderStatus"; protected const string rKeyUsers = $"{redisBaseAddr}:Cache:Users"; protected const string rKeyUsersView = $"{redisBaseAddr}:Cache:UsersView"; protected const string rKeyRoles = $"{redisBaseAddr}:Cache:Roles"; protected const string rKeyDoor = $"{redisBaseAddr}:Cache:Doors"; protected Random rnd = new Random(); #endregion Protected Fields #region Private Fields private static IConfiguration _configuration = null!; private static JsonSerializerSettings? JSSettings; private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); private readonly IEmailSender _emailSender; /// /// Durata cache lunga IN SECONDI /// private int cacheTtlLong = 60 * 5; /// /// Durata cache breve IN SECONDI /// private int cacheTtlShort = 60 * 1; /// /// Oggetto per connessione a REDIS /// private IConnectionMultiplexer redisConn; //ISubscriber sub = redis.GetSubscriber(); /// /// Oggetto DB redis da impiegare x chiamate R/W /// private IDatabase redisDb = null!; #endregion Private Fields } }