diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 3fffdd88..88ebaaa0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -285,6 +285,24 @@ IOC:build:
script:
- dotnet build $env:APP_NAME/$env:APP_NAME.csproj
+RIOC:build:
+ stage: build
+ tags:
+ - win
+ variables:
+ APP_NAME: MP.RIOC
+ SOL_NAME: MP-RIOC
+ rules:
+ - if: $CI_COMMIT_BRANCH == 'develop'
+ - if: $CI_COMMIT_BRANCH == 'master'
+ - if: $CI_COMMIT_BRANCH =~ /^feature\/IOC.+/
+ when: always
+ before_script:
+ - *nuget-fix
+ - dotnet restore "$env:SOL_NAME.sln"
+ script:
+ - dotnet build $env:APP_NAME/$env:APP_NAME.csproj
+
TAB3:build:
stage: build
tags:
@@ -350,8 +368,6 @@ LAND:SDK:deploy:
- '& "$env:NUGET_PATH" setapikey $NUGET_API_KEY -source http://nexus.steamware.net/repository/nuget-hosted'
- '& "$env:NUGET_PATH" push *$env:NUM_DEB.nupkg -Source http://nexus.steamware.net/repository/nuget-hosted'
-
-
PROG:IIS01:deploy:
stage: deploy
tags:
@@ -485,6 +501,25 @@ IOC:IIS01:deploy:
- dotnet build $env:APP_NAME/$env:APP_NAME.csproj
- dotnet publish -p:PublishProfile=IIS01.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release -p:username=jenkins -p:Password=$IIS_PWD -p:AllowUntrustedCertificate=true -p:verbosity=quiet $env:APP_NAME/$env:APP_NAME.csproj
+RIOC:IIS01:deploy:
+ stage: deploy
+ tags:
+ - win
+ variables:
+ APP_NAME: MP.RIOC
+ SOL_NAME: MP-RIOC
+ before_script:
+ - *nuget-fix
+ - dotnet restore "$env:SOL_NAME.sln"
+ rules:
+ - if: $CI_COMMIT_BRANCH == 'develop'
+ - if: $CI_COMMIT_BRANCH =~ /^feature\/IOC.+/
+ when: always
+ needs: ["RIOC:build"]
+ script:
+ - dotnet build $env:APP_NAME/$env:APP_NAME.csproj
+ - dotnet publish -p:PublishProfile=IIS01.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release -p:username=jenkins -p:Password=$IIS_PWD -p:AllowUntrustedCertificate=true -p:verbosity=quiet $env:APP_NAME/$env:APP_NAME.csproj
+
TAB3:IIS01:deploy:
stage: deploy
tags:
@@ -654,6 +689,24 @@ IOC:IIS03:deploy:
- dotnet publish -p:PublishProfile=IIS03.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release -p:username=jenkins -p:Password=$IIS_PWD -p:AllowUntrustedCertificate=true -p:verbosity=quiet $env:APP_NAME/$env:APP_NAME.csproj
- dotnet publish -p:PublishProfile=IIS04.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release -p:username=jenkins -p:Password=$IIS_PWD -p:AllowUntrustedCertificate=true -p:verbosity=quiet $env:APP_NAME/$env:APP_NAME.csproj
+RIOC:IIS03:deploy:
+ stage: deploy
+ tags:
+ - win
+ variables:
+ APP_NAME: MP.RIOC
+ SOL_NAME: MP-RIOC
+ before_script:
+ - *nuget-fix
+ - dotnet restore "$env:SOL_NAME.sln"
+ rules:
+ - if: $CI_COMMIT_BRANCH == 'master'
+ needs: ["RIOC:build"]
+ script:
+ - dotnet build $env:APP_NAME/$env:APP_NAME.csproj
+ - dotnet publish -p:PublishProfile=IIS03.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release -p:username=jenkins -p:Password=$IIS_PWD -p:AllowUntrustedCertificate=true -p:verbosity=quiet $env:APP_NAME/$env:APP_NAME.csproj
+ - dotnet publish -p:PublishProfile=IIS04.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release -p:username=jenkins -p:Password=$IIS_PWD -p:AllowUntrustedCertificate=true -p:verbosity=quiet $env:APP_NAME/$env:APP_NAME.csproj
+
TAB3:IIS03:deploy:
stage: deploy
tags:
@@ -873,6 +926,28 @@ IOC:installer:
- *hashBuild
- *nexusUpload
+RIOC:installer:
+ stage: installer
+ tags:
+ - win
+ variables:
+ APP_NAME: MP.RIOC
+ SOL_NAME: MP-RIOC
+ NEXUS_PATH: MP-RIOC
+ before_script:
+ - *nuget-fix
+ - dotnet restore "$env:SOL_NAME.sln"
+ rules:
+ - if: $CI_COMMIT_BRANCH == 'master'
+ - if: $CI_COMMIT_BRANCH == 'develop'
+ needs: ["IOC:build"]
+ script:
+ - dotnet build $env:APP_NAME/$env:APP_NAME.csproj
+ - dotnet publish -p:PublishProfile=IISProfile.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release $env:APP_NAME/$env:APP_NAME.csproj -o:publish -p:verbosity=quiet
+ # qui il deploy su nexus...
+ - *hashBuild
+ - *nexusUpload
+
# --------------------------------
# RELEASE (tags only + sdk)
# --------------------------------
@@ -897,7 +972,6 @@ LAND:release:
- dotnet build $env:APP_NAME/$env:APP_NAME.csproj
- dotnet publish -c Release -o ./publish $env:APP_NAME/$env:APP_NAME.csproj -p:verbosity=quiet
-
LAND:SDK:release:
stage: release
tags:
@@ -1067,3 +1141,24 @@ IOC:release:
- dotnet build $env:APP_NAME/$env:APP_NAME.csproj
- dotnet publish -c Release -o ./publish $env:APP_NAME/$env:APP_NAME.csproj -p:verbosity=quiet
+RIOC:release:
+ stage: release
+ tags:
+ - win
+ variables:
+ APP_NAME: MP.RIOC
+ SOL_NAME: MP-RIOC
+ NEXUS_PATH: MP-RIOC
+ before_script:
+ - *nuget-fix
+ - dotnet restore "$env:SOL_NAME.sln"
+ rules:
+ - if: $CI_COMMIT_TAG
+ needs: ["IOC:build"]
+ artifacts:
+ paths:
+ - publish/
+ script:
+ - dotnet build $env:APP_NAME/$env:APP_NAME.csproj
+ - dotnet publish -c Release -o ./publish $env:APP_NAME/$env:APP_NAME.csproj -p:verbosity=quiet
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
index de7d50f2..f5b8b499 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -7,8 +7,8 @@
-
-
+
+
@@ -28,15 +28,16 @@
-
+
-
+
+
diff --git a/MP-RIOC/MP-RIOC.http b/MP-RIOC/MP-RIOC.http
new file mode 100644
index 00000000..af71d627
--- /dev/null
+++ b/MP-RIOC/MP-RIOC.http
@@ -0,0 +1,6 @@
+@MP_RIOC_HostAddress = http://localhost:5290
+
+GET {{MP_RIOC_HostAddress}}/weatherforecast/
+Accept: application/json
+
+###
diff --git a/MP-RIOC/MP-RIOC.slnx b/MP-RIOC/MP-RIOC.slnx
new file mode 100644
index 00000000..c16a708c
--- /dev/null
+++ b/MP-RIOC/MP-RIOC.slnx
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/MP-RIOC/MP.RIOC.csproj b/MP-RIOC/MP.RIOC.csproj
new file mode 100644
index 00000000..62b5640a
--- /dev/null
+++ b/MP-RIOC/MP.RIOC.csproj
@@ -0,0 +1,46 @@
+
+
+
+ net8.0
+ enable
+ enable
+ MP.RIOC
+ 8.16.2605.812
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+
+
+
+
+
diff --git a/MP-RIOC/Pages/Index.cshtml b/MP-RIOC/Pages/Index.cshtml
new file mode 100644
index 00000000..6332b46a
--- /dev/null
+++ b/MP-RIOC/Pages/Index.cshtml
@@ -0,0 +1,97 @@
+
+@page
+@using MP.RIOC.Services
+@inject RouteStatsManager StatsManager
+@{
+ Layout = null;
+ var rawData = StatsManager.Snapshot();
+ var metrics = rawData.OrderByDescending(x => x.Value.Count).Take(10);
+}
+
+
+
+ MP.RIOC Dashboard
+
+
+
+
+
+
+
+ Stato: ● Online
+
+
+ Versione: @System.Reflection.Assembly.GetExecutingAssembly().GetName().Version
+
+
+
+
+
+ | Target | Metodo | ID |
+ Chiamate |
+ Latenza Media |
+
+
+
+ @foreach (var stat in metrics)
+ {
+
+ |
+ @if(stat.Key.StartsWith("IOC")) { NEW }
+ else { OLD }
+ @stat.Key
+ |
+ @stat.Value.Count |
+ @(stat.Value.AvgDuration)ms |
+
+ }
+ @if (!metrics.Any())
+ {
+
+ | Nessun dato raccolto al momento. |
+
+ }
+
+
+
+
+ Ultimo aggiornamento: @DateTime.Now.ToString("HH:mm:ss")
+
+
+
+
\ No newline at end of file
diff --git a/MP-RIOC/Pages/Index.cshtml.cs b/MP-RIOC/Pages/Index.cshtml.cs
new file mode 100644
index 00000000..0d5b03ed
--- /dev/null
+++ b/MP-RIOC/Pages/Index.cshtml.cs
@@ -0,0 +1,12 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+
+namespace MP.RIOC.Pages
+{
+ public class IndexModel : PageModel
+ {
+ public void OnGet()
+ {
+ }
+ }
+}
diff --git a/MP-RIOC/Program.cs b/MP-RIOC/Program.cs
new file mode 100644
index 00000000..31e3342f
--- /dev/null
+++ b/MP-RIOC/Program.cs
@@ -0,0 +1,178 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using MP.Core.Conf;
+using MP.Data;
+using MP.RIOC.Services;
+using NLog;
+using NLog.Web;
+using StackExchange.Redis;
+using System.Diagnostics;
+using System.Net;
+using System.Reflection;
+
+var builder = WebApplication.CreateBuilder(args);
+
+// recupero env corrente
+var env = builder.Environment;
+var logger = LogManager.Setup()
+ .LoadConfigurationFromAppSettings()
+ .GetCurrentClassLogger();
+
+var assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString();
+logger.Info($"MP.RIOC | Program.cs: startup | v.{assemblyVersion}");
+logger.Info($"Current ASPNETCORE_ENVIRONMENT: {env.EnvironmentName}");
+
+// Config setup
+ConfigurationManager configuration = builder.Configuration;
+// REDIS setup
+logger.Info("Config OK");
+string confRedis = configuration.GetConnectionString("Redis") ?? "localhost:6379";
+string redisSrvAddr = confRedis.Substring(0, confRedis.IndexOf(":"));
+logger.Info("Setup REDIS OK");
+
+builder.Services.Configure
(
+ builder.Configuration.GetSection("RedisScripts"));
+logger.Info("RedisScript Provider configured");
+
+// Metodi principali x accesso dati
+var connStr = builder.Configuration.GetConnectionString("MP.Data")
+ ?? throw new InvalidOperationException("ConnString 'MP.Data' mancante.");
+
+//builder.Services.AddMemoryCache();
+
+builder.Services.AddDbContextFactory(options =>
+ options.UseSqlServer(connStr)
+ .EnableSensitiveDataLogging(false) // true solo in Sviluppo
+ .ConfigureWarnings(w => w.Ignore(CoreEventId.ManyServiceProvidersCreatedWarning)));
+
+// MP.Data DbContext for Stats repositories
+string utilsConnString = builder.Configuration.GetConnectionString("MP.Utils") ?? "Server=localhost;Database=MoonPro_Utils; integrated security=True; MultipleActiveResultSets=True; App=MP.IOC;";
+builder.Services.AddDbContextFactory(options =>
+ options.UseSqlServer(utilsConnString));
+
+// MP.Data Services Utils - Statistiche DB
+builder.Services.AddIocDataLayer();
+
+// 1. Configurazione dell'invoker personalizzato (Risolve i tuoi errori)
+var httpClientInvoker = new HttpMessageInvoker(new SocketsHttpHandler
+{
+ UseProxy = false,
+ AllowAutoRedirect = false,
+ AutomaticDecompression = DecompressionMethods.None,
+ UseCookies = false,
+ // Correzione per il tracing: usa il propagatore corrente di sistema
+ ActivityHeadersPropagator = DistributedContextPropagator.Current,
+ ConnectTimeout = TimeSpan.FromSeconds(30),
+
+ // Gestione certificato (ignora errori per localhost/test)
+ SslOptions = new System.Net.Security.SslClientAuthenticationOptions
+ {
+ RemoteCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
+ }
+});
+
+builder.Services.AddSingleton(httpClientInvoker);
+builder.Services.AddHttpForwarder();
+
+// avvio oggetto shared x redis...
+var redisMux = ConnectionMultiplexer.Connect(confRedis);
+builder.Services.AddSingleton(redisMux);
+
+// Registrazione dei servizi custom
+builder.Services.AddSingleton();
+builder.Services.AddSingleton();
+builder.Services.AddHostedService();
+builder.Services.AddHostedService();
+builder.Services.AddSingleton();
+
+logger.Info("Standard service configured");
+
+// WeightProvider: Redis/Memory da config
+var weightOnRedis = builder.Configuration.GetValue("ServerConf:RedisWeight", false);
+if (weightOnRedis)
+{
+ builder.Services.AddSingleton();
+}
+else
+{
+ builder.Services.AddSingleton();
+}
+logger.Info($"Weight service configured | use Redis: {weightOnRedis}");
+
+// RouteManager registration (singleton)
+builder.Services.AddSingleton();
+logger.Info("Singleton Route Manager registered");
+
+// aggiunta pagina razor di stato
+builder.Services.AddRazorPages();
+
+var app = builder.Build();
+
+// Blocco per la migrazione automatica del DB Utils...
+using (var scope = app.Services.CreateScope())
+{
+ var services = scope.ServiceProvider;
+ try
+ {
+ var context = services.GetRequiredService();
+ context.Database.Migrate();
+ }
+ catch (Exception ex)
+ {
+ var migrateLogger = services.GetRequiredService>();
+ migrateLogger.LogError(ex, "Si � verificato un errore durante l'aggiornamento del database.");
+ }
+}
+
+// 1. Configurazione Base Path
+string baseUrl = configuration.GetValue("ServerConf:BaseUrlIoc") ?? "/MP/RIOC";
+app.UsePathBase(baseUrl);
+
+// 2. Middleware statici (essenziali per CSS/JS delle pagine Razor)
+app.UseStaticFiles();
+
+// 3. Abilita il Routing (necessario per MapGet e MapRazorPages)
+app.UseRouting();
+
+// 4. Logging middleware
+app.Use(async (ctx, next) =>
+{
+ logger.Debug($"Incoming request PathBase='{ctx.Request.PathBase}' Path='{ctx.Request.Path}'");
+ await next();
+});
+
+// 5. Il cuore del Proxy (MapWhen è terminale per le richieste che lo soddisfano)
+string routePath = configuration.GetValue("ServerConf:RoutePath") ?? "/api/IOB";
+string fullPath = $"{baseUrl}{routePath}".Replace("//", "/");
+logger.Info($"BaseUrl: {baseUrl}");
+app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments(routePath, StringComparison.OrdinalIgnoreCase),
+ builder =>
+ {
+ builder.Run(async ctx =>
+ {
+ var routeManager = ctx.RequestServices.GetRequiredService();
+ await routeManager.HandleAsync(ctx);
+ });
+ });
+
+// 6. Definizione degli Endpoints locali
+app.MapRazorPages();
+
+app.MapGet("/router-status", (RouteStatsManager stats) => Results.Ok(new
+{
+ Status = "Online",
+ Version = assemblyVersion,
+ Mode = weightOnRedis ? "Redis" : "InMemory",
+ Time = DateTime.Now,
+ Metrics = stats.Snapshot()
+}));
+
+// 7. Fallback "intelligente"
+// Invece di app.Run, usiamo MapFallback che viene eseguito SOLO se nessun altro endpoint o MapWhen ha risposto
+app.MapFallback(async context =>
+{
+ context.Response.StatusCode = 404;
+ await context.Response.WriteAsync("Router: Endpoint non trovato o non mappato.");
+});
+
+app.Run();
\ No newline at end of file
diff --git a/MP-RIOC/Properties/PublishProfiles/IIS01.pubxml b/MP-RIOC/Properties/PublishProfiles/IIS01.pubxml
new file mode 100644
index 00000000..9278d2ad
--- /dev/null
+++ b/MP-RIOC/Properties/PublishProfiles/IIS01.pubxml
@@ -0,0 +1,32 @@
+
+
+
+
+ MSDeploy
+ true
+ Release
+ Any CPU
+ https://iis01.egalware.com/MP/RIOC/
+ false
+ b9188473-f4ae-4f9f-be2d-70edaace0db9
+ false
+ https://iis01.egalware.com:8172/MsDeploy.axd
+ Default Web Site/MP/RIOC
+
+ false
+ WMSVC
+ true
+ true
+ jenkins
+ <_SavePWD>true
+ <_TargetId>IISWebDeploy
+ net8.0
+ win-x64
+
+
+
+ filePath
+ logs\\.*\.log$
+
+
+
\ No newline at end of file
diff --git a/MP-RIOC/Properties/PublishProfiles/IIS01.pubxml.user b/MP-RIOC/Properties/PublishProfiles/IIS01.pubxml.user
new file mode 100644
index 00000000..3b31eede
--- /dev/null
+++ b/MP-RIOC/Properties/PublishProfiles/IIS01.pubxml.user
@@ -0,0 +1,10 @@
+
+
+
+
+ True|2026-05-08T09:24:06.9798007Z||;True|2026-05-08T11:21:55.9425582+02:00||;True|2026-05-08T11:20:08.8391895+02:00||;True|2026-05-08T11:10:23.1435148+02:00||;True|2026-05-08T11:06:12.1010825+02:00||;True|2026-05-08T10:36:29.2623112+02:00||;False|2026-05-08T10:35:26.8348462+02:00||;True|2026-05-08T10:03:20.5314448+02:00||;True|2026-05-08T09:56:52.4040695+02:00||;True|2026-05-08T09:51:01.5094407+02:00||;False|2026-05-08T09:50:28.6127819+02:00||;False|2026-05-08T09:50:16.2479705+02:00||;True|2026-05-08T09:49:12.5533796+02:00||;True|2026-05-08T09:47:48.2838701+02:00||;True|2026-05-08T09:46:52.6514721+02:00||;True|2026-05-08T09:46:30.4584308+02:00||;True|2026-05-08T09:46:00.3430830+02:00||;True|2026-05-08T09:44:50.2145461+02:00||;False|2026-05-08T09:42:53.1130763+02:00||;True|2026-05-08T09:34:45.8167687+02:00||;False|2026-05-08T09:34:21.4017890+02:00||;True|2026-05-08T09:24:04.8527556+02:00||;False|2026-05-08T09:04:47.5869659+02:00||;False|2026-05-08T09:01:28.1405561+02:00||;False|2026-05-08T09:00:37.4358771+02:00||;False|2026-05-08T08:58:53.9394322+02:00||;False|2026-05-08T08:57:18.3710854+02:00||;False|2026-05-08T08:56:39.0642155+02:00||;True|2026-05-08T08:36:15.4113336+02:00||;False|2026-05-08T08:35:31.1992313+02:00||;False|2026-05-08T08:34:56.3101908+02:00||;False|2026-05-08T08:34:41.2943768+02:00||;True|2026-05-08T08:28:29.2065443+02:00||;
+
+
+ AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAlmCNMQ0J1UqPM+RugOqtLgAAAAACAAAAAAAQZgAAAAEAACAAAABmDmKQdTOJuzYQ2FFyU+1htQ8H/TQ+IM9D7RchZs6pvgAAAAAOgAAAAAIAACAAAABeb+XK2KUWpsQ2fiYxFKeezXYyZloQPjo9Qkmjbf+FlyAAAAAR+ckV3KTLXMIMyW4f5PBdp6Uxv5tWJ5LldbO4N+tXYUAAAACJwytTC9fJKy3wyHTlSVYRd/OdBUQ8pCweu3wSK3CGvcpgwT+VFYooELXfzgEV8l6P6FrAdGoF0gt9O3yyn1X4
+
+
\ No newline at end of file
diff --git a/MP-RIOC/Properties/PublishProfiles/IIS03.pubxml b/MP-RIOC/Properties/PublishProfiles/IIS03.pubxml
new file mode 100644
index 00000000..e2916a71
--- /dev/null
+++ b/MP-RIOC/Properties/PublishProfiles/IIS03.pubxml
@@ -0,0 +1,25 @@
+
+
+
+
+ MSDeploy
+ true
+ Release
+ Any CPU
+ https://iis03.egalware.com/MP/RIOC/
+ false
+ b9188473-f4ae-4f9f-be2d-70edaace0db9
+ false
+ https://iis03.egalware.com:8172/MsDeploy.axd
+ Default Web Site/MP/RIOC
+
+ false
+ WMSVC
+ true
+ true
+ jenkins
+ <_SavePWD>true
+ <_TargetId>IISWebDeploy
+ net8.0
+
+
\ No newline at end of file
diff --git a/MP-RIOC/Properties/PublishProfiles/IIS04.pubxml b/MP-RIOC/Properties/PublishProfiles/IIS04.pubxml
new file mode 100644
index 00000000..0322e090
--- /dev/null
+++ b/MP-RIOC/Properties/PublishProfiles/IIS04.pubxml
@@ -0,0 +1,25 @@
+
+
+
+
+ MSDeploy
+ true
+ Release
+ Any CPU
+ https://iis04.egalware.com/MP/RIOC/
+ false
+ b9188473-f4ae-4f9f-be2d-70edaace0db9
+ false
+ https://iis04.egalware.com:8172/MsDeploy.axd
+ Default Web Site/MP/RIOC
+
+ false
+ WMSVC
+ true
+ true
+ jenkins
+ <_SavePWD>true
+ <_TargetId>IISWebDeploy
+ net8.0
+
+
\ No newline at end of file
diff --git a/MP-RIOC/Properties/PublishProfiles/IISProfile.pubxml b/MP-RIOC/Properties/PublishProfiles/IISProfile.pubxml
new file mode 100644
index 00000000..43da778a
--- /dev/null
+++ b/MP-RIOC/Properties/PublishProfiles/IISProfile.pubxml
@@ -0,0 +1,20 @@
+
+
+
+
+ Package
+ Release
+ Any CPU
+
+ true
+ false
+ f3794272-87ad-7c42-2528-6b119dbbc4d5
+ bin\publish\MP.RIOC.zip
+ true
+ Default Web Site/MP/RIOC
+ <_TargetId>IISWebDeployPackage
+ net8.0
+ win-x64
+ false
+
+
\ No newline at end of file
diff --git a/MP-RIOC/Properties/PublishProfiles/IISProfile.pubxml.user b/MP-RIOC/Properties/PublishProfiles/IISProfile.pubxml.user
new file mode 100644
index 00000000..3224acae
--- /dev/null
+++ b/MP-RIOC/Properties/PublishProfiles/IISProfile.pubxml.user
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MP-RIOC/Properties/launchSettings.json b/MP-RIOC/Properties/launchSettings.json
new file mode 100644
index 00000000..b57a323d
--- /dev/null
+++ b/MP-RIOC/Properties/launchSettings.json
@@ -0,0 +1,41 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:15280",
+ "sslPort": 44323
+ }
+ },
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "MP/RIOC/api/IOB/",
+ "applicationUrl": "http://localhost:5290",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "MP/RIOC/api/IOB/",
+ "applicationUrl": "https://localhost:7120;http://localhost:5290",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "MP/RIOC/api/IOB/",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/MP.IOC/RedisScript/RedisUpdateScript_v5.lua b/MP-RIOC/RedisScript/RedisUpdateScript_v5.lua
similarity index 100%
rename from MP.IOC/RedisScript/RedisUpdateScript_v5.lua
rename to MP-RIOC/RedisScript/RedisUpdateScript_v5.lua
diff --git a/MP.IOC/RedisScript/RedisUpdateScript_v6.lua b/MP-RIOC/RedisScript/RedisUpdateScript_v6.lua
similarity index 100%
rename from MP.IOC/RedisScript/RedisUpdateScript_v6.lua
rename to MP-RIOC/RedisScript/RedisUpdateScript_v6.lua
diff --git a/MP-RIOC/Resources/ChangeLog-original.html b/MP-RIOC/Resources/ChangeLog-original.html
new file mode 100644
index 00000000..2ec27a72
--- /dev/null
+++ b/MP-RIOC/Resources/ChangeLog-original.html
@@ -0,0 +1,31 @@
+
+ Modulo MP-RIOC
+ Versione: {{CURRENT-REL}}
+
Note di rilascio:
+
+ -
+ Ultime modifiche:
+
+
+ -
+ v.8.16.* →
+
+ - Ottimizzazioni varie x Redis
+
+
+ -
+ v.8.16.* →
+
+ - Prima release dotNet 8.0 router
+
+
+
+
+
+

