Bozza pagina da testare in ufficio

This commit is contained in:
Samuele E. Locatelli
2023-02-06 23:41:52 +01:00
parent e7a1581ba3
commit f308407774
8 changed files with 367 additions and 4 deletions
+1 -1
View File
@@ -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
+228
View File
@@ -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<StockDataService> _logger = null!;
private static StoManController dbController = null!;
private static JsonSerializerSettings? JSSettings;
private static Logger Log = LogManager.GetCurrentClassLogger();
private readonly IEmailSender _emailSender;
/// <summary>
/// Durata cache lunga IN SECONDI
/// </summary>
private int cacheTtlLong = 60 * 5;
/// <summary>
/// Durata cache breve IN SECONDI
/// </summary>
private int cacheTtlShort = 60 * 1;
/// <summary>
/// Oggetto per connessione a REDIS
/// </summary>
private IConnectionMultiplexer redisConn;
//ISubscriber sub = redis.GetSubscriber();
/// <summary>
/// Oggetto DB redis da impiegare x chiamate R/W
/// </summary>
private IDatabase redisDb = null!;
#endregion Private Fields
#region Public Constructors
public StockDataService(IConfiguration configuration, ILogger<StockDataService> 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
/// <summary>
/// Durata cache lunga (+ perturbazione percentuale +/-10%)
/// </summary>
private TimeSpan FastCache
{
get => TimeSpan.FromSeconds(cacheTtlShort * rnd.Next(900, 1100) / 1000);
}
/// <summary>
/// Durata cache lunga (+ perturbazione percentuale +/-10%)
/// </summary>
private TimeSpan LongCache
{
get => TimeSpan.FromSeconds(cacheTtlLong * rnd.Next(900, 1100) / 1000);
}
/// <summary>
/// Durata cache lunga (+ perturbazione percentuale +/-10%)
/// </summary>
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();
}
/// <summary>
/// Svuotamento comleto cache REDIS
/// </summary>
/// <returns></returns>
public async Task<bool> FlushRedisCache()
{
await Task.Delay(1);
RedisValue pattern = new RedisValue($"{redisBaseAddr}:*");
bool answ = await ExecFlushRedisPattern(pattern);
return answ;
}
/// <summary>
/// Lista Famiglie Articoli
/// </summary>
/// <returns></returns>
public async Task<List<ItemFamilyModel>> ItemFamilyGetAll()
{
string source = "DB";
List<ItemFamilyModel>? dbResult = new List<ItemFamilyModel>();
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<List<ItemFamilyModel>>(rawData);
if (tempResult == null)
{
dbResult = new List<ItemFamilyModel>();
}
else
{
dbResult = tempResult;
}
}
else
{
dbResult = dbController.ItemFamilyGetAll();
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
await redisDb.StringSetAsync(currKey, rawData, LongCache);
}
if (dbResult == null)
{
dbResult = new List<ItemFamilyModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"ItemFamilyGetAll | {source} in: {ts.TotalMilliseconds} ms");
return dbResult;
}
#endregion Public Methods
#region Private Methods
/// <summary>
/// Esegue flush memoria redis dato pattern
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
private async Task<bool> 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
}
}
+23
View File
@@ -0,0 +1,23 @@
@page "/ItemFamily"
<h3>ItemFamily</h3>
@if (isLoading)
{
<i>...loading...</i>
}
@if (ListRecord == null || ListRecord.Count == 0)
{
<b>nessun record</b>
}
else
{
<ul>
@foreach (var item in ListRecord)
{
<li>@item.Descr</li>
}
</ul>
}
+44
View File
@@ -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<ItemFamilyModel>? 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
}
}
+57 -1
View File
@@ -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<IEmailSender, MailKitEmailSender>();
builder.Services.Configure<MailKitEmailSenderOptions>(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<StockDataService>();
//builder.Services.AddScoped<MessageService>();
builder.Services.AddHttpContextAccessor();
builder.Services.AddSingleton<IConnectionMultiplexer>(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();
+8 -2
View File
@@ -5,18 +5,24 @@ namespace StockMan.CORE.Shared
{
public partial class MainLayout
{
#region Protected Properties
protected List<LinkMan> navMenuLinks { get; set; } = new List<LinkMan>();
#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<string>() { "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
}
}
}
+5
View File
@@ -14,6 +14,11 @@
<None Include="compilerconfig.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="StackExchange.Redis" Version="2.6.90" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StockMan.Data\StockMan.Data.csproj" />
</ItemGroup>
+1
View File
@@ -7,4 +7,5 @@
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using StockMan.CORE
@using StockMan.CORE.Data
@using StockMan.CORE.Shared