434 lines
21 KiB
C#
434 lines
21 KiB
C#
using Microsoft.Extensions.Caching.Distributed;
|
|
using Microsoft.Extensions.Caching.Memory;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Logging;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace MP.Stats.Data
|
|
{
|
|
public class MpStatsService : IDisposable
|
|
{
|
|
#region Private Fields
|
|
|
|
private static IConfiguration _configuration;
|
|
|
|
private static ILogger<MpStatsService> _logger;
|
|
|
|
private static List<MP.Data.DatabaseModels.AzioniUL> ActionsList = new List<MP.Data.DatabaseModels.AzioniUL>();
|
|
|
|
private readonly IDistributedCache distributedCache;
|
|
|
|
private readonly IMemoryCache memoryCache;
|
|
|
|
/// <summary>
|
|
/// Durata assoluta massima della cache
|
|
/// </summary>
|
|
private int chAbsExp = 15;
|
|
|
|
/// <summary>
|
|
/// Durata della cache in modalità inattiva (non acceduta) prima di venire rimossa
|
|
/// NON estende oltre il tempo massimo di validità della cache (chAbsExp)
|
|
/// </summary>
|
|
private int chSliExp = 5;
|
|
|
|
#endregion Private Fields
|
|
|
|
#region Protected Fields
|
|
|
|
protected static string connStringBBM = "";
|
|
|
|
protected static string connStringFatt = "";
|
|
|
|
#endregion Protected Fields
|
|
|
|
#region Public Fields
|
|
|
|
public static MP.Data.Controllers.MpStatsController dbController;
|
|
|
|
#endregion Public Fields
|
|
|
|
#region Public Constructors
|
|
|
|
public MpStatsService(IConfiguration configuration, ILogger<MpStatsService> logger, IMemoryCache memoryCache, IDistributedCache distributedCache)
|
|
{
|
|
_logger = logger;
|
|
_configuration = configuration;
|
|
// conf cache
|
|
this.memoryCache = memoryCache;
|
|
this.distributedCache = distributedCache;
|
|
// conf DB
|
|
string connStr = _configuration.GetConnectionString("Mp.Stats");
|
|
if (string.IsNullOrEmpty(connStr))
|
|
{
|
|
_logger.LogError("ConnString empty!");
|
|
}
|
|
else
|
|
{
|
|
dbController = new MP.Data.Controllers.MpStatsController(configuration);
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.AppendLine($"DbController OK");
|
|
//sb.AppendLine($"CST: {dbController.CustomersCount()} | CNT: {dbController.CountersCount()} | BSK: {dbController.BasketsCount()} | NGT: {dbController.NegotiationsCount()} | DOC: {dbController.DocsCount()} | ITM: {dbController.ItemsCount()} | RES: {dbController.ResourcesCount()}");
|
|
_logger.LogInformation(sb.ToString());
|
|
}
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Private Properties
|
|
|
|
private DistributedCacheEntryOptions cacheOpt
|
|
{
|
|
get
|
|
{
|
|
return new DistributedCacheEntryOptions().SetAbsoluteExpiration(DateTime.Now.AddMinutes(chAbsExp)).SetSlidingExpiration(TimeSpan.FromMinutes(chSliExp));
|
|
}
|
|
}
|
|
|
|
private DistributedCacheEntryOptions cacheOptLong
|
|
{
|
|
get
|
|
{
|
|
return new DistributedCacheEntryOptions().SetAbsoluteExpiration(DateTime.Now.AddMinutes(chAbsExp * 10)).SetSlidingExpiration(TimeSpan.FromMinutes(chSliExp));
|
|
}
|
|
}
|
|
|
|
#endregion Private Properties
|
|
|
|
#region Protected Methods
|
|
|
|
protected string getCacheKey(string TableName, SelectData CurrFilter)
|
|
{
|
|
string answ = $"{TableName}:M_{CurrFilter.IdxMacchina}:AZ_{CurrFilter.Azione}:ART_{CurrFilter.CodArticolo}:KR_{CurrFilter.KeyRichiesta}:O_{CurrFilter.IdxOdl}:D_{CurrFilter.DateStart:yyyyMMddHHmm}_{CurrFilter.DateEnd:yyyyMMddHHmm}";
|
|
return answ;
|
|
}
|
|
|
|
protected string getCacheKeyPaged(string TableName, SelectData CurrFilter)
|
|
{
|
|
string answ = $"{TableName}:M_{CurrFilter.IdxMacchina}:A_{CurrFilter.CodArticolo}:K_{CurrFilter.KeyRichiesta}:O_{CurrFilter.IdxOdl}:D_{CurrFilter.DateStart:yyMMddHHmm}_{CurrFilter.DateEnd:yyMMddHHmm}:R_{CurrFilter.FirstRecord}_{CurrFilter.FirstRecord + CurrFilter.NumRecord}";
|
|
return answ;
|
|
}
|
|
|
|
#endregion Protected Methods
|
|
|
|
#region Public Methods
|
|
|
|
public async Task<List<MP.Data.DatabaseModels.AzioniUL>> ActionsGetAll()
|
|
{
|
|
//return Task.FromResult(dbController.ActionsGetAll());
|
|
List<MP.Data.DatabaseModels.AzioniUL> dbResult = new List<MP.Data.DatabaseModels.AzioniUL>();
|
|
string cacheKey = "MP:STATS:AZIONI_ALL";
|
|
string rawData;
|
|
var redisDataList = await distributedCache.GetAsync(cacheKey);
|
|
if (redisDataList != null)
|
|
{
|
|
rawData = Encoding.UTF8.GetString(redisDataList);
|
|
dbResult = JsonConvert.DeserializeObject<List<MP.Data.DatabaseModels.AzioniUL>>(rawData);
|
|
}
|
|
else
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
dbResult = dbController.ActionsGetAll();
|
|
rawData = JsonConvert.SerializeObject(dbResult);
|
|
redisDataList = Encoding.UTF8.GetBytes(rawData);
|
|
await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
_logger.LogTrace($"Effettuata lettura da DB + caching per AzioniUL: {ts.TotalMilliseconds} ms");
|
|
}
|
|
return await Task.FromResult(dbResult);
|
|
}
|
|
|
|
public Task<List<AutocompleteModel>> ArticoliGetSearch(int numRecord, string searchVal = "")
|
|
{
|
|
List<AutocompleteModel> answ = new List<AutocompleteModel>();
|
|
answ.Add(new AutocompleteModel { LabelField = "--- TUTTE ---", ValueField = "*" });
|
|
if (numRecord > -1)
|
|
{
|
|
answ.AddRange(dbController.ArticoliGetSearch(numRecord, searchVal).Select(x => new AutocompleteModel { LabelField = $"{x.CodArticolo} {x.DescArticolo} {x.Disegno}", ValueField = x.CodArticolo }).ToList());
|
|
}
|
|
return Task.FromResult(answ);
|
|
}
|
|
|
|
public async Task<List<AutocompleteModel>> ArticoliList(string searchVal)
|
|
{
|
|
List<AutocompleteModel> answ = new List<AutocompleteModel>();
|
|
answ.Add(new AutocompleteModel { LabelField = "--- TUTTE ---", ValueField = "*" });
|
|
var listMacchine = dbController.MacchineGetAll();
|
|
answ.AddRange(listMacchine.Select(x => new AutocompleteModel { LabelField = x.IdxMacchina, ValueField = x.IdxMacchina }).ToList());
|
|
return await Task.FromResult(answ);
|
|
}
|
|
|
|
public Task<List<AutocompleteModel>> AzioniList()
|
|
{
|
|
List<AutocompleteModel> answ = new List<AutocompleteModel>();
|
|
answ.Add(new AutocompleteModel { LabelField = "--- TUTTE ---", ValueField = "*" });
|
|
answ.AddRange(dbController.ActionsGetAll().Select(x => new AutocompleteModel { LabelField = $"{x.Descrizione}", ValueField = x.Azione}).ToList());
|
|
return Task.FromResult(answ);
|
|
}
|
|
|
|
public Task<List<AutocompleteModel>> CommesseGetSearch(int numRecord, string searchVal = "")
|
|
{
|
|
List<AutocompleteModel> answ = new List<AutocompleteModel>();
|
|
answ.Add(new AutocompleteModel { LabelField = "--- TUTTE ---", ValueField = "*" });
|
|
if (numRecord > -1)
|
|
{
|
|
answ.AddRange(dbController.CommesseGetSearch(numRecord, searchVal).GroupBy(x => x.KeyRichiesta).Select(x => new AutocompleteModel { LabelField = $"{x.First().CodArticolo} | {x.First().KeyRichiesta}", ValueField = x.First().KeyRichiesta }).ToList());
|
|
}
|
|
return Task.FromResult(answ);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
// Clear database controller
|
|
dbController.Dispose();
|
|
}
|
|
|
|
public Task<List<MP.Data.DatabaseModels.Macchine>> MacchineGetAll()
|
|
{
|
|
return Task.FromResult(dbController.MacchineGetAll().ToList());
|
|
}
|
|
|
|
public Task<List<AutocompleteModel>> MachineList()
|
|
{
|
|
List<AutocompleteModel> answ = new List<AutocompleteModel>();
|
|
answ.Add(new AutocompleteModel { LabelField = "--- TUTTE ---", ValueField = "*" });
|
|
answ.AddRange(dbController
|
|
.MacchineGetAll()
|
|
.Select(x => new AutocompleteModel {
|
|
LabelField = $"{x.IdxMacchina} | {x.Nome} {x.Descrizione} ",
|
|
ValueField = x.IdxMacchina })
|
|
.ToList());
|
|
return Task.FromResult(answ);
|
|
}
|
|
|
|
public void rollBackEdit(object item)
|
|
{
|
|
dbController.RollBackEntity(item);
|
|
}
|
|
|
|
public async Task<List<MP.Data.DatabaseModels.ResControlli>> StatControlliGetAll(SelectData CurrFilter, string searchVal = "")
|
|
{
|
|
//return Task.FromResult(dbController.StatControlliGetAll(DataStart, DataEnd, IdxMacchina, IdxODL, KeyRichiesta, CodArticolo).ToArray());
|
|
List<MP.Data.DatabaseModels.ResControlli> dbResult = new List<MP.Data.DatabaseModels.ResControlli>();
|
|
string cacheKey = getCacheKey("MP:STATS:CONTROLLI", CurrFilter);
|
|
string rawData;
|
|
var redisDataList = await distributedCache.GetAsync(cacheKey);
|
|
if (redisDataList != null)
|
|
{
|
|
rawData = Encoding.UTF8.GetString(redisDataList);
|
|
dbResult = JsonConvert.DeserializeObject<List<MP.Data.DatabaseModels.ResControlli>>(rawData);
|
|
}
|
|
else
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
dbResult = dbController.StatControlliGetAll(CurrFilter.DateStart, CurrFilter.DateEnd, CurrFilter.IdxMacchina, CurrFilter.IdxOdl, CurrFilter.KeyRichiesta, CurrFilter.CodArticolo);
|
|
rawData = JsonConvert.SerializeObject(dbResult);
|
|
redisDataList = Encoding.UTF8.GetBytes(rawData);
|
|
await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
_logger.LogTrace($"Effettuata lettura da DB + caching per ResControlli: {ts.TotalMilliseconds} ms");
|
|
}
|
|
return await Task.FromResult(dbResult);
|
|
}
|
|
|
|
public async Task<List<MP.Data.DatabaseModels.DdbTurni>> StatDdbGetAll(SelectData CurrFilter, string searchVal = "")
|
|
{
|
|
//return Task.FromResult(dbController.StatDdbGetAll(numRecord, searchVal).ToArray());
|
|
List<MP.Data.DatabaseModels.DdbTurni> dbResult = new List<MP.Data.DatabaseModels.DdbTurni>();
|
|
string cacheKey = getCacheKeyPaged("MP:STATS:DDBT", CurrFilter);
|
|
string rawData;
|
|
var redisDataList = await distributedCache.GetAsync(cacheKey);
|
|
if (redisDataList != null)
|
|
{
|
|
rawData = Encoding.UTF8.GetString(redisDataList);
|
|
dbResult = JsonConvert.DeserializeObject<List<MP.Data.DatabaseModels.DdbTurni>>(rawData);
|
|
}
|
|
else
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
dbResult = dbController.StatDdbGetAll(CurrFilter.DateStart, CurrFilter.DateEnd, CurrFilter.IdxMacchina, CurrFilter.IdxOdl, CurrFilter.KeyRichiesta, CurrFilter.CodArticolo, CurrFilter.FirstRecord, CurrFilter.NumRecord);
|
|
rawData = JsonConvert.SerializeObject(dbResult);
|
|
redisDataList = Encoding.UTF8.GetBytes(rawData);
|
|
await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
_logger.LogTrace($"Effettuata lettura da DB + caching per DdbTurni: {ts.TotalMilliseconds} ms");
|
|
}
|
|
return await Task.FromResult(dbResult);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recupera TUTTI x export
|
|
/// </summary>
|
|
/// <param name="CurrFilter"></param>
|
|
/// <param name="searchVal"></param>
|
|
/// <returns></returns>
|
|
public async Task<List<MP.Data.DatabaseModels.DdbTurni>> StatDdbGetAllExport(SelectData CurrFilter, string searchVal = "")
|
|
{
|
|
//return Task.FromResult(dbController.StatDdbGetAll(numRecord, searchVal).ToArray());
|
|
List<MP.Data.DatabaseModels.DdbTurni> dbResult = new List<MP.Data.DatabaseModels.DdbTurni>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
dbResult = dbController.StatDdbGetAll(CurrFilter.DateStart, CurrFilter.DateEnd, CurrFilter.IdxMacchina, CurrFilter.IdxOdl, CurrFilter.KeyRichiesta, CurrFilter.CodArticolo, 1, 0);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
_logger.LogTrace($"Effettuata lettura COMPLETA da DB + caching per StatDdbGetAllExport: {ts.TotalMilliseconds} ms");
|
|
return await Task.FromResult(dbResult);
|
|
}
|
|
|
|
public async Task<int> StatDdbGetCount(SelectData CurrFilter, string searchVal = "")
|
|
{
|
|
int numRec = 0;
|
|
string cacheKey = getCacheKey("MP:STATS:DDBT-COUNT", CurrFilter);
|
|
string rawData;
|
|
var redisDataList = await distributedCache.GetAsync(cacheKey);
|
|
if (redisDataList != null)
|
|
{
|
|
rawData = Encoding.UTF8.GetString(redisDataList);
|
|
int.TryParse(rawData, out numRec);
|
|
}
|
|
else
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
numRec = dbController.StatDdbGetCount(CurrFilter.DateStart, CurrFilter.DateEnd, CurrFilter.IdxMacchina, CurrFilter.IdxOdl, CurrFilter.KeyRichiesta, CurrFilter.CodArticolo);
|
|
rawData = $"{numRec}";
|
|
redisDataList = Encoding.UTF8.GetBytes(rawData);
|
|
await distributedCache.SetAsync(cacheKey, redisDataList, cacheOptLong);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
_logger.LogTrace($"Effettuata lettura da DB + caching per DdbTurni: {ts.TotalMilliseconds} ms");
|
|
}
|
|
return await Task.FromResult(numRec);
|
|
}
|
|
|
|
public async Task<List<MP.Data.DatabaseModels.StatsODL>> StatOdlGetAll(SelectData CurrFilter, string searchVal = "")
|
|
{
|
|
//return Task.FromResult(dbController.StatOdlGetAll(numRecord, searchVal));
|
|
List<MP.Data.DatabaseModels.StatsODL> dbResult = new List<MP.Data.DatabaseModels.StatsODL>();
|
|
string cacheKey = getCacheKey("MP:STATS:ODL", CurrFilter);
|
|
string rawData;
|
|
var redisDataList = await distributedCache.GetAsync(cacheKey);
|
|
if (redisDataList != null)
|
|
{
|
|
rawData = Encoding.UTF8.GetString(redisDataList);
|
|
dbResult = JsonConvert.DeserializeObject<List<MP.Data.DatabaseModels.StatsODL>>(rawData);
|
|
}
|
|
else
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
dbResult = dbController.StatOdlGetAll(CurrFilter.DateStart, CurrFilter.DateEnd, CurrFilter.IdxMacchina, CurrFilter.IdxOdl, CurrFilter.KeyRichiesta, CurrFilter.CodArticolo);
|
|
rawData = JsonConvert.SerializeObject(dbResult);
|
|
redisDataList = Encoding.UTF8.GetBytes(rawData);
|
|
await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
_logger.LogTrace($"Effettuata lettura da DB + caching per ODL: {ts.TotalMilliseconds} ms");
|
|
}
|
|
return await Task.FromResult(dbResult);
|
|
}
|
|
|
|
public async Task<List<MP.Data.DatabaseModels.ResScarti>> StatScartiGetAll(SelectData CurrFilter, string searchVal = "")
|
|
{
|
|
//return Task.FromResult(dbController.StatScartiGetAll(DataStart, DataEnd, IdxMacchina, IdxODL, KeyRichiesta, CodArticolo).ToArray());
|
|
List<MP.Data.DatabaseModels.ResScarti> dbResult = new List<MP.Data.DatabaseModels.ResScarti>();
|
|
string cacheKey = getCacheKey("MP:STATS:SCARTI:RAW", CurrFilter);
|
|
string rawData;
|
|
var redisDataList = await distributedCache.GetAsync(cacheKey);
|
|
if (redisDataList != null)
|
|
{
|
|
rawData = Encoding.UTF8.GetString(redisDataList);
|
|
dbResult = JsonConvert.DeserializeObject<List<MP.Data.DatabaseModels.ResScarti>>(rawData);
|
|
}
|
|
else
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
dbResult = dbController.StatScartiGetAll(CurrFilter.DateStart, CurrFilter.DateEnd, CurrFilter.IdxMacchina, CurrFilter.IdxOdl, CurrFilter.KeyRichiesta, CurrFilter.CodArticolo);
|
|
rawData = JsonConvert.SerializeObject(dbResult);
|
|
redisDataList = Encoding.UTF8.GetBytes(rawData);
|
|
await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
_logger.LogTrace($"Effettuata lettura da DB + caching per ResScarti: {ts.TotalMilliseconds} ms");
|
|
}
|
|
return await Task.FromResult(dbResult);
|
|
}
|
|
|
|
public async Task<List<MP.Data.DatabaseModels.TurniOee>> StatTurniOeeGetAllAsync(DateTime DataStart, DateTime DataEnd, string IdxMacchina, int IdxODL, string KeyRichiesta, string CodArticolo, string searchVal = "")
|
|
{
|
|
return await Task.FromResult(dbController.StatTurniOeeGetAll(DataStart, DataEnd, IdxMacchina, IdxODL, KeyRichiesta, CodArticolo));
|
|
}
|
|
|
|
public async Task<List<MP.Data.DatabaseModels.TurniOee>> StatTurniOeeGetAllCached(SelectData CurrFilter, string searchVal = "")
|
|
{
|
|
List<MP.Data.DatabaseModels.TurniOee> dbResult = new List<MP.Data.DatabaseModels.TurniOee>();
|
|
string cacheKey = getCacheKey("MP:STATS:OEE", CurrFilter);
|
|
string rawData;
|
|
var redisDataList = await distributedCache.GetAsync(cacheKey);
|
|
if (redisDataList != null)
|
|
{
|
|
rawData = Encoding.UTF8.GetString(redisDataList);
|
|
dbResult = JsonConvert.DeserializeObject<List<MP.Data.DatabaseModels.TurniOee>>(rawData);
|
|
}
|
|
else
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
dbResult = dbController.StatTurniOeeGetAll(CurrFilter.DateStart, CurrFilter.DateEnd, CurrFilter.IdxMacchina, CurrFilter.IdxOdl, CurrFilter.KeyRichiesta, CurrFilter.CodArticolo);
|
|
rawData = JsonConvert.SerializeObject(dbResult);
|
|
redisDataList = Encoding.UTF8.GetBytes(rawData);
|
|
await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
_logger.LogTrace($"Effettuata lettura da DB + caching per TurniOee: {ts.TotalMilliseconds} ms");
|
|
}
|
|
return await Task.FromResult(dbResult);
|
|
}
|
|
|
|
public async Task<List<MP.Data.DatabaseModels.UserActionLog>> StatUserLogGetAll(SelectData CurrFilter, string searchVal = "")
|
|
{
|
|
//return Task.FromResult(dbController.StatUserLogGetAll(DataStart, DataEnd, IdxMacchina, IdxODL, KeyRichiesta, CodArticolo).ToArray());
|
|
List<MP.Data.DatabaseModels.UserActionLog> dbResult = new List<MP.Data.DatabaseModels.UserActionLog>();
|
|
string cacheKey = getCacheKey("MP:STATS:USRACTLOG", CurrFilter);
|
|
string rawData;
|
|
var redisDataList = await distributedCache.GetAsync(cacheKey);
|
|
if (redisDataList != null)
|
|
{
|
|
rawData = Encoding.UTF8.GetString(redisDataList);
|
|
dbResult = JsonConvert.DeserializeObject<List<MP.Data.DatabaseModels.UserActionLog>>(rawData);
|
|
}
|
|
else
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
dbResult = dbController.StatUserLogGetAll(CurrFilter.DateStart, CurrFilter.DateEnd, CurrFilter.IdxMacchina, CurrFilter.IdxOdl, CurrFilter.KeyRichiesta, CurrFilter.CodArticolo);
|
|
// se richiesto filtro azioni effettuo ora selezione...
|
|
if (CurrFilter.Azione != "*")
|
|
{
|
|
dbResult= dbResult.Where(x => x.Azione == CurrFilter.Azione).ToList();
|
|
}
|
|
rawData = JsonConvert.SerializeObject(dbResult);
|
|
redisDataList = Encoding.UTF8.GetBytes(rawData);
|
|
await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
_logger.LogTrace($"Effettuata lettura da DB + caching per UserActionLog: {ts.TotalMilliseconds} ms");
|
|
}
|
|
return await Task.FromResult(dbResult);
|
|
}
|
|
|
|
#endregion Public Methods
|
|
}
|
|
} |