Files
NKC/REMAN/Data/RDataService.cs
2022-02-01 16:51:42 +01:00

299 lines
11 KiB
C#

using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using NKC.Data.DbModels;
using NKC.Data.DTO;
using NLog;
using System.Diagnostics;
using System.Text;
namespace REMAN.Data
{
public class RDataService : IDisposable
{
#region Private Fields
private static IConfiguration _configuration = null!;
private static ILogger<RDataService> _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 rKeyMaterials = "Cache:Materials";
protected const string rKeyQrRemnants = "Cache:QrRemnants";
protected const string rKeyRemnants = "Cache:Remnants";
protected static string connStringBBM = "";
#endregion Protected Fields
#region Public Fields
public static NKC.Data.Controllers.NKCController dbController = null!;
#endregion Public Fields
#region Public Constructors
public RDataService(IConfiguration configuration, ILogger<RDataService> 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
};
// conf DB
string connStr = _configuration.GetConnectionString("NKC.DB");
if (string.IsNullOrEmpty(connStr))
{
_logger.LogError("ConnString empty!");
}
else
{
dbController = new NKC.Data.Controllers.NKCController(configuration);
}
}
#endregion Public Constructors
#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));
}
#endregion Private Methods
#region Public Methods
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(rKeyMaterials);
await distributedCache.RemoveAsync(rKeyRemnants);
foreach (var item in cachedDataList)
{
await distributedCache.RemoveAsync(item);
}
cachedDataList = new List<string>();
}
public async Task<List<MaterialDTO>> MaterialsGetAll()
{
List<MaterialDTO>? dbResult = new List<MaterialDTO>();
string rawData;
var redisDataList = await distributedCache.GetAsync(rKeyMaterials);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<MaterialDTO>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.MaterialsGetAll();
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(rKeyMaterials, redisDataList, cacheOpt(false));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per GetMaterials: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<MaterialDTO>();
}
return await Task.FromResult(dbResult);
}
public async Task<List<MovMagModel>> MovMagGetFilt(int RemnId, int numShow)
{
List<MovMagModel> dbResult = new List<MovMagModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dbResult = dbController.MovMagGetFilt(RemnId, numShow);
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per MovMagGetFilt: {ts.TotalMilliseconds} ms");
return await Task.FromResult(dbResult);
}
public async Task<bool> AddPrintJob(int RemnId)
{
bool answ = dbController.AddPrintJob("docRemnant", $"{RemnId}", "queueRemnants");
return await Task.FromResult(answ);
}
public async Task<List<RemnantsModel>> RemnantsGetFilt(int matId, int minQty)
{
List<RemnantsModel>? dbResult = new List<RemnantsModel>();
string rawData;
string cacheKey = $"{rKeyRemnants}:{matId}:{minQty}";
if (!cachedDataList.Contains(cacheKey))
{
cachedDataList.Add(cacheKey);
}
var redisDataList = await distributedCache.GetAsync(cacheKey);
if (redisDataList != null)
{
rawData = Encoding.UTF8.GetString(redisDataList);
dbResult = JsonConvert.DeserializeObject<List<RemnantsModel>>(rawData);
}
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
var rawList = dbController.RemnantsGetFilt(matId, minQty);
dbResult = rawList.OrderBy(r => r.RemDtmx).ThenBy(o => o.Area).ToList();
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
redisDataList = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(false));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per RemnantsGetAll: {ts.TotalMilliseconds} ms");
}
if (dbResult == null)
{
dbResult = new List<RemnantsModel>();
}
return await Task.FromResult(dbResult);
}
public async Task<bool> RemnantsIsDupl(RemnantsModel currItem)
{
bool answ = false;
var rawList = dbController.RemnantsGetFilt(currItem.MatID, 0);
var duplicati = rawList
.Where(x => x.RemnID != currItem.RemnID && x.LMm == currItem.LMm && x.WMm == currItem.WMm && x.TMm == currItem.TMm)
.ToList();
answ = duplicati.Count > 0;
return await Task.FromResult(answ);
}
public async Task<bool> RemnantsMovMag(RemnantsModel currItem, string userId, int deltaQty)
{
bool done = false;
try
{
// recupero item da DB
var currRecord = dbController.RemnantGetByid(currItem.RemnID);
if (currRecord != null && currRecord.RemnID == currItem.RemnID)
{
// modifico qty entro limiti >=0..
if (currRecord.QtyAvail + deltaQty >= 0)
{
currRecord.QtyAvail = currRecord.QtyAvail + deltaQty;
done = dbController.RemnantsUpsert(currRecord, userId);
await InvalidateAllCache();
}
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in RemnantsMovMag:{Environment.NewLine}{exc}");
}
return await Task.FromResult(done);
}
public async Task<bool> RemnantsUpsert(RemnantsModel currItem, string userId)
{
bool done = false;
try
{
done = dbController.RemnantsUpsert(currItem, userId);
await InvalidateAllCache();
}
catch (Exception exc)
{
Log.Error($"Eccezione in RemnantsUpsert:{Environment.NewLine}{exc}");
}
return await Task.FromResult(done);
}
public void rollBackEdit(object item)
{
dbController.rollBackEntity(item);
}
public async Task<RemnantsModel> SearchQrRemnant(string QrCode)
{
RemnantsModel? answ = new RemnantsModel();
string rawData = "";
string cacheKey = $"{rKeyQrRemnants}:{QrCode}";
// cerco in redis
var redisData = await distributedCache.GetAsync(cacheKey);
if (redisData != null)
{
rawData = Encoding.UTF8.GetString(redisData);
answ = JsonConvert.DeserializeObject<RemnantsModel>(rawData);
}
// se non trovo cerco su DB
else
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
var foundItem = dbController.RemnantGetByQr(QrCode);
if (foundItem != null && foundItem.RemDtmx == QrCode)
{
rawData = JsonConvert.SerializeObject(foundItem, JSSettings);
redisData = Encoding.UTF8.GetBytes(rawData);
await distributedCache.SetAsync(cacheKey, redisData, cacheOpt(false));
answ = foundItem;
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"Effettuata lettura da DB + caching per SearchQrRemnant: {ts.TotalMilliseconds} ms");
}
if (answ == null)
{
answ = new RemnantsModel();
}
return await Task.FromResult(answ);
}
#endregion Public Methods
}
}