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 Items { get => defaultHttpContext.Items; set => defaultHttpContext.Items = value; } + public override IServiceProvider RequestServices { get => defaultHttpContext.RequestServices; set => defaultHttpContext.RequestServices = value; } + public override CancellationToken RequestAborted { get => defaultHttpContext.RequestAborted; set => defaultHttpContext.RequestAborted = value; } + public override string TraceIdentifier { get => defaultHttpContext.TraceIdentifier; set => defaultHttpContext.TraceIdentifier = value; } + public override ISession Session { + + get + { + if ((_redis != null) & (sessionId != null)) + return new RedisHttpSession(_redis, sessionId); + else return new MockHttpSession(); + } + + set => defaultHttpContext.Session = value; } + public override void Abort() + { + //throw new NotImplementedException(); + } + } + internal class GxAzureResponseHeaders : IHeaderDictionary + { + HeaderDictionary m_headers; + HttpResponseData m_httpResponseData; + internal GxAzureResponseHeaders(HttpResponseData httpResponseData) + { + m_headers = new HeaderDictionary(); + foreach (var header in httpResponseData.Headers) + { + string[] values = new Microsoft.Extensions.Primitives.StringValues(header.Value.Select(val => val).ToArray()); + m_headers.Add(header.Key, values); + } + m_httpResponseData = httpResponseData; + } + + public StringValues this[string key] + { + get + { + return m_headers[key]; + } + set + { + m_httpResponseData.Headers.Add(key, value.AsEnumerable()); + m_headers[key] = value; + } + } + + public long? ContentLength { get { return m_headers.ContentLength; } set {; } } + + public ICollection Keys { get { return m_headers.Keys; } } + public ICollection Values { get { return m_headers.Values; } } + + public int Count { get { return m_headers.Count; } } + + public bool IsReadOnly { get { return m_headers.IsReadOnly; } } + + public void Add(string key, StringValues value) + { + m_httpResponseData.Headers.Add(key, value.AsEnumerable()); + m_headers.Add(key, value); + } + + public void Add(KeyValuePair item) + { + m_httpResponseData.Headers.Add(item.Key, item.Value.AsEnumerable()); + m_headers.Add(item.Key, item.Value); + } + + public void Clear() + { + m_httpResponseData.Headers.Clear(); + m_headers.Clear(); + } + + public bool Contains(KeyValuePair item) + { + return m_headers.Contains(item); + } + + public bool ContainsKey(string key) + { + return m_headers.ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + m_headers.CopyTo(array, arrayIndex); + } + + public IEnumerator> GetEnumerator() + { + return m_headers.GetEnumerator(); + } + + public bool Remove(string key) + { + m_httpResponseData.Headers.Remove(key); + return m_headers.Remove(key); + } + + public bool Remove(KeyValuePair item) + { + m_httpResponseData.Headers.Remove(item.Key); + return m_headers.Remove(item); + } + + public bool TryGetValue(string key, [MaybeNullWhen(false)] out StringValues value) + { + return m_headers.TryGetValue(key, out value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return m_headers.GetEnumerator(); + } + } + + public class GxHttpAzureResponse : HttpResponse + { + HttpResponseData httpResponseData; + HttpContext httpContext; + + private FeatureReferences _features; + + private readonly static Func _nullResponseFeature = f => null; + private readonly static Func _nullResponseBodyFeature = f => null; + private readonly static Func _newResponseCookiesFeature = f => new ResponseCookiesFeature(f); + + struct FeatureInterfaces + { + public IHttpResponseFeature Response; + public IHttpResponseBodyFeature ResponseBody; + public IResponseCookiesFeature Cookies; + } + public void Initialize() + { + _features.Initalize(httpContext.Features); + } + public void Initialize(int revision) + { + _features.Initalize(httpContext.Features, revision); + } + + private IHttpResponseBodyFeature HttpResponseBodyFeature => + _features.Fetch(ref _features.Cache.ResponseBody, _nullResponseBodyFeature); + + private IResponseCookiesFeature ResponseCookiesFeature => + _features.Fetch(ref _features.Cache.Cookies, _newResponseCookiesFeature); + private IHttpResponseFeature HttpResponseFeature => + _features.Fetch(ref _features.Cache.Response, _nullResponseFeature); + + public GxHttpAzureResponse(HttpContext context, HttpResponseData responseData) + { + httpResponseData = responseData; + httpContext = context; + _features.Initalize(context.Features); + } + public override HttpContext HttpContext => httpContext; + + public override int StatusCode { get => (int)httpResponseData.StatusCode; set => httpResponseData.StatusCode = (System.Net.HttpStatusCode)value; } + + public override IHeaderDictionary Headers + { + get + { + return new GxAzureResponseHeaders(httpResponseData); + } + } + public override Stream Body { get => httpResponseData.Body; set => httpResponseData.Body = value; } + public override long? ContentLength {get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public override string ContentType + { + get + { + var headers = from head in httpResponseData.Headers + where head.Key == "Content-Type" + select head; + foreach (var header in headers) + { + string[] values = new Microsoft.Extensions.Primitives.StringValues(header.Value.Select(val => val).ToArray()); + return (values.First()); + } + return ("application/json"); + } + + set + { + if (!string.IsNullOrEmpty(ContentType)) + httpResponseData.Headers.Remove("Content-Type"); + httpResponseData.Headers.Add("Content-Type", value); + } + } + public override IResponseCookies Cookies + { + get { return ResponseCookiesFeature.Cookies; } + + } + + public override bool HasStarted + { + get { return HttpResponseFeature.HasStarted; } + } + + public override void OnCompleted(Func callback, object state) + { + //throw new NotImplementedException(); + } + public override void OnStarting(Func callback, object state) + { + //throw new NotImplementedException(); + } + + public override void Redirect(string location, bool permanent) + { + //throw new NotImplementedException(); + } + public override PipeWriter BodyWriter + { + get + { + return (PipeWriter.Create(Body)); + } + } + } +} diff --git a/dotnet/src/extensions/Azure/Handlers/HttpHandler/HttpTriggerHandler.cs b/dotnet/src/extensions/Azure/Handlers/HttpHandler/HttpTriggerHandler.cs new file mode 100644 index 000000000..2ee0299d2 --- /dev/null +++ b/dotnet/src/extensions/Azure/Handlers/HttpHandler/HttpTriggerHandler.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using GeneXus.Cache; +using GxClasses.Web; +using GxClasses.Web.Middleware; +using Microsoft.AspNetCore.Http; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; +using StackExchange.Redis; + +namespace GeneXus.Deploy.AzureFunctions.HttpHandler + +{ + public class HttpTriggerHandler + { + + public static Dictionary servicesPathUrl = new Dictionary(); + public List servicesBase = new List(); + public static Dictionary> servicesMap = new Dictionary>(); + public static Dictionary, String>> servicesMapData = new Dictionary, string>>(); + public static Dictionary> servicesValidPath = new Dictionary>(); + + private IGXRouting _gxRouting; + private ICacheService2 _redis; + + public HttpTriggerHandler(IGXRouting gxRouting, ICacheService2 redis) + { + _gxRouting = gxRouting; + if (redis != null && redis.GetType() == typeof(Redis)) + _redis = redis; + } + public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req, + FunctionContext executionContext) + { + + var logger = executionContext.GetLogger("HttpTriggerHandler"); + logger.LogInformation($"GeneXus Http trigger handler. Function processed: {executionContext.FunctionDefinition.Name}."); + + var httpResponseData = req.CreateResponse(); + HttpContext httpAzureContextAccessor = new GXHttpAzureContextAccessor(req, httpResponseData, _redis); + + GXRouting.ContentRootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + GXRouting.AzureFunctionName = executionContext.FunctionDefinition.Name; + + _gxRouting.ProcessRestRequest(httpAzureContextAccessor); + return httpResponseData; + } + } + + 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)); + } + + } + 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; + } + } +} + + + diff --git a/dotnet/src/extensions/Azure/Handlers/Program.cs b/dotnet/src/extensions/Azure/Handlers/Program.cs index ec67ac479..4ebb360d2 100644 --- a/dotnet/src/extensions/Azure/Handlers/Program.cs +++ b/dotnet/src/extensions/Azure/Handlers/Program.cs @@ -22,11 +22,17 @@ static async Task Main() GXRouting.ContentRootPath = roothPath; var host = new HostBuilder() - .ConfigureFunctionsWebApplication() + .ConfigureFunctionsWorkerDefaults() .ConfigureServices(services => { services.AddSingleton(x => new CallMappings(roothPath)); - services.AddControllers(); + }) + .ConfigureServices(services => + { + services.AddSingleton(x => new GXRouting(routePrefix)); + }) + .ConfigureServices(services => + { ISessionService sessionService = GXSessionServiceFactory.GetProvider(); if (sessionService is GxRedisSession) { diff --git a/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs b/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs index 60e7fe592..bed11eb6b 100644 --- a/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs +++ b/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs @@ -21,7 +21,7 @@ public class HttpTriggerTest [Fact] public void HttpApiObjectTest() { - /* try + try { ServiceCollection serviceCollection = new ServiceCollection(); serviceCollection.AddScoped(); @@ -51,13 +51,13 @@ public void HttpApiObjectTest() catch (Exception ex) { throw new Exception("Exception should not be thrown.", ex); - }*/ + } } [Fact] public void HttpTest() { - /* try + try { ServiceCollection serviceCollection = new ServiceCollection(); serviceCollection.AddScoped(); @@ -89,7 +89,7 @@ public void HttpTest() } catch(Exception ex) { throw new Exception("Exception should not be thrown.", ex); - }*/ + } } }