Inizio gestione routing (qualche warning ma funziona)
This commit is contained in:
@@ -20,6 +20,7 @@ string connStringRedis = configuration.GetConnectionString("Redis");
|
||||
string redisSrvAddr = connStringRedis.Substring(0, connStringRedis.IndexOf(":"));
|
||||
logger.Info("Setup REDIS OK");
|
||||
|
||||
|
||||
// YARP base config
|
||||
builder.Services.AddReverseProxy().LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
|
||||
builder.Services.AddHttpForwarder();
|
||||
@@ -34,6 +35,13 @@ builder.Services.AddSingleton(sp =>
|
||||
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");
|
||||
@@ -75,6 +83,11 @@ logger.Info("Singleton Route Manager registered");
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// aggiunt base URL x routing corretto
|
||||
string baseUrl = configuration.GetValue<string>("ServerConf:BaseUrl") ?? "";
|
||||
app.UsePathBase(baseUrl);
|
||||
logger.Info($"BaseUrl: {baseUrl}");
|
||||
|
||||
// Map route to RouteManager
|
||||
app.Map("/MP/IOC/api/RIOB/{**catchAll}", async (HttpContext ctx) =>
|
||||
{
|
||||
|
||||
@@ -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-03T08:03:02.5833820Z||;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-04-03T10:55:15.0251473Z||;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,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo MP-IOC </i>
|
||||
<h4>Versione: 6.16.2604.311</h4>
|
||||
<h4>Versione: 6.16.2604.318</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
6.16.2604.311
|
||||
6.16.2604.318
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>6.16.2604.311</version>
|
||||
<version>6.16.2604.318</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>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Net.Http.Headers;
|
||||
using Yarp.ReverseProxy.Forwarder;
|
||||
using Yarp.ReverseProxy.Forwarder;
|
||||
|
||||
namespace MP.IOC.Services
|
||||
{
|
||||
@@ -8,28 +7,27 @@ namespace MP.IOC.Services
|
||||
{
|
||||
public override async ValueTask TransformRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest, string destinationPrefix, CancellationToken cancellationToken)
|
||||
{
|
||||
// Copia headers standard e method (usa la overload con cancellationToken)
|
||||
// Chiama il base (usa overload con cancellationToken)
|
||||
await base.TransformRequestAsync(httpContext, proxyRequest, destinationPrefix, cancellationToken);
|
||||
|
||||
// Imposta il method correttamente
|
||||
proxyRequest.Method = new HttpMethod(httpContext.Request.Method);
|
||||
|
||||
// Copia body as-is. Per payload grandi preferire streaming (qui usiamo buffering semplice).
|
||||
// Se vuoi leggere/loggare il body, abilita buffering e rewind.
|
||||
// NON assegnare proxyRequest.Content: YARP copierà il body da HttpContext.Request.
|
||||
if (httpContext.Request.ContentLength > 0 || httpContext.Request.Body.CanRead)
|
||||
{
|
||||
// Abilita buffering solo se necessario; attenzione a payload grandi
|
||||
// Abilita buffering solo se necessario (attenzione a payload grandi)
|
||||
httpContext.Request.EnableBuffering();
|
||||
|
||||
// Rewind per sicurezza
|
||||
httpContext.Request.Body.Position = 0;
|
||||
|
||||
var ms = new MemoryStream();
|
||||
await httpContext.Request.Body.CopyToAsync(ms, cancellationToken);
|
||||
ms.Position = 0;
|
||||
|
||||
proxyRequest.Content = new StreamContent(ms);
|
||||
if (!string.IsNullOrEmpty(httpContext.Request.ContentType))
|
||||
{
|
||||
proxyRequest.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(httpContext.Request.ContentType);
|
||||
}
|
||||
|
||||
httpContext.Request.Body.Position = 0;
|
||||
// Se vuoi leggere il body per logging, fallo qui ma non sostituire proxyRequest.Content.
|
||||
// Esempio (opzionale): leggere senza consumare
|
||||
// using var sr = new StreamReader(httpContext.Request.Body, leaveOpen: true);
|
||||
// var bodyText = await sr.ReadToEndAsync();
|
||||
// httpContext.Request.Body.Position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,4 +37,5 @@ namespace MP.IOC.Services
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using NLog;
|
||||
using System.Diagnostics;
|
||||
using Yarp.ReverseProxy.Forwarder;
|
||||
|
||||
namespace MP.IOC.Services
|
||||
@@ -30,13 +31,19 @@ namespace MP.IOC.Services
|
||||
_config = config;
|
||||
}
|
||||
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
#if false
|
||||
public async Task HandleAsync(HttpContext context)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
// Estrapola il catch-all relativo: /MP/IOC/api/RIOB/enabled/SIMUL_01 -> enabled/SIMUL_01
|
||||
var fullPath = context.Request.Path.Value ?? "";
|
||||
var prefix = "/MP/IOC/api/RIOB/";
|
||||
|
||||
var prefix = "/api/RIOB/";
|
||||
//var prefix = "/MP/IOC/api/RIOB/";
|
||||
var relativePath = fullPath.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)
|
||||
? fullPath[prefix.Length..]
|
||||
: fullPath.TrimStart('/');
|
||||
@@ -87,7 +94,7 @@ namespace MP.IOC.Services
|
||||
ActivityTimeout = TimeSpan.FromSeconds(100)
|
||||
};
|
||||
|
||||
var error = await _forwarder.SendAsync(context, destination, _httpClientInvoker, requestOptions, _transformer);
|
||||
var error = await _forwarder.SendAsync(context, destination, _httpClientInvoker, requestOptions, _transformer, context.RequestAborted);
|
||||
|
||||
sw.Stop();
|
||||
_stats.RecordDuration(metodo, sw.Elapsed);
|
||||
@@ -98,6 +105,129 @@ namespace MP.IOC.Services
|
||||
context.Response.StatusCode = 502;
|
||||
await context.Response.WriteAsync(feat?.Exception?.Message ?? "Forward error");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public async Task HandleAsync(HttpContext context)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var routePrefix = new PathString("/api/RIOB");
|
||||
var fullPrefix = context.Request.PathBase.Add(routePrefix);
|
||||
|
||||
string relativePath;
|
||||
string query = context.Request.QueryString.HasValue ? context.Request.QueryString.Value : "";
|
||||
|
||||
if (context.Request.Path.StartsWithSegments(fullPrefix, out var remaining))
|
||||
{
|
||||
relativePath = remaining.Value.TrimStart('/');
|
||||
}
|
||||
else if (context.Request.Path.StartsWithSegments(routePrefix, out remaining))
|
||||
{
|
||||
relativePath = remaining.Value.TrimStart('/');
|
||||
}
|
||||
else
|
||||
{
|
||||
var fullPath = (context.Request.PathBase + context.Request.Path).Value ?? "";
|
||||
var idx = fullPath.IndexOf("/RIOB/", StringComparison.OrdinalIgnoreCase);
|
||||
relativePath = idx >= 0 ? fullPath[(idx + "/RIOB/".Length)..] : fullPath.TrimStart('/');
|
||||
}
|
||||
|
||||
Log.Info($"PathBase={context.Request.PathBase} | Path={context.Request.Path} | relativePath={relativePath}");
|
||||
|
||||
// da calcolare metodo...
|
||||
string metodo = "undef";
|
||||
if (!string.IsNullOrEmpty(relativePath))
|
||||
{
|
||||
// splitto se ho /...
|
||||
if (relativePath.Contains("/"))
|
||||
{
|
||||
metodo = relativePath.Substring(0, relativePath.IndexOf("/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
metodo = relativePath;
|
||||
}
|
||||
}
|
||||
Log.Info($"Metodo: {metodo}");
|
||||
|
||||
var (oldW, newW) = _weightProvider.GetWeightsFor(metodo);
|
||||
var pickNew = DecideByWeights(oldW, newW);
|
||||
|
||||
|
||||
var target = pickNew ? "new" : "old";
|
||||
|
||||
var destBase = pickNew
|
||||
? _config["ReverseProxy:Clusters:cluster-new:Destinations:new1:Address"]
|
||||
: _config["ReverseProxy:Clusters:cluster-old:Destinations:old1:Address"];
|
||||
|
||||
if (!destBase.EndsWith("/")) destBase += "/";
|
||||
//var destination = destBase + relativePath + query;
|
||||
|
||||
//Log.Info("Forwarding to {Destination}", destination);
|
||||
|
||||
//var requestOptions = new ForwarderRequestConfig { ActivityTimeout = TimeSpan.FromSeconds(100) };
|
||||
//var error = await _forwarder.SendAsync(context, destination, _httpClientInvoker, requestOptions, _transformer, context.RequestAborted);
|
||||
|
||||
//sw.Stop();
|
||||
//_stats.RecordDuration(metodo, sw.Elapsed);
|
||||
|
||||
//if (error != ForwarderError.None)
|
||||
//{
|
||||
// var feat = context.GetForwarderErrorFeature();
|
||||
// Log.Error(feat?.Exception, "Forwarder error to {Destination}", destination);
|
||||
// context.Response.StatusCode = 502;
|
||||
// await context.Response.WriteAsync($"Forward error: {feat?.Exception?.Message}");
|
||||
//}
|
||||
|
||||
// salva path originale per ripristino
|
||||
var originalPath = context.Request.Path;
|
||||
var originalPathBase = context.Request.PathBase;
|
||||
|
||||
try
|
||||
{
|
||||
// imposta la Path che vogliamo che YARP appenda al destBase
|
||||
context.Request.Path = new PathString("/" + relativePath);
|
||||
// opzionale: se vuoi che PathBase sia vuoto per il backend, impostalo così
|
||||
context.Request.PathBase = PathString.Empty;
|
||||
|
||||
Log.Info("Forwarding to base {DestBase} with forwarded path {ForwardedPath} (original PathBase={PathBase} Path={Path})",
|
||||
destBase, context.Request.Path, originalPathBase, originalPath);
|
||||
|
||||
var requestOptions = new ForwarderRequestConfig { ActivityTimeout = TimeSpan.FromSeconds(100) };
|
||||
var error = await _forwarder.SendAsync(context, destBase, _httpClientInvoker, requestOptions, _transformer, context.RequestAborted);
|
||||
|
||||
if (error != ForwarderError.None)
|
||||
{
|
||||
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}");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// ripristina i path originali per non rompere la pipeline successiva
|
||||
context.Request.Path = originalPath;
|
||||
context.Request.PathBase = originalPathBase;
|
||||
}
|
||||
}
|
||||
|
||||
private bool DecideByWeights(int oldW, int newW)
|
||||
{
|
||||
bool result = false;
|
||||
// se entrambi zero -> prefer legacy
|
||||
var total = oldW + newW;
|
||||
if (total <= 0)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var rnd = Random.Shared.NextDouble(); // 0..1
|
||||
result = rnd < (double)newW / total;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,8 @@
|
||||
{
|
||||
"RouteId": "route-man-r-iob",
|
||||
"ClusterId": "cluster-placeholder",
|
||||
"Match": { "Path": "/MP/IOC/api/RIOB/{**catch-all}" }
|
||||
"Match": { "Path": "/api/RIOB/{**catch-all}" },
|
||||
//"Match": { "Path": "/MP/IOC/api/RIOB/{**catch-all}" }
|
||||
}
|
||||
],
|
||||
"Clusters": {
|
||||
@@ -73,7 +74,8 @@
|
||||
"DefaultWeightNew": 0
|
||||
},
|
||||
"ServerConf": {
|
||||
"RedisWeight": true
|
||||
"BaseUrl": "/MP/IOC/",
|
||||
"RedisWeight": true
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"MP.Data": "Server=SQL2016DEV;Database=MoonPro; User ID=sa;Password=keyhammer16; integrated security=False; MultipleActiveResultSets=True; App=MP.IOC;",
|
||||
|
||||
Reference in New Issue
Block a user