+
+
+
+
\ No newline at end of file
diff --git a/MP-RIOC/Resources/ChangeLog.html b/MP-RIOC/Resources/ChangeLog.html
new file mode 100644
index 00000000..f24ab287
--- /dev/null
+++ b/MP-RIOC/Resources/ChangeLog.html
@@ -0,0 +1,31 @@
+
+ Modulo MP-RIOC
+ Versione: 8.16.2605.812
+
Note di rilascio:
+
+ -
+ Ultime modifiche:
+
+
+ -
+ v.8.16.* →
+
+ - Ottimizzazioni varie x Redis
+
+
+ -
+ v.8.16.* →
+
+ - Prima release dotNet 8.0 router
+
+
+
+
+
+

+
+
+
+
diff --git a/MP-RIOC/Resources/VersNum.txt b/MP-RIOC/Resources/VersNum.txt
new file mode 100644
index 00000000..3ac974ab
--- /dev/null
+++ b/MP-RIOC/Resources/VersNum.txt
@@ -0,0 +1 @@
+8.16.2605.812
diff --git a/MP-RIOC/Resources/logoSteamware.png b/MP-RIOC/Resources/logoSteamware.png
new file mode 100644
index 00000000..0958b50a
Binary files /dev/null and b/MP-RIOC/Resources/logoSteamware.png differ
diff --git a/MP-RIOC/Resources/manifest-original.xml b/MP-RIOC/Resources/manifest-original.xml
new file mode 100644
index 00000000..f95e0763
--- /dev/null
+++ b/MP-RIOC/Resources/manifest-original.xml
@@ -0,0 +1,7 @@
+
+-
+ 1.0.0.0
+ https://nexus.steamware.net/repository/SWS/{{DIRNAME}}/{{BRANCHNAME}}/{{PACKNAME}}.zip
+ https://nexus.steamware.net/repository/SWS/{{DIRNAME}}/{{BRANCHNAME}}/ChangeLog.html
+ false
+
diff --git a/MP-RIOC/Resources/manifest.xml b/MP-RIOC/Resources/manifest.xml
new file mode 100644
index 00000000..3cb930b3
--- /dev/null
+++ b/MP-RIOC/Resources/manifest.xml
@@ -0,0 +1,7 @@
+
+-
+ 8.16.2605.812
+ https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/MP.IOC.zip
+ https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/ChangeLog.html
+ false
+
diff --git a/MP-RIOC/Services/IWeightProvider.cs b/MP-RIOC/Services/IWeightProvider.cs
new file mode 100644
index 00000000..b18e4fcb
--- /dev/null
+++ b/MP-RIOC/Services/IWeightProvider.cs
@@ -0,0 +1,29 @@
+using MP.Core.DTO;
+
+namespace MP.RIOC.Services
+{
+ public interface IWeightProvider
+ {
+ #region Public Methods
+
+ ///
+ /// Ritorna l'intero elenco dei weight attivi nel formato WeightDTO
+ ///
+ ///
+ Task> GetAllWeightsAsync();
+
+ ///
+ /// Ritorna la coppia (oldWeight, newWeight) per scegliere dove instradare il metodo tra i 2 sistemi API.
+ ///
+ (int oldWeight, int newWeight) GetWeightsFor(string method);
+
+ ///
+ /// Aggiorna/Aggiuinge il valore del weight richiesto
+ ///
+ ///
+ ///
+ bool UpsertWeight(WeightDTO updRecord);
+
+ #endregion Public Methods
+ }
+}
diff --git a/MP-RIOC/Services/InMemoryWeightProvider.cs b/MP-RIOC/Services/InMemoryWeightProvider.cs
new file mode 100644
index 00000000..f4baf415
--- /dev/null
+++ b/MP-RIOC/Services/InMemoryWeightProvider.cs
@@ -0,0 +1,56 @@
+using MP.Core.DTO;
+using System.Collections.Concurrent;
+
+namespace MP.RIOC.Services
+{
+ public class InMemoryWeightProvider : IWeightProvider
+ {
+ private readonly ConcurrentDictionary _map = new();
+ private readonly int _defaultOld;
+ private readonly int _defaultNew;
+
+ public InMemoryWeightProvider(IConfiguration config)
+ {
+ _defaultOld = config.GetValue("RouteMan:DefaultWeightOld", 100);
+ _defaultNew = config.GetValue("RouteMan:DefaultWeightNew", 0);
+ }
+
+ public (int oldWeight, int newWeight) GetWeightsFor(string method)
+ {
+ if (string.IsNullOrEmpty(method)) method = "unknown";
+ return _map.GetOrAdd(method, _ => (_defaultOld, _defaultNew));
+ }
+
+ public void SetWeights(string method, int oldWeight, int newWeight)
+ {
+ _map[method] = (Math.Clamp(oldWeight, 0, 100), Math.Clamp(newWeight, 0, 100));
+ }
+
+ public async Task> GetAllWeightsAsync()
+ {
+ var result = new List();
+ await Task.Delay(1);
+
+ foreach (var kvp in _map)
+ {
+ result.Add(new WeightDTO
+ {
+ Method = kvp.Key,
+ OldWeight = Math.Clamp(kvp.Value.oldW, 0, 100),
+ NewWeight = Math.Clamp(kvp.Value.newW, 0, 100)
+ });
+ }
+ return result;
+ }
+
+ public bool UpsertWeight(WeightDTO updRecord)
+ {
+ if (updRecord == null || string.IsNullOrEmpty(updRecord.Method))
+ return false;
+
+ _map[updRecord.Method] = (Math.Clamp(updRecord.OldWeight, 0, 100), Math.Clamp(updRecord.NewWeight, 0, 100));
+
+ return true;
+ }
+ }
+}
diff --git a/MP.IOC/Services/LuaScriptProvider.cs b/MP-RIOC/Services/LuaScriptProvider.cs
similarity index 97%
rename from MP.IOC/Services/LuaScriptProvider.cs
rename to MP-RIOC/Services/LuaScriptProvider.cs
index c7eb1e58..41951353 100644
--- a/MP.IOC/Services/LuaScriptProvider.cs
+++ b/MP-RIOC/Services/LuaScriptProvider.cs
@@ -1,7 +1,7 @@
using Microsoft.Extensions.Options;
using MP.Core.Conf;
-namespace MP.IOC.Services
+namespace MP.RIOC.Services
{
public sealed class LuaScriptProvider
{
@@ -39,5 +39,4 @@ namespace MP.IOC.Services
return script;
}
}
-
}
diff --git a/MP.IOC/Services/MetricsCalcService.cs b/MP-RIOC/Services/MetricsCalcService.cs
similarity index 99%
rename from MP.IOC/Services/MetricsCalcService.cs
rename to MP-RIOC/Services/MetricsCalcService.cs
index b9918619..81c164c4 100644
--- a/MP.IOC/Services/MetricsCalcService.cs
+++ b/MP-RIOC/Services/MetricsCalcService.cs
@@ -1,8 +1,8 @@
-using NLog;
+using NLog;
using StackExchange.Redis;
using System.Globalization;
-namespace MP.IOC.Services
+namespace MP.RIOC.Services
{
public class MetricsCalcService : BackgroundService
{
@@ -55,7 +55,7 @@ namespace MP.IOC.Services
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
- var interval = _config.GetValue("RouteMan:MetricCalcIntervalSeconds", 20);
+ var interval = _config.GetValue("RouteMan:MetricCalcIntervalSeconds", 30);
while (!stoppingToken.IsCancellationRequested)
{
diff --git a/MP.IOC/Services/MetricsDbFlushService.cs b/MP-RIOC/Services/MetricsDbFlushService.cs
similarity index 94%
rename from MP.IOC/Services/MetricsDbFlushService.cs
rename to MP-RIOC/Services/MetricsDbFlushService.cs
index 4aef9eb7..ba6444b2 100644
--- a/MP.IOC/Services/MetricsDbFlushService.cs
+++ b/MP-RIOC/Services/MetricsDbFlushService.cs
@@ -1,10 +1,10 @@
-using MP.Data.DbModels.Utils;
+using MP.Data.DbModels.Utils;
using MP.Data.Services.Utils;
using NLog;
using StackExchange.Redis;
using System.Globalization;
-namespace MP.IOC.Services
+namespace MP.RIOC.Services
{
public class MetricsDbFlushService : BackgroundService
{
@@ -27,8 +27,7 @@ namespace MP.IOC.Services
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
- //var interval = _config.GetValue("RouteMan:MetricFlushIntervalSeconds", 120);
- var interval = _config.GetValue("RouteMan:MetricFlushIntervalSeconds", 300);
+ var interval = _config.GetValue("RouteMan:MetricFlushIntervalSeconds", 180);
while (!stoppingToken.IsCancellationRequested)
{
@@ -97,6 +96,7 @@ namespace MP.IOC.Services
$"{_redisBaseKey}:stats:days:*"
};
+ var batch = _db.CreateBatch();
foreach (var pattern in patternsToScan)
{
// Nota: KeyScanAsync/KeysAsync e' disponibile su IServer
@@ -122,7 +122,12 @@ namespace MP.IOC.Services
// Se fosse scaduta e abbiamo il permesso, segnamola per la cancellazione
if (isExpired && deleteConfirmed)
{
+ // 1. Segna la chiave Hash (Dati) per l'eliminazione
keysToDelete.Add(sKey);
+
+ // 2. CORREZIONE: Devi rimuovere il riferimento dal Sorted Set (Indice)
+ // Usiamo il batch per essere efficienti
+ _ = batch.SortedSetRemoveAsync(indexKey, statKey);
}
// Recupero dati dalla Hash
@@ -162,6 +167,7 @@ namespace MP.IOC.Services
}
}
}
+ batch.Execute();
}
// --- FASE UPSERT DB ---
@@ -219,6 +225,7 @@ namespace MP.IOC.Services
$"{_redisBaseKey}:stats:hours:*"
};
+ var batch = _db.CreateBatch();
foreach (var pattern in patternsToScan)
{
// Nota: KeyScanAsync/KeysAsync e' disponibile su IServer
@@ -244,7 +251,12 @@ namespace MP.IOC.Services
// Se fosse scaduta e abbiamo il permesso, segnamola per la cancellazione
if (isExpired && deleteConfirmed)
{
+ // 1. Segna la chiave Hash (Dati) per l'eliminazione
keysToDelete.Add(sKey);
+
+ // 2. CORREZIONE: Devi rimuovere il riferimento dal Sorted Set (Indice)
+ // Usiamo il batch per essere efficienti
+ _ = batch.SortedSetRemoveAsync(indexKey, statKey);
}
// Recupero dati dalla Hash
@@ -284,6 +296,7 @@ namespace MP.IOC.Services
}
}
}
+ batch.Execute();
}
// --- FASE UPSERT DB ---
@@ -365,4 +378,4 @@ namespace MP.IOC.Services
#endregion Private Methods
}
-}
\ No newline at end of file
+}
diff --git a/MP.IOC/Services/PreserveBodyTransformer.cs b/MP-RIOC/Services/PreserveBodyTransformer.cs
similarity index 98%
rename from MP.IOC/Services/PreserveBodyTransformer.cs
rename to MP-RIOC/Services/PreserveBodyTransformer.cs
index c8d6ed33..2434f658 100644
--- a/MP.IOC/Services/PreserveBodyTransformer.cs
+++ b/MP-RIOC/Services/PreserveBodyTransformer.cs
@@ -1,8 +1,7 @@
using Yarp.ReverseProxy.Forwarder;
-namespace MP.IOC.Services
+namespace MP.RIOC.Services
{
-
public class PreserveBodyTransformer : HttpTransformer
{
public override async ValueTask TransformRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest, string destinationPrefix, CancellationToken cancellationToken)
@@ -36,6 +35,4 @@ namespace MP.IOC.Services
return base.TransformResponseAsync(httpContext, proxyResponse, cancellationToken);
}
}
-
-
}
diff --git a/MP-RIOC/Services/RedisWeightProvider.cs b/MP-RIOC/Services/RedisWeightProvider.cs
new file mode 100644
index 00000000..e003c8e5
--- /dev/null
+++ b/MP-RIOC/Services/RedisWeightProvider.cs
@@ -0,0 +1,157 @@
+using MP.Core.DTO;
+using StackExchange.Redis;
+
+namespace MP.RIOC.Services
+{
+ public class RedisWeightProvider : IWeightProvider
+ {
+ #region Public Constructors
+
+ public RedisWeightProvider(IConnectionMultiplexer mux, IConfiguration config)
+ {
+ _config = config;
+ _db = mux.GetDatabase();
+ _mux = mux;
+ _defaultOld = config.GetValue("RouteMan:DefaultWeightOld", 100);
+ _defaultNew = config.GetValue("RouteMan:DefaultWeightNew", 0);
+ _redisBaseKey = config.GetValue("ServerConf:RedisBaseKey") ?? "MP_IOC";
+ _keyPrefix = $"{_redisBaseKey}:route_weight:";
+ }
+
+ #endregion Public Constructors
+
+ #region Public Methods
+
+ ///
+ /// Ritorna (oldWeight, newWeight) per il metodo. Se non esiste, crea la chiave con i default.
+ ///
+ public (int oldWeight, int newWeight) GetWeightsFor(string method)
+ {
+ if (string.IsNullOrEmpty(method)) method = "unknown";
+ var key = _keyPrefix + method;
+
+ // Leggi entrambi i campi
+ var oldVal = _db.HashGet(key, "old");
+ var newVal = _db.HashGet(key, "new");
+
+ // Se entrambi mancanti, inizializza con default (usando HSet con When.NotExists per evitare overwrite)
+ if (oldVal.IsNull && newVal.IsNull)
+ {
+ // Imposta i campi singolarmente con When.NotExists per evitare overwrite
+ _db.HashSet(key, "old", _defaultOld, When.NotExists);
+ _db.HashSet(key, "new", _defaultNew, When.NotExists);
+
+ // Rileggi per essere sicuri
+ oldVal = _db.HashGet(key, "old");
+ newVal = _db.HashGet(key, "new");
+ }
+
+ // Se uno dei due manca, impostalo al default (non sovrascrive l'altro)
+ if (oldVal.IsNull)
+ {
+ _db.HashSet(key, "old", _defaultOld, When.NotExists);
+ oldVal = _defaultOld;
+ }
+ if (newVal.IsNull)
+ {
+ _db.HashSet(key, "new", _defaultNew, When.NotExists);
+ newVal = _defaultNew;
+ }
+
+ if (!int.TryParse(oldVal.ToString(), out var oldW)) oldW = _defaultOld;
+ if (!int.TryParse(newVal.ToString(), out var newW)) newW = _defaultNew;
+
+ // clamp 0..100
+ oldW = Math.Clamp(oldW, 0, 100);
+ newW = Math.Clamp(newW, 0, 100);
+
+ return (oldW, newW);
+ }
+
+ // API per aggiornare i pesi a runtime (opzionale)
+ public void SetWeights(string method, int oldWeight, int newWeight)
+ {
+ var key = _keyPrefix + (string.IsNullOrEmpty(method) ? "unknown" : method);
+ _db.HashSet(key, new HashEntry[] {
+ new HashEntry("old", Math.Clamp(oldWeight,0,100)),
+ new HashEntry("new", Math.Clamp(newWeight,0,100))
+ });
+ }
+
+ public async Task> GetAllWeightsAsync()
+ {
+ var result = new List();
+ var server = _mux.GetServer(_mux.GetEndPoints().First());
+
+ if (server.IsReplica)
+ {
+ return result;
+ }
+
+ await foreach (var key in server.KeysAsync(pattern: $"{_keyPrefix}*"))
+ {
+ var methodName = KeyToString(key.ToString());
+ if (string.IsNullOrEmpty(methodName)) continue;
+
+ var oldVal = _db.HashGet(key, "old");
+ var newVal = _db.HashGet(key, "new");
+
+ int oldW = 100;
+ int newW = 0;
+
+ if (!oldVal.IsNull && int.TryParse(oldVal.ToString(), out var parsedOld))
+ oldW = Math.Clamp(parsedOld, 0, 100);
+
+ if (!newVal.IsNull && int.TryParse(newVal.ToString(), out var parsedNew))
+ newW = Math.Clamp(parsedNew, 0, 100);
+
+ result.Add(new WeightDTO { Method = methodName, OldWeight = oldW, NewWeight = newW });
+ }
+
+ // riordino desc x NEW poi alfabetico...
+ result = result
+ .OrderByDescending(x => x.NewWeight)
+ .ThenBy(x => x.Method)
+ .ToList();
+
+ return result;
+ }
+
+ public bool UpsertWeight(WeightDTO updRecord)
+ {
+ if (updRecord == null || string.IsNullOrEmpty(updRecord.Method))
+ return false;
+
+ var key = _keyPrefix + updRecord.Method;
+ _db.HashSet(key, new HashEntry[] {
+ new HashEntry("old", Math.Clamp(updRecord.OldWeight, 0, 100)),
+ new HashEntry("new", Math.Clamp(updRecord.NewWeight, 0, 100))
+ });
+
+ return true;
+ }
+
+ private string KeyToString(string key)
+ {
+ if (string.IsNullOrEmpty(key)) return "";
+ var prefix = _keyPrefix ?? "";
+ if (key.StartsWith(prefix))
+ return key.Substring(prefix.Length);
+ return key;
+ }
+
+ #endregion Public Methods
+
+ #region Private Fields
+
+ private static string _keyPrefix = "route_weight:";
+ private static string _redisBaseKey = "";
+ private readonly IConfiguration _config;
+ private readonly IDatabase _db;
+ private readonly IConnectionMultiplexer _mux;
+ private readonly int _defaultNew;
+ private readonly int _defaultOld;
+
+ #endregion Private Fields
+ }
+}
diff --git a/MP.IOC/Services/RouteManager.cs b/MP-RIOC/Services/RouteManager.cs
similarity index 82%
rename from MP.IOC/Services/RouteManager.cs
rename to MP-RIOC/Services/RouteManager.cs
index 529996e6..3febe3c9 100644
--- a/MP.IOC/Services/RouteManager.cs
+++ b/MP-RIOC/Services/RouteManager.cs
@@ -2,10 +2,8 @@
using System.Diagnostics;
using Yarp.ReverseProxy.Forwarder;
-namespace MP.IOC.Services
+namespace MP.RIOC.Services
{
-
-
public class RouteManager
{
private readonly IHttpForwarder _forwarder;
@@ -14,6 +12,7 @@ namespace MP.IOC.Services
private readonly RouteStatsManager _stats;
private readonly IWeightProvider _weightProvider;
private readonly IConfiguration _config;
+ private readonly ForwarderRequestConfig _forwarderConfig;
public RouteManager(
IHttpForwarder forwarder,
@@ -29,7 +28,16 @@ namespace MP.IOC.Services
_stats = stats;
_weightProvider = weightProvider;
_config = config;
- _routePath = _config.GetValue("ServerConf:RoutePath") ?? "/api/RIOB";
+ _routePath = _config.GetValue("ServerConf:RoutePath") ?? "/api/IOB";
+ _forwarderConfig = new ForwarderRequestConfig
+ {
+ ActivityTimeout = TimeSpan.FromSeconds(30),
+ // Parse della versione (es. "1.1")
+ Version = Version.Parse(_config.GetValue("ServerConf:HttpVersion") ?? "1.1"),
+ // Policy per la versione
+ VersionPolicy = _config.GetValue("ServerConf:HttpVersionPolicy")
+ ?? HttpVersionPolicy.RequestVersionExact
+ };
}
private string _routePath = "";
@@ -74,23 +82,8 @@ namespace MP.IOC.Services
// Splitto per /
var parts = pathOnly.Split('/', StringSplitOptions.RemoveEmptyEntries);
- if (parts.Length > 0)
- metodo = parts[0];
-
- if (parts.Length > 1)
- id = parts[1];
-
-#if false
- // splitto se ho /...
- if (relativePath.Contains("/"))
- {
- metodo = relativePath.Substring(0, relativePath.IndexOf("/"));
- }
- else
- {
- metodo = relativePath;
- }
-#endif
+ if (parts.Length > 0) metodo = parts[0];
+ if (parts.Length > 1) id = parts[1];
}
Log.Debug($"Metodo: {metodo} | machineId: {id}");
@@ -101,8 +94,8 @@ namespace MP.IOC.Services
// Costruisci destination base in base al target
var destBase = pickNew
- ? _config["ReverseProxy:Clusters:cluster-new:Destinations:new1:Address"]
- : _config["ReverseProxy:Clusters:cluster-old:Destinations:old1:Address"];
+ ? _config["ServerConf:NewApiUrl"]
+ : _config["ServerConf:OldApiUrl"];
if (string.IsNullOrEmpty(destBase))
{
@@ -130,8 +123,7 @@ namespace MP.IOC.Services
Log.Debug($"Forwarding to base {destBase} with forwarded path {context.Request.Path} | original PathBase:{originalPathBase} | Path={originalPath})");
- var requestOptions = new ForwarderRequestConfig { ActivityTimeout = TimeSpan.FromSeconds(100) };
- var error = await _forwarder.SendAsync(context, destBase, _httpClientInvoker, requestOptions, _transformer, context.RequestAborted);
+ var error = await _forwarder.SendAsync(context, destBase, _httpClientInvoker, _forwarderConfig, _transformer, context.RequestAborted);
sw.Stop();
_stats.RecordDuration(sKey, sw.Elapsed);
@@ -140,8 +132,11 @@ namespace MP.IOC.Services
{
var feat = context.GetForwarderErrorFeature();
Log.Error(feat?.Exception, "Forwarder error to {DestBase}", destBase);
- context.Response.StatusCode = 502;
- await context.Response.WriteAsync($"Forward error: {feat?.Exception?.Message}");
+ if (!context.Response.HasStarted)
+ {
+ context.Response.StatusCode = 502;
+ await context.Response.WriteAsync($"Forward error: {feat?.Exception?.Message}");
+ }
}
}
finally
@@ -169,5 +164,4 @@ namespace MP.IOC.Services
return result;
}
}
-
}
diff --git a/MP.IOC/Services/RouteStatsManager.cs b/MP-RIOC/Services/RouteStatsManager.cs
similarity index 93%
rename from MP.IOC/Services/RouteStatsManager.cs
rename to MP-RIOC/Services/RouteStatsManager.cs
index 2af2edee..9274826a 100644
--- a/MP.IOC/Services/RouteStatsManager.cs
+++ b/MP-RIOC/Services/RouteStatsManager.cs
@@ -1,6 +1,6 @@
-using System.Collections.Concurrent;
+using System.Collections.Concurrent;
-namespace MP.IOC.Services
+namespace MP.RIOC.Services
{
public class RouteStats
{
@@ -9,6 +9,7 @@ namespace MP.IOC.Services
public TimeSpan MaxDuration = TimeSpan.Zero;
public TimeSpan MinDuration = TimeSpan.MaxValue;
public ConcurrentDictionary StatusCodes = new();
+ public TimeSpan AvgDuration => TotalDuration / (Count > 0 ? Count : 1);
}
public class RouteStatsManager
diff --git a/MP-RIOC/appsettings.Development.json b/MP-RIOC/appsettings.Development.json
new file mode 100644
index 00000000..b14a27c9
--- /dev/null
+++ b/MP-RIOC/appsettings.Development.json
@@ -0,0 +1,13 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "ServerConf": {
+ "useFactory": false,
+ "OldApiUrl": "http://localhost/MP/IO/IOB/",
+ "NewApiUrl": "http://localhost/MP/IOC/api/IOB/"
+ }
+}
diff --git a/MP-RIOC/appsettings.Production.json b/MP-RIOC/appsettings.Production.json
new file mode 100644
index 00000000..7a752d3d
--- /dev/null
+++ b/MP-RIOC/appsettings.Production.json
@@ -0,0 +1,26 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*",
+ "CodApp": "MP.RIOC",
+ "ConnectionStrings": {
+ "MP.Data": "Server=localhost\\SQLEXPRESS;Database=MoonPro;User ID=steamware;Password=viadante16; integrated security=False; MultipleActiveResultSets=True; App=MP.RIOC;",
+ "MP.Utils": "Server=localhost\\SQLEXPRESS;Database=MoonPro_Utils; User ID=steamware;Password=viadante16; integrated security=False; App=MP.RIOC;",
+ "Redis": "localhost:6379,DefaultDatabase=5,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,abortConnect=false,ssl=false",
+ "RedisAdmin": "localhost:6379,DefaultDatabase=5,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,abortConnect=false,ssl=false,allowAdmin=true"
+ },
+ "ServerConf": {
+ "useFactory": false,
+ "OldApiUrl": "http://maposrv.egalware.com/MP/IO/IOB/",
+ "NewApiUrl": "http://maposrv.egalware.com/MP/IOC/api/IOB/"
+ },
+ "RedisScripts": {
+ "Scripts": {
+ "Update": "RedisScript/RedisUpdateScript_v5.lua"
+ }
+ }
+}
diff --git a/MP-RIOC/appsettings.json b/MP-RIOC/appsettings.json
new file mode 100644
index 00000000..590b8fb4
--- /dev/null
+++ b/MP-RIOC/appsettings.json
@@ -0,0 +1,86 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Yarp": "Debug",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*",
+ "NLog": {
+ "variables": {
+ "baseFileDir": "${basedir}/logs/",
+ "layout": "${longdate} | ${uppercase:${level}} | ${logger:shortName=false} | ${message}"
+ },
+ "extensions": [
+ { "assembly": "NLog.Extensions.Logging" },
+ { "assembly": "NLog.Web.AspNetCore" }
+ ],
+ "throwConfigExceptions": true,
+ "targets": {
+ "async": true,
+ "logfile": {
+ "type": "File",
+ "fileName": "${basedir}/logs/${shortdate}.log",
+ "keepFileOpen": false,
+ "archiveEvery": "Day",
+ "archiveFileName": "${basedir}/logs/old/${shortdate}_{#}.log",
+ "archiveNumbering": "DateAndSequence",
+ "archiveAboveSize": "10240000",
+ "archiveDateFormat": "HH",
+ "maxArchiveFiles": "60",
+ "maxArchiveDays": "30"
+ },
+ "logconsole": {
+ "type": "ColoredConsole",
+ "layout": "${longdate} | ${uppercase:${level}} | ${logger:shortName=true} | ${message}"
+ }
+ },
+ "rules": [
+ {
+ "logger": "*",
+ "minLevel": "Trace",
+ "writeTo": "logconsole"
+ },
+ {
+ "logger": "*",
+ "minLevel": "Info",
+ "writeTo": "logfile"
+ }
+ ]
+ },
+ "CodApp": "MP.RIOC",
+ "RouteMan": {
+ "MetricCalcIntervalSeconds": 20,
+ "MetricFlushIntervalSeconds": 60,
+ "DefaultWeightOld": 100,
+ "DefaultWeightNew": 0,
+ "DeleteExpiredMetrics": true
+ },
+ "ServerConf": {
+ "RoutePath": "/api/IOB",
+ "HttpVersion": "1.1",
+ "HttpVersionPolicy": "RequestVersionExact",
+ "OldApiUrl": "http://iis01.egalware.com/MP/IO/IOB/",
+ "NewApiUrl": "http://iis01.egalware.com/MP/IOC/api/IOB/",
+ "BaseUrlIoc": "/MP/RIOC/",
+ "MpIoNS": "MoonPro:SQL2016DEV:MoonPro",
+ "RedisBaseKey": "MP-IOC",
+ "RedisWeight": true,
+ "SafePages": "Index",
+ "redisLongTimeCache": 60,
+ "redisShortTimeCache": 30,
+ "useFactory": true
+ },
+ "RedisScripts": {
+ "Scripts": {
+ "Update": "RedisScript/RedisUpdateScript_v6.lua"
+ }
+ },
+ "ConnectionStrings": {
+ "MP.Data": "Server=SQL2016DEV;Database=MoonPro; User ID=sa;Password=keyhammer16; integrated security=False; App=MP.IOC;",
+ "MP.Utils": "Server=SQL2016DEV;Database=MoonPro_Utils; User ID=sa;Password=keyhammer16; integrated security=False; App=MP.RIOC;",
+ "Redis": "redis.ufficio:26379,serviceName=devel,DefaultDatabase=5,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,abortConnect=false,ssl=false",
+ "RedisAdmin": "redis.ufficio:26379,serviceName=devel,DefaultDatabase=5,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,abortConnect=false,ssl=false,allowAdmin=true"
+ }
+}
diff --git a/MP-RIOC/compilerconfig.json b/MP-RIOC/compilerconfig.json
new file mode 100644
index 00000000..445819db
--- /dev/null
+++ b/MP-RIOC/compilerconfig.json
@@ -0,0 +1,6 @@
+[
+ {
+ "outputFile": "Components/Layout/MainLayout.razor.css",
+ "inputFile": "Components/Layout/MainLayout.razor.less"
+ }
+]
\ No newline at end of file
diff --git a/MP-RIOC/compilerconfig.json.defaults b/MP-RIOC/compilerconfig.json.defaults
new file mode 100644
index 00000000..a5a10c08
--- /dev/null
+++ b/MP-RIOC/compilerconfig.json.defaults
@@ -0,0 +1,59 @@
+{
+ "compilers": {
+ "less": {
+ "autoPrefix": "",
+ "cssComb": "none",
+ "ieCompat": true,
+ "math": null,
+ "strictMath": false,
+ "strictUnits": false,
+ "relativeUrls": true,
+ "rootPath": "",
+ "sourceMapRoot": "",
+ "sourceMapBasePath": "",
+ "sourceMap": false
+ },
+ "sass": {
+ "autoPrefix": "",
+ "loadPaths": "",
+ "style": "expanded",
+ "relativeUrls": true,
+ "sourceMap": false
+ },
+ "stylus": {
+ "sourceMap": false
+ },
+ "babel": {
+ "sourceMap": false
+ },
+ "coffeescript": {
+ "bare": false,
+ "runtimeMode": "node",
+ "sourceMap": false
+ },
+ "handlebars": {
+ "root": "",
+ "noBOM": false,
+ "name": "",
+ "namespace": "",
+ "knownHelpersOnly": false,
+ "forcePartial": false,
+ "knownHelpers": [],
+ "commonjs": "",
+ "amd": false,
+ "sourceMap": false
+ }
+ },
+ "minifiers": {
+ "css": {
+ "enabled": true,
+ "termSemicolons": true,
+ "gzip": false
+ },
+ "javascript": {
+ "enabled": true,
+ "termSemicolons": true,
+ "gzip": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/MP-RIOC/dotnet-tools.json b/MP-RIOC/dotnet-tools.json
new file mode 100644
index 00000000..ce0aab73
--- /dev/null
+++ b/MP-RIOC/dotnet-tools.json
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "dotnet-ef": {
+ "version": "10.0.7",
+ "commands": [
+ "dotnet-ef"
+ ],
+ "rollForward": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/MP-RIOC/logs/.placeholder.file b/MP-RIOC/logs/.placeholder.file
new file mode 100644
index 00000000..e69de29b
diff --git a/MP-RIOC/post-build.ps1 b/MP-RIOC/post-build.ps1
new file mode 100644
index 00000000..446eede8
--- /dev/null
+++ b/MP-RIOC/post-build.ps1
@@ -0,0 +1,32 @@
+param([string]$ProjectDir, [string]$ProjectPath);
+
+$FileMajMin = "..\MajMin.vers"
+$FileVers = "Resources\VersNum.txt"
+$FileManIn = "Resources\manifest-original.xml"
+$FileManOut = "Resources\manifest.xml"
+$FileCLogIn = "Resources\ChangeLog-original.html"
+$FileCLogOut = "Resources\ChangeLog.html"
+$MajMin = Get-Content $FileMajMin
+$currentDate = get-date -format yyMM;
+$currentTime = get-date -format dHH;
+$find = "(.|\n)*?";
+$currRelNum = $MajMin + $currentDate +"." + $currentTime
+$replace = "" + $MajMin + $currentDate +"." + $currentTime + "";
+$csproj = Get-Content $ProjectPath
+$csprojUpdated = $csproj -replace $find, $replace
+
+Set-Content -Path $ProjectPath -Value $csprojUpdated
+Set-Content -Path $FileVers -Value $currRelNum
+
+# replace x manifest
+$manData = Get-Content $FileManIn
+$manData = $manData -replace "1.0.0.0", $currRelNum
+$manData = $manData -replace "{{DIRNAME}}", "MP-IOC"
+$manData = $manData -replace "{{BRANCHNAME}}", "stable/LAST"
+$manData = $manData -replace "{{PACKNAME}}", "MP.IOC"
+Set-Content -Path $FileManOut -Value $manData
+
+# replace x ChangeLog
+$clogData = Get-Content $FileCLogIn
+$clogData = $clogData -replace "{{CURRENT-REL}}", $currRelNum
+Set-Content -Path $FileCLogOut -Value $clogData
diff --git a/MP.AppAuth/AppAuthContext.cs b/MP.AppAuth/AppAuthContext.cs
index 35fedc43..7a770a8f 100644
--- a/MP.AppAuth/AppAuthContext.cs
+++ b/MP.AppAuth/AppAuthContext.cs
@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Options;
using MP.AppAuth.Models;
using NLog;
using System;
@@ -23,9 +24,23 @@ namespace MP.AppAuth
{
}
+ private DbContextOptions _options;
public AppAuthContext(IConfiguration configuration)
{
_configuration = configuration;
+ string connStr = _configuration.GetConnectionString("MP.Land.Auth");
+ if (string.IsNullOrEmpty(connStr))
+ {
+ connStr = _configuration.GetConnectionString("MP.Land");
+ }
+ if (string.IsNullOrEmpty(connStr))
+ {
+ connStr = _configuration.GetConnectionString("MP.Data");
+ }
+ _options = new DbContextOptionsBuilder()
+ .UseSqlServer(connStr)
+ .Options;
+
try
{
// se non ci fosse... crea o migra!
@@ -39,6 +54,7 @@ namespace MP.AppAuth
public AppAuthContext(DbContextOptions options) : base(options)
{
+ _options = options;
try
{
// se non ci fosse... crea o migra!
diff --git a/MP.AppAuth/Controllers/AppAuthController.cs b/MP.AppAuth/Controllers/AppAuthController.cs
index 24757db7..bd6047d5 100644
--- a/MP.AppAuth/Controllers/AppAuthController.cs
+++ b/MP.AppAuth/Controllers/AppAuthController.cs
@@ -1,4 +1,5 @@
-using Microsoft.Extensions.Configuration;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
using MP.AppAuth.Models;
using NLog;
using System;
@@ -9,14 +10,14 @@ using System.Threading.Tasks;
namespace MP.AppAuth.Controllers
{
- public class AppAuthController : IDisposable
+ public class AppAuthController
{
#region Public Constructors
public AppAuthController(IConfiguration configuration)
{
_configuration = configuration;
- dbCtx = new AppAuthContext(configuration);
+
Log.Info("Avviata classe AppAuthController");
}
@@ -116,11 +117,6 @@ namespace MP.AppAuth.Controllers
return dbResult;
}
- public void Dispose()
- {
- // Clear database context
- dbCtx.Dispose();
- }
///
/// Elenco completo permessi2funzione
@@ -193,33 +189,7 @@ namespace MP.AppAuth.Controllers
return dbResult;
}
- public void ResetController()
- {
- dbCtx = new AppAuthContext(_configuration);
- Log.Info("Effettuato reset AppAuthController");
- }
-
- ///
- /// Annulla modifiche su una specifica entity (cancel update)
- ///
- ///
- ///
- public bool RollBackEntity(object item)
- {
- bool answ = false;
- try
- {
- if (dbCtx.Entry(item).State == Microsoft.EntityFrameworkCore.EntityState.Deleted || dbCtx.Entry(item).State == Microsoft.EntityFrameworkCore.EntityState.Modified)
- {
- dbCtx.Entry(item).Reload();
- }
- }
- catch (Exception exc)
- {
- Log.Error($"Eccezione in rollBackEntity{Environment.NewLine}{exc}");
- }
- return answ;
- }
+
///
/// Elenco Record x gestione Update
@@ -259,7 +229,6 @@ namespace MP.AppAuth.Controllers
#region Private Fields
private static IConfiguration _configuration;
- private static AppAuthContext dbCtx;
private static Logger Log = LogManager.GetCurrentClassLogger();
#endregion Private Fields
diff --git a/MP.AppAuth/Services/AppAuthService.cs b/MP.AppAuth/Services/AppAuthService.cs
index cef52a0a..7ab866af 100644
--- a/MP.AppAuth/Services/AppAuthService.cs
+++ b/MP.AppAuth/Services/AppAuthService.cs
@@ -96,7 +96,7 @@ namespace MP.AppAuth.Services
};
// conf DB
- string connStr = _configuration.GetConnectionString("MP.Land");
+ string connStr = _configuration.GetConnectionString("MP.Land.Auth");
if (string.IsNullOrEmpty(connStr))
{
_logger.LogError("ConnString empty!");
@@ -431,10 +431,6 @@ namespace MP.AppAuth.Services
public void Dispose()
{
// Clear database controller
- if (dbController != null)
- {
- dbController.Dispose();
- }
if (MpDbController != null)
{
MpDbController.Dispose();
diff --git a/MP.Data/Controllers/MpLandController.cs b/MP.Data/Controllers/MpLandController.cs
index 956c460c..9a77ad18 100644
--- a/MP.Data/Controllers/MpLandController.cs
+++ b/MP.Data/Controllers/MpLandController.cs
@@ -19,7 +19,11 @@ namespace MP.Data.Controllers
public MpLandController(IConfiguration configuration)
{
_configuration = configuration;
- string connStr = _configuration.GetConnectionString("MP.Data");
+ string connStr = _configuration.GetConnectionString("MP.Land");
+ if(string.IsNullOrEmpty(connStr))
+ {
+ connStr = _configuration.GetConnectionString("MP.Data");
+ }
options = new DbContextOptionsBuilder()
.UseSqlServer(connStr)
.Options;
diff --git a/MP.Data/DataServiceCollectionExtensions.cs b/MP.Data/DataServiceCollectionExtensions.cs
index 78eb73e2..2ff337b3 100644
--- a/MP.Data/DataServiceCollectionExtensions.cs
+++ b/MP.Data/DataServiceCollectionExtensions.cs
@@ -14,15 +14,6 @@ namespace MP.Data
{
public static IServiceCollection AddIocDataLayer(this IServiceCollection services)
{
- //// DbContextFactory: preferibile in Blazor Server e scenari concorrenti
- //services.AddDbContextFactory(options =>
- // options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)));
-
- //// servizi preliminari
- ////services.TryAddSingleton(redisConn);
- //services.TryAddSingleton();
- //services.TryAddSingleton();
-
// Repository Singleton
services.TryAddSingleton();
@@ -40,14 +31,6 @@ namespace MP.Data
services.TryAddScoped();
services.TryAddScoped();
- //// aggiunta servizi finali Singleton...
- //services.TryAddSingleton();
- //services.TryAddSingleton();
- //services.TryAddSingleton();
- //services.TryAddSingleton();
- //services.TryAddSingleton();
-
-
return services;
}
}
diff --git a/MP.IOC/MP.IOC.csproj b/MP.IOC/MP.IOC.csproj
index d1c88af3..0a714ad2 100644
--- a/MP.IOC/MP.IOC.csproj
+++ b/MP.IOC/MP.IOC.csproj
@@ -4,7 +4,7 @@
net8.0
enable
enable
- 8.16.2605.611
+ 8.16.2605.811
@@ -33,8 +33,8 @@
+
-
@@ -48,12 +48,6 @@
Always
-
- Always
-
-
- Always
-
diff --git a/MP.IOC/Program.cs b/MP.IOC/Program.cs
index c0ccbfda..59a5e764 100644
--- a/MP.IOC/Program.cs
+++ b/MP.IOC/Program.cs
@@ -1,4 +1,3 @@
-using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.OpenApi.Models;
@@ -10,7 +9,6 @@ using MP.IOC.Services;
using NLog;
using NLog.Web;
using StackExchange.Redis;
-using System.Net;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
@@ -29,36 +27,11 @@ logger.Info($"Current ASPNETCORE_ENVIRONMENT: {env.EnvironmentName}");
ConfigurationManager configuration = builder.Configuration;
// REDIS setup
logger.Info("Config OK");
-string confRedis = configuration.GetConnectionString("Redis");
+string confRedis = configuration.GetConnectionString("Redis") ?? "localhost:6379";
string redisSrvAddr = confRedis.Substring(0, confRedis.IndexOf(":"));
logger.Info("Setup REDIS OK");
-// YARP base config
-builder.Services.AddReverseProxy().LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
-builder.Services.AddHttpForwarder();
-
-// HttpMessageInvoker (SocketsHttpHandler)
-builder.Services.AddSingleton(sp =>
-{
- var handler = new SocketsHttpHandler
- {
- AllowAutoRedirect = false,
- UseCookies = false,
- PooledConnectionLifetime = TimeSpan.FromMinutes(5),
- AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
- };
-
- // Accetta certificati non validi (dev only)
- handler.SslOptions = new System.Net.Security.SslClientAuthenticationOptions
- {
- RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true
- };
-
- return new HttpMessageInvoker(handler);
-});
-logger.Info("YARP reverse proxy configured");
-
builder.Services.Configure(
builder.Configuration.GetSection("RedisScripts"));
logger.Info("RedisScript Provider configured");
@@ -82,13 +55,6 @@ builder.Services.AddDbContextFactory(options =>
// MP.Data Services Utils - Statistiche DB
builder.Services.AddIocDataLayer();
-// base services
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddHostedService();
-builder.Services.AddHostedService();
-builder.Services.AddSingleton();
-
// Registra i servizi per Blazor
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
@@ -96,8 +62,6 @@ builder.Services.AddRazorComponents()
//builder.Services.AddHealthChecks()
// .AddSqlServer(builder.Configuration.GetConnectionString("CoreDb"));
-
-
// generic controller
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
@@ -136,59 +100,14 @@ else
}
logger.Info($"Weight service configured | use Redis: {weightOnRedis}");
-// RouteManager registration (singleton)
-builder.Services.AddSingleton();
-logger.Info("Singleton Route Manager registered");
var app = builder.Build();
-// Blocco per la migrazione automatica del DB Utils...
-using (var scope = app.Services.CreateScope())
-{
- var services = scope.ServiceProvider;
- try
- {
- var context = services.GetRequiredService();
- context.Database.Migrate();
- }
- catch (Exception ex)
- {
- var migrateLogger = services.GetRequiredService>();
- migrateLogger.LogError(ex, "Si � verificato un errore durante l'aggiornamento del database.");
- }
-}
-
-
// aggiunt base URL x routing corretto
string baseUrl = configuration.GetValue("ServerConf:BaseUrlIoc") ?? "/MP/";
app.UsePathBase(baseUrl);
-string routePath = configuration.GetValue("ServerConf:RoutePath") ?? "/api/RIOB";
-string fullPath = $"{baseUrl}{routePath}".Replace("//", "/");
logger.Info($"BaseUrl: {baseUrl}");
-app.Use(async (ctx, next) =>
-{
- logger.Debug($"Incoming request PathBase='{ctx.Request.PathBase}' Path='{ctx.Request.Path}' RawTarget='{ctx.Request.GetEncodedUrl()}'");
- await next();
-});
-
-
-// parametrizzare?!?!?
-app.MapWhen(ctx =>
- ctx.Request.Path.StartsWithSegments(fullPath, StringComparison.OrdinalIgnoreCase) ||
- ctx.Request.Path.StartsWithSegments(routePath, StringComparison.OrdinalIgnoreCase) ||
- (ctx.Request.PathBase.HasValue && ctx.Request.Path.StartsWithSegments(routePath, StringComparison.OrdinalIgnoreCase)),
- builder =>
- {
- builder.Run(async ctx =>
- {
- var routeManager = ctx.RequestServices.GetRequiredService();
- await routeManager.HandleAsync(ctx);
- });
- });
-
-logger.Info("App: route Mapped");
-
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment() || app.Environment.IsStaging())
diff --git a/MP.IOC/Properties/PublishProfiles/IIS01.pubxml b/MP.IOC/Properties/PublishProfiles/IIS01.pubxml
index d7ddcd79..823f36eb 100644
--- a/MP.IOC/Properties/PublishProfiles/IIS01.pubxml
+++ b/MP.IOC/Properties/PublishProfiles/IIS01.pubxml
@@ -25,4 +25,10 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
net8.0
win-x64
+
+
+ filePath
+ logs\\.*\.log$
+
+
\ No newline at end of file
diff --git a/MP.IOC/Properties/PublishProfiles/IIS01.pubxml.user b/MP.IOC/Properties/PublishProfiles/IIS01.pubxml.user
index 40aee328..15901b1b 100644
--- a/MP.IOC/Properties/PublishProfiles/IIS01.pubxml.user
+++ b/MP.IOC/Properties/PublishProfiles/IIS01.pubxml.user
@@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAdCoESbxryUqXde3FfEOCTwAAAAACAAAAAAADZgAAwAAAABAAAAAFrH1vByj45Qn06hO/OH6tAAAAAASAAACgAAAAEAAAAIUK5NiEpc4lc11Op6/CLx8YAAAAMecN12fzIN9e3E8R/nu0ATe2PAsMy7M8FAAAAKbUyki2vkSFehjbpB8wCVVVa055
- True|2026-04-17T17:09:49.4900600Z||;True|2026-04-03T12:55:15.0251473+02:00||;True|2026-04-03T10:03:02.5833820+02:00||;True|2026-04-03T09:55:55.5274684+02:00||;True|2026-04-03T09:52:44.9063312+02:00||;False|2026-04-03T09:45:49.5943015+02:00||;True|2024-11-04T08:56:17.3071781+01:00||;True|2023-02-14T17:41:26.3850692+01:00||;True|2023-02-14T17:31:39.4933399+01:00||;
+ True|2026-05-08T09:26:08.1731328Z||;False|2026-05-08T11:06:51.2202890+02:00||;True|2026-05-08T10:37:55.0049896+02:00||;False|2026-05-08T10:37:05.1546068+02:00||;False|2026-05-08T10:36:33.0311629+02:00||;False|2026-05-08T10:35:55.7742437+02:00||;True|2026-04-17T19:09:49.4900600+02:00||;True|2026-04-03T12:55:15.0251473+02:00||;True|2026-04-03T10:03:02.5833820+02:00||;True|2026-04-03T09:55:55.5274684+02:00||;True|2026-04-03T09:52:44.9063312+02:00||;False|2026-04-03T09:45:49.5943015+02:00||;True|2024-11-04T08:56:17.3071781+01:00||;True|2023-02-14T17:41:26.3850692+01:00||;True|2023-02-14T17:31:39.4933399+01:00||;
\ No newline at end of file
diff --git a/MP.IOC/Resources/ChangeLog-original.html b/MP.IOC/Resources/ChangeLog-original.html
index fa79ade6..cf07d7e9 100644
--- a/MP.IOC/Resources/ChangeLog-original.html
+++ b/MP.IOC/Resources/ChangeLog-original.html
@@ -25,7 +25,7 @@
Modulo MP-IOC
- Versione: 8.16.2605.611
+ Versione: 8.16.2605.811
Note di rilascio:
-
@@ -25,7 +25,7 @@