diff --git a/dotnet/src/extensions/Azure/Handlers/GeneXus.Deploy.AzureFunctions.Handlers.csproj b/dotnet/src/extensions/Azure/Handlers/GeneXus.Deploy.AzureFunctions.Handlers.csproj
index 4d8a3d602..a0b5cfa26 100644
--- a/dotnet/src/extensions/Azure/Handlers/GeneXus.Deploy.AzureFunctions.Handlers.csproj
+++ b/dotnet/src/extensions/Azure/Handlers/GeneXus.Deploy.AzureFunctions.Handlers.csproj
@@ -58,7 +58,7 @@
-
+
@@ -69,7 +69,6 @@
-
@@ -100,7 +99,6 @@
-
diff --git a/dotnet/src/extensions/Azure/Handlers/HttpHandler/GXAzureRestServices.cs b/dotnet/src/extensions/Azure/Handlers/HttpHandler/GXAzureRestServices.cs
deleted file mode 100644
index 0dddfc563..000000000
--- a/dotnet/src/extensions/Azure/Handlers/HttpHandler/GXAzureRestServices.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using GeneXus;
-using GeneXus.Application;
-using GeneXus.Cache;
-using GeneXus.Deploy.AzureFunctions.HttpHandler;
-using GeneXus.Utils;
-using Microsoft.AspNetCore.Http;
-
-namespace GxClasses.Web.Middleware
-{
- public class GXAzureRestService : GxRestService
- {
- static readonly IGXLogger log = GXLoggerFactory.GetLogger();
- private readonly ICacheService2 _cacheService;
- public GXAzureRestService(ICacheService2 redis) : base()
- {
- if (GxContext.IsAzureContext)
- {
- if (redis != null && redis.GetType() == typeof(Redis))
- {
- _cacheService = redis;
- }
- }
- }
- public void SetServiceSession(HttpRequest request, HttpResponse response, HttpContext httpContext)
- {
- if (GxContext.IsAzureContext)
- {
- GXHttpAzureContext httpAzureContext;
- if ((context != null & context.HttpContext != null) && (Request != null && Response != null))
- {
- httpAzureContext = new GXHttpAzureContext(Request, Response, _cacheService);
- }
- else
- {
- context.HttpContext = httpContext;
- httpAzureContext = new GXHttpAzureContext(request, response, _cacheService);
-
- }
- if (httpAzureContext != null && httpAzureContext.Session != null)
- context.HttpContext.Session = httpAzureContext.Session;
- else
- GXLogging.Debug(log, $"Azure Serverless: Session could not be created.");
- }
- }
- }
-}
diff --git a/dotnet/src/extensions/Azure/Handlers/HttpHandler/GXHttpAzureContext.cs b/dotnet/src/extensions/Azure/Handlers/HttpHandler/GXHttpAzureContext.cs
deleted file mode 100644
index addb08393..000000000
--- a/dotnet/src/extensions/Azure/Handlers/HttpHandler/GXHttpAzureContext.cs
+++ /dev/null
@@ -1,225 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using GeneXus.Cache;
-using GeneXus.Utils;
-using Microsoft.AspNetCore.Http;
-using StackExchange.Redis;
-
-namespace GeneXus.Deploy.AzureFunctions.HttpHandler
-{
- public class GXHttpAzureContext
- {
- private ICacheService2 _redis;
- private string sessionId;
- private ISession session;
- private static readonly IGXLogger log = GXLoggerFactory.GetLogger();
- internal const string AzureSessionId = "GX_AZURE_SESSIONID";
-
- public ISession Session => session;
-
- public GXHttpAzureContext( HttpRequest request, HttpResponse response, ICacheService2 redis)
- {
- bool isSecure = IsSecureConnection(request);
- sessionId = request.Cookies[AzureSessionId];
-
- if (redis != null && redis.GetType() == typeof(Redis))
- _redis = redis;
-
- if (string.IsNullOrEmpty(sessionId))
- CreateSessionId(isSecure, response, request);
-
- if ((_redis != null) & (sessionId != null))
- session = new RedisHttpSession(_redis, sessionId);
- else
- session = new MockHttpSession();
-
- if (!string.IsNullOrEmpty(sessionId))
- {//Refresh the session timestamp
- if (session is RedisHttpSession)
- {
- RedisHttpSession redisHttpSession = (RedisHttpSession)session;
- //Check if session is in cache
- if (redisHttpSession.SessionKeyExists(sessionId))
- {
- bool success = redisHttpSession.RefreshSession(sessionId);
- if (!success)
- GXLogging.Debug(log, $"Azure Serverless: Session could not be refreshed :{sessionId}");
- }
- }
- }
-
- }
- private bool GetSecureConnection(string headerKey, string headerValue)
- {
- if ((headerKey == "Front-End-Https") & (headerValue == "on"))
- return true;
-
- if ((headerKey == "X-Forwarded-Proto") & (headerValue == "https"))
- return true;
-
- return false;
- }
-
- private bool IsSecureConnection(HttpRequest request)
- {
- if ((request.Cookies["Front-End-Https"] == "on") || (request.Cookies["X-Forwarded-Proto"] == "https"))
- return true;
- else
- return false;
- }
- private void CreateSessionId(bool isSecure, HttpResponse response, HttpRequest request)
- {
- sessionId = Guid.NewGuid().ToString();
-
- if (!isSecure)
- isSecure = request.IsHttps;
-
- CookieOptions cookieOptions = new CookieOptions();
-
- if (!DateTime.MinValue.Equals(DateTimeUtil.NullDate()))
- cookieOptions.Expires = DateTime.MinValue;
- cookieOptions.Path = "";
- cookieOptions.Domain = "";
- cookieOptions.HttpOnly = true;
- cookieOptions.Secure = isSecure;
-
- if (response.Cookies != null)
- response.Cookies.Append(AzureSessionId,sessionId,cookieOptions);
- GXLogging.Debug(log, $"Create new Azure Session Id :{sessionId}");
- }
- public class MockHttpSession : ISession
- {
- string _sessionId = Guid.NewGuid().ToString();
- readonly Dictionary _sessionStorage = new Dictionary();
- string ISession.Id => _sessionId;
- bool ISession.IsAvailable => throw new NotImplementedException();
- IEnumerable ISession.Keys => _sessionStorage.Keys;
- void ISession.Clear()
- {
- _sessionStorage.Clear();
- }
- Task ISession.CommitAsync(CancellationToken cancellationToken)
- {
- throw new NotImplementedException();
- }
- Task ISession.LoadAsync(CancellationToken cancellationToken)
- {
- throw new NotImplementedException();
- }
- void ISession.Remove(string key)
- {
- _sessionStorage.Remove(key);
- }
- void ISession.Set(string key, byte[] value)
- {
- _sessionStorage[key] = Encoding.UTF8.GetString(value);
- }
- bool ISession.TryGetValue(string key, out byte[] value)
- {
-
- if (_sessionStorage.ContainsKey(key) && _sessionStorage[key] != null)
- {
- value = Encoding.ASCII.GetBytes(_sessionStorage[key].ToString());
- return true;
- }
- value = null;
- return false;
- }
- }
- public class RedisHttpSession : ISession
- {
- const int SESSION_TIMEOUT_IN_MINUTES = 5;
- const string AzureRedisCacheId = "REDIS_CACHE_SESSION_ID";
- string _sessionId;
- private Redis _redis;
- public Dictionary data;
- public RedisHttpSession(ICacheService2 redis, string sessionId)
- {
- _redis = (Redis)redis;
- _sessionId = sessionId;
- }
-
- public bool IsAvailable => throw new NotImplementedException();
-
- public string Id => _sessionId;
-
- public IEnumerable Keys => throw new NotImplementedException();
-
- private IEnumerable convert(IEnumerable enumerable)
- {
- foreach (RedisKey key in enumerable)
- yield return key;
- }
- public void Clear()
- {
- _redis.ClearCache(AzureRedisCacheId);
- }
-
- public bool RefreshSession(string sessionId)
- {
- if (_redis.Get(AzureRedisCacheId, sessionId, out Dictionary value))
- {
- int refreshTimeout = (_redis.redisSessionTimeout == 0) ? SESSION_TIMEOUT_IN_MINUTES : _redis.redisSessionTimeout;
- if (value != null)
- {
- return (_redis.KeyExpire(AzureRedisCacheId, sessionId, TimeSpan.FromMinutes(refreshTimeout), CommandFlags.None));
- }
- }
- return false;
- }
-
- public Task CommitAsync(CancellationToken cancellationToken = default)
- {
- throw new NotImplementedException();
- }
-
- public Task LoadAsync(CancellationToken cancellationToken = default)
- {
- throw new NotImplementedException();
- }
-
- public void Remove(string key)
- {
- _redis.ClearKey(key);
- }
-
- public void Set(string key, byte[] value)
- {
- if (!_redis.Get(AzureRedisCacheId, Id, out Dictionary data))
- data = new Dictionary();
- data[key] = value;
-
- if (_redis.redisSessionTimeout != 0)
- _redis.Set(AzureRedisCacheId, Id, data, _redis.redisSessionTimeout);
- else
- _redis.Set(AzureRedisCacheId, Id, data, SESSION_TIMEOUT_IN_MINUTES);
- }
-
- public bool TryGetValue(string key, out byte[] value)
- {
- if (_redis.Get(AzureRedisCacheId, Id, out Dictionary data))
- {
- if (data != null)
- {
- if (data.TryGetValue(key, out byte[] keyvalue))
- {
- value = keyvalue;
- return true;
- }
- }
- }
- value = null;
- return false;
- }
- public bool SessionKeyExists(string sessionId)
- {
- return (_redis.KeyExists(AzureRedisCacheId, sessionId));
- }
-
- }
- }
-
-}
diff --git a/dotnet/src/extensions/Azure/Handlers/HttpHandler/GXHttpAzureContextAccessor.cs b/dotnet/src/extensions/Azure/Handlers/HttpHandler/GXHttpAzureContextAccessor.cs
new file mode 100644
index 000000000..1c3285d3f
--- /dev/null
+++ b/dotnet/src/extensions/Azure/Handlers/HttpHandler/GXHttpAzureContextAccessor.cs
@@ -0,0 +1,373 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.IO.Pipelines;
+using System.Linq;
+using System.Security.Claims;
+using System.Text.Json.Nodes;
+using System.Threading;
+using System.Threading.Tasks;
+using GeneXus.Cache;
+using GeneXus.Utils;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.Azure.Functions.Worker.Http;
+using Microsoft.Extensions.Primitives;
+
+namespace GeneXus.Deploy.AzureFunctions.HttpHandler
+{
+ public class GXHttpAzureContextAccessor : HttpContext
+ {
+ DefaultHttpContext defaultHttpContext = new DefaultHttpContext();
+ public HttpResponse httpResponseData;
+ private ICacheService2 _redis;
+ private string sessionId;
+ private static readonly IGXLogger log = GXLoggerFactory.GetLogger();
+ internal const string AzureSessionId = "GX_AZURE_SESSIONID";
+ public GXHttpAzureContextAccessor(HttpRequestData requestData, HttpResponseData responseData, ICacheService2 redis)
+ {
+ if (redis != null)
+ _redis = redis;
+
+ bool isSecure = false;
+ foreach (var header in requestData.Headers)
+ {
+ string[] values = new Microsoft.Extensions.Primitives.StringValues(header.Value.Select(val => val).ToArray());
+ defaultHttpContext.Request.Headers[header.Key] = new Microsoft.Extensions.Primitives.StringValues(values);
+
+ if (header.Key == "Cookie")
+ {
+ sessionId = CookieValue(defaultHttpContext.Request.Headers[header.Key], AzureSessionId);
+ }
+
+ if (!isSecure)
+ isSecure = GetSecureConnection(header.Key, defaultHttpContext.Request.Headers[header.Key]);
+
+ }
+ if (requestData.FunctionContext.BindingContext != null)
+ {
+ IReadOnlyDictionary keyValuePairs = requestData.FunctionContext.BindingContext.BindingData;
+ object queryparamsJson = requestData.FunctionContext.BindingContext.BindingData.GetValueOrDefault("Query");
+ JsonNode queryparams = JsonNode.Parse((string)queryparamsJson);
+
+ foreach (var keyValuePair in keyValuePairs)
+ {
+ if ((keyValuePair.Key != "Headers") && (keyValuePair.Key != "Query"))
+ {
+ JsonNode qKey = queryparams[keyValuePair.Key];
+ if (qKey == null)
+ defaultHttpContext.Request.RouteValues.Add(keyValuePair.Key.ToLower(), keyValuePair.Value);
+ }
+ }
+ }
+
+ defaultHttpContext.Request.Method = requestData.Method;
+ defaultHttpContext.Request.Body = requestData.Body;
+ defaultHttpContext.Request.Path = PathString.FromUriComponent(requestData.Url);
+ defaultHttpContext.Request.QueryString = QueryString.FromUriComponent(requestData.Url);
+
+
+ IHttpRequestFeature requestFeature = defaultHttpContext.Features.Get();
+ requestFeature.RawTarget = defaultHttpContext.Request.Path.HasValue ? defaultHttpContext.Request.Path.Value : String.Empty;
+ defaultHttpContext.Features.Set(requestFeature);
+
+ if (string.IsNullOrEmpty(sessionId))
+ {
+ CreateSessionId(isSecure, responseData, requestData);
+ }
+ else //Refresh the session timestamp
+ {
+ if (Session is RedisHttpSession)
+ {
+ RedisHttpSession redisHttpSession = (RedisHttpSession)Session;
+ //Check if session is in cache
+ if (redisHttpSession.SessionKeyExists(sessionId))
+ {
+ bool success = redisHttpSession.RefreshSession(sessionId);
+ if (!success)
+ GXLogging.Debug(log, $"Azure Serverless: Session could not be refreshed :{sessionId}");
+ }
+ }
+ }
+
+ httpResponseData = new GxHttpAzureResponse(defaultHttpContext, responseData);
+ }
+ private bool GetSecureConnection(string headerKey, string headerValue)
+ {
+ if ((headerKey == "Front-End-Https") & (headerValue == "on"))
+ return true;
+
+ if ((headerKey == "X-Forwarded-Proto") & (headerValue == "https"))
+ return true;
+
+ return false;
+ }
+ private void CreateSessionId(bool isSecure, HttpResponseData responseData, HttpRequestData requestData)
+ {
+ sessionId = Guid.NewGuid().ToString();
+ HttpCookie sessionCookie = new HttpCookie(AzureSessionId, sessionId);
+
+ if (!isSecure)
+ isSecure = requestData.Url.Scheme == "https";
+
+ if (!DateTime.MinValue.Equals(DateTimeUtil.NullDate()))
+ sessionCookie.Expires = DateTime.MinValue;
+ sessionCookie.Path = "";
+ sessionCookie.Domain = "";
+ sessionCookie.HttpOnly = true;
+ sessionCookie.Secure = isSecure;
+
+ if (responseData.Cookies != null)
+ responseData.Cookies.Append(sessionCookie);
+ GXLogging.Debug(log, $"Create new Azure Session Id :{sessionId}");
+ }
+ private string CookieValue(string header, string name)
+ {
+ string[] words = header.Split(';');
+
+ foreach (string word in words)
+ {
+ string[] parts = word.Split('=');
+ if (parts[0].Trim() == name)
+ return parts[1];
+ }
+ return string.Empty;
+ }
+ public override IFeatureCollection Features => defaultHttpContext.Features;
+
+ public override HttpRequest Request => defaultHttpContext.Request;
+
+ public override HttpResponse Response => httpResponseData;
+
+ public override ConnectionInfo Connection => defaultHttpContext.Connection;
+
+ public override WebSocketManager WebSockets => defaultHttpContext.WebSockets;
+
+ public override ClaimsPrincipal User { get => defaultHttpContext.User; set => defaultHttpContext.User = value; }
+ public override IDictionary