Merge branch 'Release/AddRIoc_01'

This commit is contained in:
Samuele Locatelli
2026-05-08 12:01:24 +02:00
62 changed files with 1258 additions and 279 deletions
+98 -3
View File
@@ -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
+5 -4
View File
@@ -7,8 +7,8 @@
<PackageVersion Include="Blazored.LocalStorage" Version="4.5.0" />
<PackageVersion Include="Blazored.SessionStorage" Version="2.4.0" />
<PackageVersion Include="DiffMatchPatch" Version="1.0.3" />
<PackageVersion Include="EgwCoreLib.Razor" Version="1.5.2605.412" />
<PackageVersion Include="EgwCoreLib.Utils" Version="1.5.2605.412" />
<PackageVersion Include="EgwCoreLib.Razor" Version="1.5.2605.511" />
<PackageVersion Include="EgwCoreLib.Utils" Version="1.5.2605.511" />
<PackageVersion Include="MailKit" Version="4.16.0" />
<PackageVersion Include="Majorsoft.Blazor.Components.Debounce" Version="1.5.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.Negotiate" Version="8.0.25" />
@@ -28,15 +28,16 @@
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.17" />
<PackageVersion Include="MongoDB.Driver" Version="2.19.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="NLog" Version="6.1.2" />
<PackageVersion Include="NLog" Version="6.1.3" />
<PackageVersion Include="NLog.Targets.OpenTelemetryProtocol" Version="1.2.6" />
<PackageVersion Include="NLog.Web.AspNetCore" Version="6.1.2" />
<PackageVersion Include="NLog.Web.AspNetCore" Version="6.1.3" />
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
<PackageVersion Include="OpenTelemetry.Instrumentation.SqlClient" Version="1.15.2" />
<PackageVersion Include="OpenTelemetry.Instrumentation.StackExchangeRedis" Version="1.15.0-beta.1" />
<PackageVersion Include="Snappier" Version="1.3.1" />
<PackageVersion Include="System.Text.Encodings.Web" Version="8.0.0" />
<PackageVersion Include="RestSharp" Version="112.0.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
+6
View File
@@ -0,0 +1,6 @@
@MP_RIOC_HostAddress = http://localhost:5290
GET {{MP_RIOC_HostAddress}}/weatherforecast/
Accept: application/json
###
+5
View File
@@ -0,0 +1,5 @@
<Solution>
<Project Path="../MP.Core/MP.Core.csproj" />
<Project Path="../MP.Data/MP.Data.csproj" />
<Project Path="MP.RIOC.csproj" />
</Solution>
+46
View File
@@ -0,0 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>MP.RIOC</RootNamespace>
<Version>8.16.2605.812</Version>
</PropertyGroup>
<ItemGroup>
<Content Remove="compilerconfig.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NLog" />
<PackageReference Include="NLog.Web.AspNetCore" />
<PackageReference Include="Swashbuckle.AspNetCore" />
<PackageReference Include="Yarp.ReverseProxy" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MP.Core\MP.Core.csproj" />
<ProjectReference Include="..\MP.Data\MP.Data.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="compilerconfig.json" />
</ItemGroup>
<ItemGroup>
<None Update="logs\.placeholder.file">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="RedisScript\RedisUpdateScript_v5.lua">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="RedisScript\RedisUpdateScript_v6.lua">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="powershell.exe -ExecutionPolicy Unrestricted -NoProfile -NonInteractive -File $(ProjectDir)\post-build.ps1 -ProjectDir $(ProjectDir) -ProjectPath $(ProjectPath)" />
</Target>
</Project>
+97
View File
@@ -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);
}
<!DOCTYPE html>
<html>
<head>
<title>MP.RIOC Dashboard</title>
<style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f0f2f5; padding: 30px; color: #333; }
.card { background: white; padding: 25px; border-radius: 12px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); max-width: 900px; margin: auto; }
h1 { color: #0056b3; margin-top: 0; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th, td { text-align: left; padding: 12px; border-bottom: 1px solid #eee; }
th { background-color: #f8f9fa; color: #666; text-transform: uppercase; font-size: 0.85em; }
.tag { padding: 4px 8px; border-radius: 4px; font-size: 0.8em; font-weight: bold; }
.tag-ioc { background: #e3f2fd; color: #0d47a1; }
.tag-io { background: #fff3e0; color: #e65100; }
.latency { font-family: monospace; font-weight: bold; }
.d-flex { display: flex !important; }
.justify-content-between { justify-content: space-between !important; }
.align-items-center { align-items: center !important; }
.flex-column { flex-direction: column !important; }
.text-end { text-align: right !important; }
.px-0 { padding-left: 0 !important; padding-right: 0 !important; }
/* Miglioramento per l'intestazione custom */
.header-container {
border-bottom: 2px solid #0056b3;
margin-bottom: 20px;
padding-bottom: 10px;
}
h1 { margin: 0; font-size: 2.5em; color: #0056b3; line-height: 1; }
h2 { margin: 0; font-size: 1.8em; color: #333; line-height: 1; }
h3 { margin: 5px 0 0 0; font-size: 1em; color: #666; font-weight: normal; }
</style>
</head>
<body>
<div class="card">
<div class="d-flex justify-content-between align-items-center header-container">
<div class="px-0">
<h1>MAPO MES</h1>
<div>Live Dashboard</div>
</div>
<div class="px-0 text-end">
<h2>MP-RIOC</h2>
<h3>Router I/O Controller</h3>
</div>
</div>
<div class="d-flex justify-content-between align-items-center">
<div class="px-0">
Stato: <span style="color:green">● Online</span>
</div>
<div class="px-0 text-end">
Versione: @System.Reflection.Assembly.GetExecutingAssembly().GetName().Version
</div>
</div>
<table>
<thead>
<tr>
<th>Target | Metodo | ID</th>
<th class="text-end">Chiamate</th>
<th class="text-end">Latenza Media</th>
</tr>
</thead>
<tbody>
@foreach (var stat in metrics)
{
<tr>
<td>
@if(stat.Key.StartsWith("IOC")) { <span class="tag tag-ioc">NEW</span> }
else { <span class="tag tag-io">OLD</span> }
@stat.Key
</td>
<td class="text-end">@stat.Value.Count</td>
<td class="latency text-end">@(stat.Value.AvgDuration)ms</td>
</tr>
}
@if (!metrics.Any())
{
<tr>
<td colspan="3" style="text-align:center; padding: 40px; color: #999;">Nessun dato raccolto al momento.</td>
</tr>
}
</tbody>
</table>
<div class="text-end" style="margin-top: 20px; font-size: 0.8em; color: #999;">
Ultimo aggiornamento: @DateTime.Now.ToString("HH:mm:ss")
</p>
</div>
</body>
</html>
+12
View File
@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace MP.RIOC.Pages
{
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
}
+178
View File
@@ -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<RedisScriptsConfig>(
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<MoonProContext>(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<MoonPro_UtilsContext>(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<IConnectionMultiplexer>(redisMux);
// Registrazione dei servizi custom
builder.Services.AddSingleton<PreserveBodyTransformer>();
builder.Services.AddSingleton<RouteStatsManager>();
builder.Services.AddHostedService<MetricsCalcService>();
builder.Services.AddHostedService<MetricsDbFlushService>();
builder.Services.AddSingleton<LuaScriptProvider>();
logger.Info("Standard service configured");
// WeightProvider: Redis/Memory da config
var weightOnRedis = builder.Configuration.GetValue<bool>("ServerConf:RedisWeight", false);
if (weightOnRedis)
{
builder.Services.AddSingleton<IWeightProvider, RedisWeightProvider>();
}
else
{
builder.Services.AddSingleton<IWeightProvider, InMemoryWeightProvider>();
}
logger.Info($"Weight service configured | use Redis: {weightOnRedis}");
// RouteManager registration (singleton)
builder.Services.AddSingleton<RouteManager>();
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<MoonPro_UtilsContext>();
context.Database.Migrate();
}
catch (Exception ex)
{
var migrateLogger = services.GetRequiredService<ILogger<Program>>();
migrateLogger.LogError(ex, "Si verificato un errore durante l'aggiornamento del database.");
}
}
// 1. Configurazione Base Path
string baseUrl = configuration.GetValue<string>("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<string>("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<RouteManager>();
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();
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<WebPublishMethod>MSDeploy</WebPublishMethod>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish>https://iis01.egalware.com/MP/RIOC/</SiteUrlToLaunchAfterPublish>
<ExcludeApp_Data>false</ExcludeApp_Data>
<ProjectGuid>b9188473-f4ae-4f9f-be2d-70edaace0db9</ProjectGuid>
<SelfContained>false</SelfContained>
<MSDeployServiceURL>https://iis01.egalware.com:8172/MsDeploy.axd</MSDeployServiceURL>
<DeployIisAppPath>Default Web Site/MP/RIOC</DeployIisAppPath>
<RemoteSitePhysicalPath />
<SkipExtraFilesOnServer>false</SkipExtraFilesOnServer>
<MSDeployPublishMethod>WMSVC</MSDeployPublishMethod>
<EnableMSDeployBackup>true</EnableMSDeployBackup>
<EnableMsDeployAppOffline>true</EnableMsDeployAppOffline>
<UserName>jenkins</UserName>
<_SavePWD>true</_SavePWD>
<_TargetId>IISWebDeploy</_TargetId>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<MsDeploySkipRules Include="SkipLogFiles">
<ObjectName>filePath</ObjectName>
<AbsolutePath>logs\\.*\.log$</AbsolutePath>
</MsDeploySkipRules>
</ItemGroup>
</Project>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<History>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||;</History>
<LastFailureDetails />
<TimeStampOfAssociatedLegacyPublishXmlFile />
<EncryptedPassword>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAlmCNMQ0J1UqPM+RugOqtLgAAAAACAAAAAAAQZgAAAAEAACAAAABmDmKQdTOJuzYQ2FFyU+1htQ8H/TQ+IM9D7RchZs6pvgAAAAAOgAAAAAIAACAAAABeb+XK2KUWpsQ2fiYxFKeezXYyZloQPjo9Qkmjbf+FlyAAAAAR+ckV3KTLXMIMyW4f5PBdp6Uxv5tWJ5LldbO4N+tXYUAAAACJwytTC9fJKy3wyHTlSVYRd/OdBUQ8pCweu3wSK3CGvcpgwT+VFYooELXfzgEV8l6P6FrAdGoF0gt9O3yyn1X4</EncryptedPassword>
</PropertyGroup>
</Project>
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<WebPublishMethod>MSDeploy</WebPublishMethod>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish>https://iis03.egalware.com/MP/RIOC/</SiteUrlToLaunchAfterPublish>
<ExcludeApp_Data>false</ExcludeApp_Data>
<ProjectGuid>b9188473-f4ae-4f9f-be2d-70edaace0db9</ProjectGuid>
<SelfContained>false</SelfContained>
<MSDeployServiceURL>https://iis03.egalware.com:8172/MsDeploy.axd</MSDeployServiceURL>
<DeployIisAppPath>Default Web Site/MP/RIOC</DeployIisAppPath>
<RemoteSitePhysicalPath />
<SkipExtraFilesOnServer>false</SkipExtraFilesOnServer>
<MSDeployPublishMethod>WMSVC</MSDeployPublishMethod>
<EnableMSDeployBackup>true</EnableMSDeployBackup>
<EnableMsDeployAppOffline>true</EnableMsDeployAppOffline>
<UserName>jenkins</UserName>
<_SavePWD>true</_SavePWD>
<_TargetId>IISWebDeploy</_TargetId>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
</Project>
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<WebPublishMethod>MSDeploy</WebPublishMethod>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish>https://iis04.egalware.com/MP/RIOC/</SiteUrlToLaunchAfterPublish>
<ExcludeApp_Data>false</ExcludeApp_Data>
<ProjectGuid>b9188473-f4ae-4f9f-be2d-70edaace0db9</ProjectGuid>
<SelfContained>false</SelfContained>
<MSDeployServiceURL>https://iis04.egalware.com:8172/MsDeploy.axd</MSDeployServiceURL>
<DeployIisAppPath>Default Web Site/MP/RIOC</DeployIisAppPath>
<RemoteSitePhysicalPath />
<SkipExtraFilesOnServer>false</SkipExtraFilesOnServer>
<MSDeployPublishMethod>WMSVC</MSDeployPublishMethod>
<EnableMSDeployBackup>true</EnableMSDeployBackup>
<EnableMsDeployAppOffline>true</EnableMsDeployAppOffline>
<UserName>jenkins</UserName>
<_SavePWD>true</_SavePWD>
<_TargetId>IISWebDeploy</_TargetId>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
</Project>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<WebPublishMethod>Package</WebPublishMethod>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<ExcludeApp_Data>false</ExcludeApp_Data>
<ProjectGuid>f3794272-87ad-7c42-2528-6b119dbbc4d5</ProjectGuid>
<DesktopBuildPackageLocation>bin\publish\MP.RIOC.zip</DesktopBuildPackageLocation>
<PackageAsSingleFile>true</PackageAsSingleFile>
<DeployIisAppPath>Default Web Site/MP/RIOC</DeployIisAppPath>
<_TargetId>IISWebDeployPackage</_TargetId>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<TimeStampOfAssociatedLegacyPublishXmlFile />
</PropertyGroup>
</Project>
+41
View File
@@ -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"
}
}
}
}
+31
View File
@@ -0,0 +1,31 @@
<body>
<i>Modulo MP-RIOC </i>
<h4>Versione: {{CURRENT-REL}}</h4>
<br /> Note di rilascio:
<ul>
<li>
<b>Ultime modifiche:</b>
<ul>{{LAST-CHANGES}}</ul>
</li>
<li>
<b>v.8.16.* &rarr;</b>
<ul>
<li>Ottimizzazioni varie x Redis</li>
</ul>
</li>
<li>
<b>v.8.16.* &rarr;</b>
<ul>
<li>Prima release dotNet 8.0 router</li>
</ul>
</li>
</ul>
<div>
<div style="float: left;">
<img src="logoSteamware.png" />
</div>
<div style="float: right;">
<a href="https://www.steamware.net/IOT" target="_blank">&copy; Steamware 2006-2026</a>
</div>
</div>
</body>
+31
View File
@@ -0,0 +1,31 @@
<body>
<i>Modulo MP-RIOC </i>
<h4>Versione: 8.16.2605.812</h4>
<br /> Note di rilascio:
<ul>
<li>
<b>Ultime modifiche:</b>
<ul>{{LAST-CHANGES}}</ul>
</li>
<li>
<b>v.8.16.* &rarr;</b>
<ul>
<li>Ottimizzazioni varie x Redis</li>
</ul>
</li>
<li>
<b>v.8.16.* &rarr;</b>
<ul>
<li>Prima release dotNet 8.0 router</li>
</ul>
</li>
</ul>
<div>
<div style="float: left;">
<img src="logoSteamware.png" />
</div>
<div style="float: right;">
<a href="https://www.steamware.net/IOT" target="_blank">&copy; Steamware 2006-2026</a>
</div>
</div>
</body>
+1
View File
@@ -0,0 +1 @@
8.16.2605.812
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>1.0.0.0</version>
<url>https://nexus.steamware.net/repository/SWS/{{DIRNAME}}/{{BRANCHNAME}}/{{PACKNAME}}.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/{{DIRNAME}}/{{BRANCHNAME}}/ChangeLog.html</changelog>
<mandatory>false</mandatory>
</item>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>8.16.2605.812</version>
<url>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/MP.IOC.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
</item>
+29
View File
@@ -0,0 +1,29 @@
using MP.Core.DTO;
namespace MP.RIOC.Services
{
public interface IWeightProvider
{
#region Public Methods
/// <summary>
/// Ritorna l'intero elenco dei weight attivi nel formato WeightDTO
/// </summary>
/// <returns></returns>
Task<List<WeightDTO>> GetAllWeightsAsync();
/// <summary>
/// Ritorna la coppia (oldWeight, newWeight) per scegliere dove instradare il metodo tra i 2 sistemi API.
/// </summary>
(int oldWeight, int newWeight) GetWeightsFor(string method);
/// <summary>
/// Aggiorna/Aggiuinge il valore del weight richiesto
/// </summary>
/// <param name=""></param>
/// <returns></returns>
bool UpsertWeight(WeightDTO updRecord);
#endregion Public Methods
}
}
@@ -0,0 +1,56 @@
using MP.Core.DTO;
using System.Collections.Concurrent;
namespace MP.RIOC.Services
{
public class InMemoryWeightProvider : IWeightProvider
{
private readonly ConcurrentDictionary<string, (int oldW, int newW)> _map = new();
private readonly int _defaultOld;
private readonly int _defaultNew;
public InMemoryWeightProvider(IConfiguration config)
{
_defaultOld = config.GetValue<int>("RouteMan:DefaultWeightOld", 100);
_defaultNew = config.GetValue<int>("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<List<WeightDTO>> GetAllWeightsAsync()
{
var result = new List<WeightDTO>();
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;
}
}
}
@@ -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;
}
}
}
@@ -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<int>("RouteMan:MetricCalcIntervalSeconds", 20);
var interval = _config.GetValue<int>("RouteMan:MetricCalcIntervalSeconds", 30);
while (!stoppingToken.IsCancellationRequested)
{
@@ -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<int>("RouteMan:MetricFlushIntervalSeconds", 120);
var interval = _config.GetValue<int>("RouteMan:MetricFlushIntervalSeconds", 300);
var interval = _config.GetValue<int>("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
}
}
}
@@ -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);
}
}
}
+157
View File
@@ -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<int>("RouteMan:DefaultWeightOld", 100);
_defaultNew = config.GetValue<int>("RouteMan:DefaultWeightNew", 0);
_redisBaseKey = config.GetValue<string>("ServerConf:RedisBaseKey") ?? "MP_IOC";
_keyPrefix = $"{_redisBaseKey}:route_weight:";
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Ritorna (oldWeight, newWeight) per il metodo. Se non esiste, crea la chiave con i default.
/// </summary>
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<List<WeightDTO>> GetAllWeightsAsync()
{
var result = new List<WeightDTO>();
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
}
}
@@ -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<string>("ServerConf:RoutePath") ?? "/api/RIOB";
_routePath = _config.GetValue<string>("ServerConf:RoutePath") ?? "/api/IOB";
_forwarderConfig = new ForwarderRequestConfig
{
ActivityTimeout = TimeSpan.FromSeconds(30),
// Parse della versione (es. "1.1")
Version = Version.Parse(_config.GetValue<string>("ServerConf:HttpVersion") ?? "1.1"),
// Policy per la versione
VersionPolicy = _config.GetValue<HttpVersionPolicy?>("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;
}
}
}
@@ -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<int, long> StatusCodes = new();
public TimeSpan AvgDuration => TotalDuration / (Count > 0 ? Count : 1);
}
public class RouteStatsManager
+13
View File
@@ -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/"
}
}
+26
View File
@@ -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"
}
}
}
+86
View File
@@ -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"
}
}
+6
View File
@@ -0,0 +1,6 @@
[
{
"outputFile": "Components/Layout/MainLayout.razor.css",
"inputFile": "Components/Layout/MainLayout.razor.less"
}
]
+59
View File
@@ -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
}
}
}
+13
View File
@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "10.0.7",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
}
}
View File
+32
View File
@@ -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 = "<Version>(.|\n)*?</Version>";
$currRelNum = $MajMin + $currentDate +"." + $currentTime
$replace = "<Version>" + $MajMin + $currentDate +"." + $currentTime + "</Version>";
$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
+16
View File
@@ -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<AppAuthContext> _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<AppAuthContext>()
.UseSqlServer(connStr)
.Options;
try
{
// se non ci fosse... crea o migra!
@@ -39,6 +54,7 @@ namespace MP.AppAuth
public AppAuthContext(DbContextOptions<AppAuthContext> options) : base(options)
{
_options = options;
try
{
// se non ci fosse... crea o migra!
+5 -36
View File
@@ -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();
}
/// <summary>
/// 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");
}
/// <summary>
/// Annulla modifiche su una specifica entity (cancel update)
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 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
+1 -5
View File
@@ -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();
+5 -1
View File
@@ -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<MoonProContext>()
.UseSqlServer(connStr)
.Options;
@@ -14,15 +14,6 @@ namespace MP.Data
{
public static IServiceCollection AddIocDataLayer(this IServiceCollection services)
{
//// DbContextFactory: preferibile in Blazor Server e scenari concorrenti
//services.AddDbContextFactory<DataLayerContext>(options =>
// options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)));
//// servizi preliminari
////services.TryAddSingleton<IConnectionMultiplexer>(redisConn);
//services.TryAddSingleton<IRedisService, RedisService>();
//services.TryAddSingleton<IRedisSubscriptionManager, RedisSubscriptionManager>();
// Repository Singleton
services.TryAddSingleton<IMtcSetupRepository, MtcSetupRepository>();
@@ -40,14 +31,6 @@ namespace MP.Data
services.TryAddScoped<IStatsAggrService, StatsAggrService>();
services.TryAddScoped<IStatsDetailService, StatsDetailService>();
//// aggiunta servizi finali Singleton...
//services.TryAddSingleton<IImageCacheService, ImageCacheService>();
//services.TryAddSingleton<IConfigDataService, ConfigDataService>();
//services.TryAddSingleton<ICalcRequestService, CalcRequestService>();
//services.TryAddSingleton<IFileService, FileService>();
//services.TryAddSingleton<IProdService, ProdService>();
return services;
}
}
+2 -8
View File
@@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>8.16.2605.611</Version>
<Version>8.16.2605.811</Version>
</PropertyGroup>
<ItemGroup>
@@ -33,8 +33,8 @@
<PackageReference Include="Microsoft.AspNetCore.Components" />
<PackageReference Include="NLog" />
<PackageReference Include="NLog.Web.AspNetCore" />
<PackageReference Include="Snappier" />
<PackageReference Include="Swashbuckle.AspNetCore" />
<PackageReference Include="Yarp.ReverseProxy" />
</ItemGroup>
<ItemGroup>
@@ -48,12 +48,6 @@
<None Update="post-build.ps1">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="RedisScript\RedisUpdateScript_v5.lua">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="RedisScript\RedisUpdateScript_v6.lua">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
+1 -82
View File
@@ -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<RedisScriptsConfig>(
builder.Configuration.GetSection("RedisScripts"));
logger.Info("RedisScript Provider configured");
@@ -82,13 +55,6 @@ builder.Services.AddDbContextFactory<MoonPro_UtilsContext>(options =>
// MP.Data Services Utils - Statistiche DB
builder.Services.AddIocDataLayer();
// base services
builder.Services.AddSingleton<PreserveBodyTransformer>();
builder.Services.AddSingleton<RouteStatsManager>();
builder.Services.AddHostedService<MetricsCalcService>();
builder.Services.AddHostedService<MetricsDbFlushService>();
builder.Services.AddSingleton<LuaScriptProvider>();
// 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<RouteManager>();
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<MoonPro_UtilsContext>();
context.Database.Migrate();
}
catch (Exception ex)
{
var migrateLogger = services.GetRequiredService<ILogger<Program>>();
migrateLogger.LogError(ex, "Si verificato un errore durante l'aggiornamento del database.");
}
}
// aggiunt base URL x routing corretto
string baseUrl = configuration.GetValue<string>("ServerConf:BaseUrlIoc") ?? "/MP/";
app.UsePathBase(baseUrl);
string routePath = configuration.GetValue<string>("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<RouteManager>();
await routeManager.HandleAsync(ctx);
});
});
logger.Info("App: route Mapped");
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment() || app.Environment.IsStaging())
@@ -25,4 +25,10 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<MsDeploySkipRules Include="SkipLogFiles">
<ObjectName>filePath</ObjectName>
<AbsolutePath>logs\\.*\.log$</AbsolutePath>
</MsDeploySkipRules>
</ItemGroup>
</Project>
@@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<TimeStampOfAssociatedLegacyPublishXmlFile />
<EncryptedPassword>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAdCoESbxryUqXde3FfEOCTwAAAAACAAAAAAADZgAAwAAAABAAAAAFrH1vByj45Qn06hO/OH6tAAAAAASAAACgAAAAEAAAAIUK5NiEpc4lc11Op6/CLx8YAAAAMecN12fzIN9e3E8R/nu0ATe2PAsMy7M8FAAAAKbUyki2vkSFehjbpB8wCVVVa055</EncryptedPassword>
<History>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||;</History>
<History>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||;</History>
<LastFailureDetails />
</PropertyGroup>
</Project>
+1 -1
View File
@@ -25,7 +25,7 @@
<img src="logoSteamware.png" />
</div>
<div style="float: right;">
<a href="https://www.steamware.net/IOT" target="_blank">&copy; Steamware 2006-2023</a>
<a href="https://www.steamware.net/IOT" target="_blank">&copy; Steamware 2006-2026</a>
</div>
</div>
</body>
+2 -2
View File
@@ -1,6 +1,6 @@
<body>
<i>Modulo MP-IOC </i>
<h4>Versione: 8.16.2605.611</h4>
<h4>Versione: 8.16.2605.811</h4>
<br /> Note di rilascio:
<ul>
<li>
@@ -25,7 +25,7 @@
<img src="logoSteamware.png" />
</div>
<div style="float: right;">
<a href="https://www.steamware.net/IOT" target="_blank">&copy; Steamware 2006-2023</a>
<a href="https://www.steamware.net/IOT" target="_blank">&copy; Steamware 2006-2026</a>
</div>
</div>
</body>
+1 -1
View File
@@ -1 +1 @@
8.16.2605.611
8.16.2605.811
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>8.16.2605.611</version>
<version>8.16.2605.811</version>
<url>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/MP.IOC.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
-22
View File
@@ -5,23 +5,6 @@
"Microsoft.AspNetCore": "Warning"
}
},
"ReverseProxy": {
"Routes": [
{
"RouteId": "route-man-r-iob",
"ClusterId": "cluster-placeholder",
"Match": { "Path": "/api/RIOB/{**catch-all}" }
}
],
"Clusters": {
"cluster-old": {
"Destinations": { "old1": { "Address": "https://maposrv.egalware.com/MP/IO/IOB/" } }
},
"cluster-new": {
"Destinations": { "new1": { "Address": "https://maposrv.egalware.com/MP/IOC/api/IOB/" } }
}
}
},
"AllowedHosts": "*",
"CodApp": "MP.IOC",
"ConnectionStrings": {
@@ -34,10 +17,5 @@
},
"ServerConf": {
"useFactory": false
},
"RedisScripts": {
"Scripts": {
"Update": "RedisScript/RedisUpdateScript_v5.lua"
}
}
}
+2 -19
View File
@@ -14,8 +14,6 @@
"baseFileDir": "${basedir}/logs/",
"layout": "${longdate} | ${uppercase:${level}} | ${logger:shortName=false} | ${message}"
},
// "internalLogLevel": "Info",
// "internalLogFile": "c:\\temp\\internal-nlog.txt",
"extensions": [
{ "assembly": "NLog.Extensions.Logging" },
{ "assembly": "NLog.Web.AspNetCore" }
@@ -26,6 +24,7 @@
"logfile": {
"type": "File",
"fileName": "${basedir}/logs/${shortdate}.log",
"keepFileOpen": false,
"archiveEvery": "Day",
"archiveFileName": "${basedir}/logs/old/${shortdate}_{#}.log",
"archiveNumbering": "DateAndSequence",
@@ -54,23 +53,7 @@
},
"AllowedHosts": "*",
"CodApp": "MP.IOC",
"ReverseProxy": {
"Routes": [
{
"RouteId": "route-man-r-iob",
"ClusterId": "cluster-placeholder",
"Match": { "Path": "/api/RIOB/{**catch-all}" }
}
],
"Clusters": {
"cluster-old": {
"Destinations": { "old1": { "Address": "https://iis01.egalware.com/MP/IO/IOB/" } }
},
"cluster-new": {
"Destinations": { "new1": { "Address": "https://iis01.egalware.com/MP/IOC/api/IOB/" } }
}
}
},
"RouteMan": {
"MetricCalcIntervalSeconds": 10,
"MetricFlushIntervalSeconds": 60,
+1 -1
View File
@@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>MP.Land</RootNamespace>
<Version>8.16.2605.0411</Version>
<Version>8.16.2605.0811</Version>
<Configurations>Debug;Release;Debug_LiManDebug</Configurations>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<RunAnalyzersDuringBuild>True</RunAnalyzersDuringBuild>
-23
View File
@@ -173,18 +173,6 @@ namespace MP.Land.Pages
return answ;
}
#if false
protected Core.Objects.IOB_data CurrIobInfo(string idxMacc)
{
Core.Objects.IOB_data answ = new Core.Objects.IOB_data();
if (DictIobInfo.ContainsKey(idxMacc))
{
answ = DictIobInfo[idxMacc];
}
return answ;
}
#endif
protected void DataInit()
{
isLoading = true;
@@ -219,17 +207,6 @@ namespace MP.Land.Pages
return answ;
}
#if false
protected string IobExeTrim(string IdxMacchina)
{
string answ = MacIobConf(IdxMacchina, "IobExe");
if (!string.IsNullOrEmpty(answ) && answ.Contains(","))
{
answ = answ.Substring(0, answ.IndexOf(','));
}
return answ;
}
#endif
protected override async Task OnInitializedAsync()
{
-5
View File
@@ -143,11 +143,9 @@ namespace MP.Land.Pages
private async void OnFilterUpdated()
{
isLoading = true;
await Task.Delay(1);
await InvokeAsync(StateHasChanged);
ListRecords = null;
currPage = 1;
await Task.Delay(1);
await ReloadData();
}
@@ -158,7 +156,6 @@ namespace MP.Land.Pages
await InvokeAsync(StateHasChanged);
ListRecords = null;
currPage = 1;
await Task.Delay(1);
await ReloadData();
}
@@ -166,11 +163,9 @@ namespace MP.Land.Pages
{
isLoading = true;
// importante altrimenti NON mostra update UI
await Task.Delay(1);
SearchRecords = await DataService.AnagOperByGroupList(groupName, AppMService.SearchVal);
ListRecords = SearchRecords.Skip((currPage - 1) * numRecord).Take(numRecord).ToList();
totalCount = SearchRecords.Count();
await Task.Delay(1);
isLoading = false;
StateHasChanged();
}
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>Modulo Tablet MAPO - DotNet6</i>
<h4>Versione: 8.16.2605.0411</h4>
<h4>Versione: 8.16.2605.0811</h4>
<br />
Note di rilascio:
<ul>
+1 -1
View File
@@ -1 +1 @@
8.16.2605.0411
8.16.2605.0811
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>8.16.2605.0411</version>
<version>8.16.2605.0811</version>
<url>https://nexus.steamware.net/repository/SWS/MP-LAND/stable/LAST/MP.Land.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/MP-LAND/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
+1
View File
@@ -58,6 +58,7 @@
"ConnectionStrings": {
"DefaultConnection": "Server=SQL2016DEV;Database=MoonPro;Trusted_Connection=True;MultipleActiveResultSets=true",
"MP.All": "Server=SQL2016DEV;Database=MoonPro;User ID=sa;Password=keyhammer16;integrated security=False;MultipleActiveResultSets=True;App=MP.Land;",
"MP.Data": "Server=SQL2016DEV;Database=MoonPro;User ID=sa;Password=keyhammer16;integrated security=False;MultipleActiveResultSets=True;App=MP.Land;",
"MP.Flux": "Server=SQL2016DEV;Database=MoonPro_FluxData;User ID=sa;Password=keyhammer16;integrated security=False;MultipleActiveResultSets=True;App=MP.Land;",
"MP.Land": "Server=SQL2016DEV;Database=MoonPro;User ID=sa;Password=keyhammer16;integrated security=False;MultipleActiveResultSets=True;App=MP.Land;",
"MP.Land.Auth": "Server=SQL2016DEV;Database=MoonPro_Anagrafica;User ID=sa;Password=keyhammer16;integrated security=False;MultipleActiveResultSets=True;App=MP.Land;",