Files
GPW/GPW.CORE.UI/Data/GpwDataService.cs
T
2022-01-17 18:48:34 +01:00

725 lines
28 KiB
C#

using GPW.CORE.Data;
using GPW.CORE.Data.DbModels;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using NLog;
using RestSharp;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
using System.Web;
namespace GPW.CORE.UI.Data
{
public class GpwDataService : IDisposable
{
#region Private Fields
private static IConfiguration _configuration = null!;
private static ILogger<GpwDataService> _logger = null!;
private static JsonSerializerSettings? JSSettings;
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
//private readonly IEmailSender _emailSender;
//private readonly UserManager<IdentityUser> _userManager;
private readonly IDistributedCache distributedCache;
private readonly IMemoryCache memoryCache;
private List<string> cachedDataList = new List<string>();
/// <summary>
/// Durata assoluta massima della cache IN SECONDI
/// </summary>
private int chAbsExp = 60 * 5;
/// <summary>
/// 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)
/// </summary>
private int chSliExp = 60 * 1;
#endregion Private Fields
#region Protected Fields
protected const string rKeyAKV = "Cache:AKV";
protected const string rKeyCalcOreProj = "Cache:CalcOreProj";
protected const string rKeyCliAll = "Cache:CliAll";
protected const string rKeyDailyData = "Cache:DailyData";
protected const string rKeyDipendenti = "Cache:Dipendenti";
protected const string rKeyFasiAll = "Cache:FasiAll";
protected const string rKeyGrpAll = "Cache:GrpAll";
protected const string rKeyParetoRegAtt = "Cache:ParetoRegAtt";
protected const string rKeyProjAll = "Cache:ProjAll";
protected const string rKeyRilTemp = "Cache:RilTemp";
protected const string rKeyVC19 = "Cache:VC19";
protected const string rKeyWeekStats = "Cache:WeekStats";
protected static string connStringBBM = "";
#endregion Protected Fields
#region Public Fields
public static CORE.Data.Controllers.GPWController dbController = null!;
#endregion Public Fields
#region Public Constructors
public GpwDataService(IConfiguration configuration, ILogger<GpwDataService> logger, IMemoryCache memoryCache, IDistributedCache distributedCache)
{
_logger = logger;
_configuration = configuration;
// conf cache
this.memoryCache = memoryCache;
this.distributedCache = distributedCache;
// 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("GPW.DB");
if (string.IsNullOrEmpty(connStr))
{
_logger.LogError("ConnString empty!");
}
else
{
dbController = new CORE.Data.Controllers.GPWController(configuration);
}
}
#endregion Public Constructors
#region Public Properties
public string CodApp { get; set; } = "";
#endregion Public Properties
#region Private Methods
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));
}
private DistributedCacheEntryOptions cacheOpt(int multFact)
{
var numSecAbsExp = chAbsExp * multFact;
var numSecSliExp = chSliExp * multFact;
return new DistributedCacheEntryOptions().SetAbsoluteExpiration(DateTime.Now.AddSeconds(numSecAbsExp)).SetSlidingExpiration(TimeSpan.FromSeconds(numSecSliExp));
}
#endregion Private Methods
#region Protected Methods
/// <summary>
/// Registra in cache chiave se non fosse già in elenco
/// </summary>
/// <param name="newKey"></param>
protected void trackCache(string newKey)
{
if (!cachedDataList.Contains(newKey))
{
cachedDataList.Add(newKey);
}
}
#endregion Protected Methods
#region Public Methods
/// <summary>
/// Elenco AKV
/// </summary>
public async Task<List<AnagKeyValueModel>> AKVList()
{
List<AnagKeyValueModel> dbResult = new List<AnagKeyValueModel>();
// cerco da cache
string currKey = rKeyAKV;
trackCache(currKey);
string rawData;
var redisDataList = await distributedCache.GetAsync(currKey);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<AnagKeyValueModel>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.AnagKeyValGetAll();
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(currKey, redisDataList, cacheOpt(500));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per AKVList: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<AnagKeyValueModel>();
}
return await Task.FromResult(dbResult);
}
/// <summary>
/// Recupera l'elenco fasi (tutte)
/// </summary>
/// <returns></returns>
public async Task<List<AnagClientiModel>> AnagClientiAll()
{
List<AnagClientiModel>? dbResult = new List<AnagClientiModel>();
string currKey = $"{rKeyCliAll}";
string rawData;
var redisDataList = await distributedCache.GetAsync(currKey);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<AnagClientiModel>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.AnagClientiAll();
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(currKey, redisDataList, cacheOpt(true));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per AnagClientiAll: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<AnagClientiModel>();
}
return await Task.FromResult(dbResult);
}
/// <summary>
/// Recupera l'elenco fasi (tutte)
/// </summary>
/// <returns></returns>
public async Task<List<AnagFasiModel>> AnagFasiAll()
{
List<AnagFasiModel>? dbResult = new List<AnagFasiModel>();
string currKey = $"{rKeyFasiAll}";
string rawData;
var redisDataList = await distributedCache.GetAsync(currKey);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<AnagFasiModel>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.AnagFasiAll();
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(currKey, redisDataList, cacheOpt(true));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per AnagFasiAll: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<AnagFasiModel>();
}
return await Task.FromResult(dbResult);
}
/// <summary>
/// Recupera info x una specifica FASE
/// </summary>
/// <returns></returns>
public async Task<AnagFasiModel?> AnagFasiSearch(int idxFase)
{
AnagFasiModel dbResult = new AnagFasiModel();
var rawData = await AnagFasiAll();
if (rawData != null)
{
dbResult = rawData.FirstOrDefault(x => x.IdxFase == idxFase);
}
return await Task.FromResult(dbResult);
}
/// <summary>
/// Recupera l'elenco gruppi (tutti)
/// </summary>
/// <returns></returns>
public async Task<List<AnagGruppiModel>> AnagGruppiAll()
{
List<AnagGruppiModel>? dbResult = new List<AnagGruppiModel>();
string currKey = $"{rKeyGrpAll}";
string rawData;
var redisDataList = await distributedCache.GetAsync(currKey);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<AnagGruppiModel>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.AnagGruppiAll();
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(currKey, redisDataList, cacheOpt(true));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per AnagGruppiAll: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<AnagGruppiModel>();
}
return await Task.FromResult(dbResult);
}
/// <summary>
/// Recupera l'elenco progetti (tutti)
/// </summary>
/// <returns></returns>
public async Task<List<AnagProgettiModel>> AnagProjAll()
{
List<AnagProgettiModel>? dbResult = new List<AnagProgettiModel>();
string currKey = $"{rKeyProjAll}";
string rawData;
var redisDataList = await distributedCache.GetAsync(currKey);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<AnagProgettiModel>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.AnagProjAll();
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(currKey, redisDataList, cacheOpt(true));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per AnagProjAll: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<AnagProgettiModel>();
}
return await Task.FromResult(dbResult);
}
/// <summary>
/// Vista dati per progetto con totalizzaizone ore budget/real
/// </summary>
/// <param name="idxProj"></param>
/// <returns></returns>
public async Task<CalcOreProgettiModel> CalcOreProj(int idxProj)
{
CalcOreProgettiModel? dbResult = new CalcOreProgettiModel();
string currKey = $"{rKeyCalcOreProj}:{idxProj}";
trackCache(currKey);
string rawData;
var redisDataList = await distributedCache.GetAsync(currKey);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<CalcOreProgettiModel>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.CalcOreProj(idxProj);
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(currKey, redisDataList, cacheOpt(true));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per CalcOreProj: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new CalcOreProgettiModel();
}
return await Task.FromResult(dbResult);
}
/// <summary>
/// Recupera l'elenco dei controlli VC19 nel periodo indicato x dipendente
/// </summary>
/// <param name="idxDipendente">Dipendente interessato</param>
/// <param name="dtInizio">Data di riferimento (ultima/corrente)</param>
/// <param name="dtFine">NUm settimane precedenti da recuperare</param>
/// <returns></returns>
public async Task<List<CheckVc19Model>> CheckVC19List(int idxDipendente, DateTime dtInizio, DateTime dtFine)
{
List<CheckVc19Model>? dbResult = new List<CheckVc19Model>();
string currKey = $"{rKeyVC19}:{dtInizio:yyyyMMdd}:{dtFine:yyyMMdd}";
trackCache(currKey);
string rawData;
var redisDataList = await distributedCache.GetAsync(currKey);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<CheckVc19Model>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.CheckVC19List(idxDipendente, dtInizio, dtFine);
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(currKey, redisDataList, cacheOpt(true));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per CheckVC19List: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<CheckVc19Model>();
}
return await Task.FromResult(dbResult);
}
/// <summary>
/// Recupera l'elenco dei dettagli giornalieri attività di un dipendente, dato periodo riferimento
/// </summary>
/// <param name="idxDipendente">Dipendente interessato</param>
/// <param name="dtInizio">Data di riferimento (ultima/corrente)</param>
/// <param name="dtFine">NUm settimane precedenti da recuperare</param>
/// <returns></returns>
public async Task<List<CORE.Data.DTO.DailyDataDTO>> DailyDetails(int idxDipendente, DateTime dtInizio, DateTime dtFine)
{
List<CORE.Data.DTO.DailyDataDTO>? dbResult = new List<CORE.Data.DTO.DailyDataDTO>();
string currKey = $"{rKeyDailyData}:{idxDipendente}:{dtInizio.ToString("yyyy-MM-dd")}:{dtFine.ToString("yyyy-MM-dd")}";
trackCache(currKey);
string rawData;
var redisDataList = await distributedCache.GetAsync(currKey);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<CORE.Data.DTO.DailyDataDTO>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.DailyDetails(idxDipendente, dtInizio, dtFine);
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(currKey, redisDataList, cacheOpt(true));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per DailyDetails: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<CORE.Data.DTO.DailyDataDTO>();
}
return await Task.FromResult(dbResult);
}
public async Task<List<DipendentiModel>> DipendentiGetAll()
{
List<DipendentiModel>? dbResult = new List<DipendentiModel>();
string rawData;
var redisDataList = await distributedCache.GetAsync(rKeyDipendenti);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<DipendentiModel>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.DipendentiGetAll();
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(rKeyDipendenti, redisDataList, cacheOpt(false));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per DipendentiGetAll: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<DipendentiModel>();
}
return await Task.FromResult(dbResult);
}
public void Dispose()
{
// Clear database controller
dbController.Dispose();
}
/// <summary>
/// invalida tutta la cache in caso di update
/// </summary>
/// <returns></returns>
public async Task InvalidateAllCache()
{
await distributedCache.RemoveAsync(rKeyDipendenti);
await distributedCache.RemoveAsync(rKeyFasiAll);
foreach (var item in cachedDataList)
{
await distributedCache.RemoveAsync(item);
}
cachedDataList = new List<string>();
}
/// <summary>
/// Invalida la cache corrispondente al apttern fornito
/// </summary>
/// <returns></returns>
public async Task InvalidateCache(string cachePattern)
{
foreach (var item in cachedDataList)
{
if (item.Contains(cachePattern))
{
await distributedCache.RemoveAsync(item);
}
}
}
/// <summary>
/// Statistiche ultime settimane
/// </summary>
/// <param name="idxDipendente"></param>
/// <param name="dtRif"></param>
/// <param name="numWeek"></param>
/// <returns></returns>
public async Task<List<CORE.Data.DTO.WeekStatDTO>> LastWeeks(int idxDipendente, DateTime dtRif, int numWeek)
{
List<CORE.Data.DTO.WeekStatDTO>? dbResult = new List<CORE.Data.DTO.WeekStatDTO>();
string currKey = $"{rKeyWeekStats}:{idxDipendente}:{dtRif.ToString("yyyy-MM-dd")}:{numWeek}";
trackCache(currKey);
string rawData;
var redisDataList = await distributedCache.GetAsync(currKey);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<CORE.Data.DTO.WeekStatDTO>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.WeekOverview(idxDipendente, dtRif, numWeek);
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(currKey, redisDataList, cacheOpt(true));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per LastWeeks: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<CORE.Data.DTO.WeekStatDTO>();
}
return await Task.FromResult(dbResult);
}
/// <summary>
/// Elenco pareto progetti ordinati da filtro
/// </summary>
/// <param name="idxDip"></param>
/// <param name="numDayPrev"></param>
/// <param name="maxResult"></param>
/// <returns></returns>
public async Task<List<ParetoRegAttModel>> ParetoRegAtt(int idxDip, int numDayPrev, int maxResult)
{
List<ParetoRegAttModel>? dbResult = new List<ParetoRegAttModel>();
string currKey = $"{rKeyParetoRegAtt}:{idxDip}:{numDayPrev}:{maxResult}";
DateTime dataFine = DateTime.Today.AddDays(1);
DateTime dataInizio = dataFine.AddDays(-numDayPrev);
string rawData;
var redisDataList = await distributedCache.GetAsync(currKey);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<ParetoRegAttModel>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.ParetoRegAtt(idxDip, dataInizio, dataFine, maxResult);
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(currKey, redisDataList, cacheOpt(true));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per ParetoRegAtt: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<ParetoRegAttModel>();
}
return await Task.FromResult(dbResult);
}
public async Task<bool> RegAttDelete(RegAttivitaModel currItem)
{
bool answ = false;
try
{
dbController.RegAttDelete(currItem);
// invalido la cache...
await InvalidateAllCache();
answ = true;
}
catch
{ }
return answ;
}
public async Task<RegAttivitaModel> RegAttLastByDip(int IdxDipendente)
{
RegAttivitaModel dbResult = dbController.RegAttLastByDip(IdxDipendente);
return await Task.FromResult(dbResult);
}
public async Task<bool> RegAttUpdate(RegAttivitaModel currItem)
{
bool answ = false;
try
{
dbController.RegAttUpdate(currItem);
// invalido la cache...
await InvalidateAllCache();
answ = true;
}
catch
{ }
return answ;
}
/// <summary>
/// Recupera l'elenco dei Rilievi temperatura nel periodo indicato x dipendente
/// </summary>
/// <param name="idxDipendente">Dipendente interessato</param>
/// <param name="dtInizio">Data di riferimento (ultima/corrente)</param>
/// <param name="dtFine">NUm settimane precedenti da recuperare</param>
/// <returns></returns>
public async Task<List<RilievoTempModel>> RilTempList(int idxDipendente, DateTime dtInizio, DateTime dtFine)
{
List<RilievoTempModel>? dbResult = new List<RilievoTempModel>();
string currKey = $"{rKeyRilTemp}:{dtInizio:yyyyMMdd}:{dtFine:yyyMMdd}";
trackCache(currKey);
string rawData;
var redisDataList = await distributedCache.GetAsync(currKey);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<RilievoTempModel>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.RilTempList(idxDipendente, dtInizio, dtFine);
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(currKey, redisDataList, cacheOpt(true));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per RilTempList: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<RilievoTempModel>();
}
return await Task.FromResult(dbResult);
}
public async Task<bool> RilTempUpdate(RilievoTempModel currItem)
{
bool answ = false;
try
{
dbController.RilTempUpdate(currItem);
// invalido la cache...
await InvalidateCache(rKeyRilTemp);
//await InvalidateCache($"{rKeyWeekStats}:{currItem.IdxDipendente}");
await InvalidateCache($"{rKeyDailyData}:{currItem.IdxDipendente}");
answ = true;
}
catch
{ }
return answ;
}
public void rollBackEdit(object item)
{
dbController.rollBackEntity(item);
}
public async Task<bool> TimbratureDelete(TimbratureModel currItem)
{
bool answ = false;
try
{
dbController.TimbratureDelete(currItem);
// invalido la cache...
await InvalidateAllCache();
answ = true;
}
catch
{ }
return answ;
}
public async Task<bool> TimbratureUpdate(TimbratureModel currItem)
{
bool answ = false;
try
{
dbController.TimbratureUpdate(currItem);
// invalido la cache...
await InvalidateAllCache();
answ = true;
}
catch
{ }
return answ;
}
#endregion Public Methods
}
}