From f3084077746f1fec6be2f2e4804c2739e9b2caac Mon Sep 17 00:00:00 2001 From: "Samuele E. Locatelli" Date: Mon, 6 Feb 2023 23:41:52 +0100 Subject: [PATCH] Bozza pagina da testare in ufficio --- StockMan.CORE.sln | 2 +- StockMan.CORE/Data/StockDataService.cs | 228 +++++++++++++++++++++++ StockMan.CORE/Pages/ItemFamily.razor | 23 +++ StockMan.CORE/Pages/ItemFamily.razor.cs | 44 +++++ StockMan.CORE/Program.cs | 58 +++++- StockMan.CORE/Shared/MainLayout.razor.cs | 10 +- StockMan.CORE/StockMan.CORE.csproj | 5 + StockMan.CORE/_Imports.razor | 1 + 8 files changed, 367 insertions(+), 4 deletions(-) create mode 100644 StockMan.CORE/Data/StockDataService.cs create mode 100644 StockMan.CORE/Pages/ItemFamily.razor create mode 100644 StockMan.CORE/Pages/ItemFamily.razor.cs diff --git a/StockMan.CORE.sln b/StockMan.CORE.sln index 4b572d0..3f9681f 100644 --- a/StockMan.CORE.sln +++ b/StockMan.CORE.sln @@ -5,7 +5,7 @@ VisualStudioVersion = 17.4.33213.308 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StockMan.CORE", "StockMan.CORE\StockMan.CORE.csproj", "{3D23F328-E6B6-4EDB-B2DE-00E39E953757}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StockMan.Data", "StockMan.Data\StockMan.Data.csproj", "{5C4C9C5C-9478-424A-B68C-C3C04C5E2165}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StockMan.Data", "StockMan.Data\StockMan.Data.csproj", "{5C4C9C5C-9478-424A-B68C-C3C04C5E2165}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/StockMan.CORE/Data/StockDataService.cs b/StockMan.CORE/Data/StockDataService.cs new file mode 100644 index 0000000..3a681c6 --- /dev/null +++ b/StockMan.CORE/Data/StockDataService.cs @@ -0,0 +1,228 @@ +using Microsoft.AspNetCore.Identity.UI.Services; +using Newtonsoft.Json; +using NLog; +using StackExchange.Redis; +using StockMan.Data.Controllers; +using StockMan.Data.DbModels; +using System.Diagnostics; + +namespace StockMan.CORE.Data +{ + public class StockDataService : IDisposable + { + #region Protected Fields + + protected Random rnd = new Random(); + + #endregion Protected Fields + + #region Private Fields + + private const string passPhrase = "53DBA37E-257D-4276-BAC2-C0BF7E04BBD6"; + private const string redisBaseAddr = "STOCKMAN:STEAM"; + private const string rKeyCounters = $"{redisBaseAddr}:Cache:Counters"; + private const string rKeyItemFamily = $"{redisBaseAddr}:Cache:ItemFamily"; + private const string rKeyItemFlux = $"{redisBaseAddr}:Cache:ItemFlux"; + private const string rKeyItems = $"{redisBaseAddr}:Cache:Items"; + private const string rKeyItemStock = $"{redisBaseAddr}:Cache:Item:Stock"; + private const string rKeyLocation = $"{redisBaseAddr}:Cache:Location"; + private const string rKeyLocType = $"{redisBaseAddr}:Cache:LocType"; + private const string rKeyMovType = $"{redisBaseAddr}:Cache:MovType"; + private const string rKeyOperator = $"{redisBaseAddr}:Cache:Operator"; + private static IConfiguration _configuration = null!; + private static ILogger _logger = null!; + private static StoManController dbController = null!; + private static JsonSerializerSettings? JSSettings; + + private static 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 + + #region Public Constructors + + public StockDataService(IConfiguration configuration, ILogger logger, IConnectionMultiplexer redisConnMult, IEmailSender emailSender) + { + _logger = logger; + _configuration = configuration; + _emailSender = emailSender; + // Conf cache + redisConn = redisConnMult;// ConnectionMultiplexer.Connect(_configuration.GetConnectionString("Redis")); + //redisConn = ConnectionMultiplexer.Connect(_configuration.GetConnectionString("Redis")); + 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("StockMan.DB"); + if (string.IsNullOrEmpty(connStr)) + { + _logger.LogError("ConnString empty!"); + } + else + { + dbController = new StoManController(configuration); + } + _logger.LogInformation("Avviata classe StockDataService"); + } + + #endregion Public Constructors + + #region Protected Properties + + protected string CodApp { get; set; } = ""; + + #endregion Protected Properties + + #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 + + #region Public Methods + + public void Dispose() + { + // Clear database controller + dbController.Dispose(); + GC.Collect(); + } + + /// + /// Svuotamento comleto cache REDIS + /// + /// + public async Task FlushRedisCache() + { + await Task.Delay(1); + RedisValue pattern = new RedisValue($"{redisBaseAddr}:*"); + bool answ = await ExecFlushRedisPattern(pattern); + return answ; + } + + /// + /// Lista Famiglie Articoli + /// + /// + public async Task> ItemFamilyGetAll() + { + string source = "DB"; + List? dbResult = new List(); + string currKey = $"{rKeyItemFamily}"; + 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.ItemFamilyGetAll(); + rawData = JsonConvert.SerializeObject(dbResult, JSSettings); + await redisDb.StringSetAsync(currKey, rawData, LongCache); + } + if (dbResult == null) + { + dbResult = new List(); + } + stopWatch.Stop(); + TimeSpan ts = stopWatch.Elapsed; + Log.Debug($"ItemFamilyGetAll | {source} in: {ts.TotalMilliseconds} ms"); + return dbResult; + } + + #endregion Public Methods + + #region Private 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; + } + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/StockMan.CORE/Pages/ItemFamily.razor b/StockMan.CORE/Pages/ItemFamily.razor new file mode 100644 index 0000000..3bc600d --- /dev/null +++ b/StockMan.CORE/Pages/ItemFamily.razor @@ -0,0 +1,23 @@ +@page "/ItemFamily" + +

ItemFamily

+ + +@if (isLoading) +{ + ...loading... +} +@if (ListRecord == null || ListRecord.Count == 0) +{ + nessun record +} +else +{ +
    + + @foreach (var item in ListRecord) + { +
  • @item.Descr
  • + } +
+} \ No newline at end of file diff --git a/StockMan.CORE/Pages/ItemFamily.razor.cs b/StockMan.CORE/Pages/ItemFamily.razor.cs new file mode 100644 index 0000000..9e933d6 --- /dev/null +++ b/StockMan.CORE/Pages/ItemFamily.razor.cs @@ -0,0 +1,44 @@ +using Microsoft.AspNetCore.Components; +using StockMan.CORE.Data; +using StockMan.Data.DbModels; + +namespace StockMan.CORE.Pages +{ + public partial class ItemFamily + { + #region Protected Properties + + protected List? ListRecord { get; set; } = null; + + [Inject] + protected StockDataService SDService { get; set; } = null!; + + #endregion Protected Properties + + #region Private Properties + + private bool isLoading { get; set; } = false; + + #endregion Private Properties + + #region Protected Methods + + protected override async Task OnParametersSetAsync() + { + await ReloadData(); + } + + #endregion Protected Methods + + #region Private Methods + + private async Task ReloadData() + { + isLoading = true; + ListRecord = await SDService.ItemFamilyGetAll(); + isLoading = false; + } + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/StockMan.CORE/Program.cs b/StockMan.CORE/Program.cs index dba8883..94dc597 100644 --- a/StockMan.CORE/Program.cs +++ b/StockMan.CORE/Program.cs @@ -1,12 +1,56 @@ using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.Identity.UI.Services; +using Microsoft.AspNetCore.Localization; +using StackExchange.Redis; using StockMan.CORE.Data; +using StockMan.Data; +using System.Globalization; +using Blazored.LocalStorage; +using Blazored.SessionStorage; var builder = WebApplication.CreateBuilder(args); +//builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme) +// .AddNegotiate(); + +//builder.Services.AddAuthorization(options => +//{ +// // By default, all incoming requests will be authorized according to the default policy. +// options.FallbackPolicy = options.DefaultPolicy; +//}); + +// configuration setup +ConfigurationManager configuration = builder.Configuration; + +// REDIS setup +string connStringRedis = configuration.GetConnectionString("Redis"); +string redisSrvAddr = connStringRedis.Substring(0, connStringRedis.IndexOf(":")); +// avvio oggetto shared x redis... +var redisMultiplexer = ConnectionMultiplexer.Connect(connStringRedis); + +// abilitazione x email management con MailKit +builder.Services.AddTransient(); +builder.Services.Configure(options => +{ + options.Host_Address = configuration["ExternalProviders:MailKit:SMTP:Address"]; + options.Host_Port = Convert.ToInt32(configuration["ExternalProviders:MailKit:SMTP:Port"]); + options.Host_Username = configuration["ExternalProviders:MailKit:SMTP:Account"]; + options.Host_Password = configuration["ExternalProviders:MailKit:SMTP:Password"]; + options.Sender_EMail = configuration["ExternalProviders:MailKit:SMTP:SenderEmail"]; + options.Sender_Name = configuration["ExternalProviders:MailKit:SMTP:SenderName"]; +}); + // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); +builder.Services.AddSingleton(); +//builder.Services.AddScoped(); +builder.Services.AddHttpContextAccessor(); +builder.Services.AddSingleton(redisMultiplexer); + +builder.Services.AddBlazoredLocalStorage(); +builder.Services.AddBlazoredSessionStorage(); var app = builder.Build(); @@ -18,6 +62,18 @@ if (!app.Environment.IsDevelopment()) app.UseHsts(); } +// cultura IT... +var supportedCultures = new[]{ + new CultureInfo("it-IT") + }; +app.UseRequestLocalization(new RequestLocalizationOptions +{ + DefaultRequestCulture = new RequestCulture("it-IT"), + SupportedCultures = supportedCultures, + FallBackToParentCultures = false +}); +CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture("it-IT"); + app.UseHttpsRedirection(); app.UseStaticFiles(); @@ -27,4 +83,4 @@ app.UseRouting(); app.MapBlazorHub(); app.MapFallbackToPage("/_Host"); -app.Run(); +app.Run(); \ No newline at end of file diff --git a/StockMan.CORE/Shared/MainLayout.razor.cs b/StockMan.CORE/Shared/MainLayout.razor.cs index 7225021..2d31150 100644 --- a/StockMan.CORE/Shared/MainLayout.razor.cs +++ b/StockMan.CORE/Shared/MainLayout.razor.cs @@ -5,18 +5,24 @@ namespace StockMan.CORE.Shared { public partial class MainLayout { + #region Protected Properties protected List navMenuLinks { get; set; } = new List(); + #endregion Protected Properties + + #region Protected Methods + protected override async Task OnInitializedAsync() { await Task.Delay(1); navMenuLinks.Clear(); navMenuLinks.Add(new LinkMan() { Title = "Articolo", Icon = "fa-solid fa-box", hasChildren = true, linkChildren = new List() { "Anagrafica articoli", "Famiglia articoli" } }); navMenuLinks.Add(new LinkMan() { Title = "Magazzino", Icon = "fa-solid fa-boxes-stacked" }); - navMenuLinks.Add(new LinkMan() { Title = "Aagrafiche", Icon = "fa-solid fa-clipboard-list" }); + navMenuLinks.Add(new LinkMan() { Title = "Anagrafiche", Icon = "fa-solid fa-clipboard-list" }); navMenuLinks.Add(new LinkMan() { Title = "Admin", Icon = "fa-solid fa-id-card-clip" }); } + #endregion Protected Methods } -} +} \ No newline at end of file diff --git a/StockMan.CORE/StockMan.CORE.csproj b/StockMan.CORE/StockMan.CORE.csproj index c580c1f..df97ad9 100644 --- a/StockMan.CORE/StockMan.CORE.csproj +++ b/StockMan.CORE/StockMan.CORE.csproj @@ -14,6 +14,11 @@ + + + + + diff --git a/StockMan.CORE/_Imports.razor b/StockMan.CORE/_Imports.razor index b8b0fe2..05ad72a 100644 --- a/StockMan.CORE/_Imports.razor +++ b/StockMan.CORE/_Imports.razor @@ -7,4 +7,5 @@ @using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.JSInterop @using StockMan.CORE +@using StockMan.CORE.Data @using StockMan.CORE.Shared