Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@
[assembly: InternalsVisibleTo("GeneXus.OpenTelemetry.Diagnostics")]
[assembly: InternalsVisibleTo("ConsoleApp2")]
[assembly: InternalsVisibleTo("GxAI")]
[assembly: InternalsVisibleTo("GxRedis")]

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Threading;
using System.Threading.Tasks;
using GeneXus.Application;
using GeneXus.Cache;
using GeneXus.Configuration;
using GeneXus.Data;
using GeneXus.Data.ADO;
Expand Down Expand Up @@ -70,7 +71,6 @@ public class GxRedisSession : ISessionService
internal static string SESSION_INSTANCE = "SESSION_PROVIDER_INSTANCE_NAME";
internal static string SESSION_PASSWORD = "SESSION_PROVIDER_PASSWORD";
static string SESSION_TIMEOUT = "SESSION_PROVIDER_SESSION_TIMEOUT";
const string SUBDOMAIN = "%SUBDOMAIN%";
public GxRedisSession(GXService serviceProvider)
{
string password = serviceProvider.Properties.Get(SESSION_PASSWORD);
Expand Down Expand Up @@ -110,7 +110,7 @@ public GxRedisSession(string host, string password, string instanceName, int ses
}
internal bool IsMultitenant
{
get { return InstanceName == SUBDOMAIN; }
get { return InstanceName == CacheFactory.SUBDOMAIN; }
}
public string ConnectionString { get; }
public string InstanceName { get; }
Expand Down
15 changes: 10 additions & 5 deletions dotnet/src/dotnetcore/GxNetCoreStartup/SessionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public TenantRedisCache(IHttpContextAccessor httpContextAccessor, IServiceProvid

private IDistributedCache GetTenantCache()
{
string tenantId = _httpContextAccessor.HttpContext?.Items[TenantMiddleware.TENANT_ID]?.ToString() ?? "default";
string tenantId = _httpContextAccessor.HttpContext?.Items[AppContext.TENANT_ID]?.ToString() ?? "default";

return _redisCaches.GetOrAdd(tenantId, id =>
{
Expand All @@ -51,7 +51,6 @@ private IDistributedCache GetTenantCache()

public class TenantMiddleware
{
internal const string TENANT_ID = "TenantId";
private readonly RequestDelegate _next;

public TenantMiddleware(RequestDelegate next)
Expand All @@ -61,9 +60,15 @@ public TenantMiddleware(RequestDelegate next)

public async Task Invoke(HttpContext context)
{
string host = context.Request.Host.Host;
string subdomain = host.Split('.').FirstOrDefault();
context.Items[TENANT_ID] = subdomain;
string host = context?.Request?.Host.Host ?? string.Empty;
string subdomain;

if (!string.IsNullOrEmpty(host) && host.Contains('.'))
{
subdomain = host.Split('.').FirstOrDefault();
if (!string.IsNullOrEmpty(subdomain))
context.Items[AppContext.TENANT_ID] = subdomain;
}

await _next(context);
}
Expand Down
6 changes: 1 addition & 5 deletions dotnet/src/dotnetcore/GxNetCoreStartup/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -540,11 +540,7 @@ public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHos
app.UseStaticFiles();

ISessionService sessionService = GXSessionServiceFactory.GetProvider();
GxRedisSession gxRedisSession = sessionService as GxRedisSession;
if (gxRedisSession != null && gxRedisSession.IsMultitenant)
{
app.UseMiddleware<TenantMiddleware>();
}
app.UseMiddleware<TenantMiddleware>();

ConfigureCors(app);
ConfigureSwaggerUI(app, baseVirtualPath);
Expand Down
3 changes: 2 additions & 1 deletion dotnet/src/dotnetcore/Providers/Cache/GxRedis/GxRedis.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<PackageTags>Redis</PackageTags>
<PackageId>GeneXus.Redis.Core</PackageId>
<DefineConstants>NETCORE</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<AppDesignerFolder>Properties</AppDesignerFolder>
Expand Down
33 changes: 30 additions & 3 deletions dotnet/src/dotnetframework/GxClasses/Core/GXApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,12 @@ public interface IGxContext
#if NETCORE
internal static class AppContext
{
internal const string TENANT_ID = "TenantId";
internal static string TenantId
{
get => Current?.Items[TENANT_ID]?.ToString() ?? "default";
}

static IHttpContextAccessor _httpContextAccessor { get; set; }
internal static HttpContext Current => _httpContextAccessor != null ? new GxHttpContextAccesor(_httpContextAccessor) : null;
internal static void Configure(IHttpContextAccessor accessor)
Expand Down Expand Up @@ -365,6 +371,9 @@ public class GxContext : IGxContext
internal const string GXLanguage = "GXLanguage";
internal const string GXTheme = "GXTheme";
internal const string SERVER_VAR_HTTP_HOST = "HTTP_HOST";
#if NETCORE
string _tenantId;
#endif
internal const string CURRENT_GX_CONTEXT = "CURRENT_GX_CONTEXT";
[NonSerialized]
HttpContext _HttpContext;
Expand Down Expand Up @@ -1193,10 +1202,8 @@ private void LocalInitialize()
Config.LoadConfiguration();
}


public static bool isReorganization { get; set; }


public bool IsMultipartRequest
{
get
Expand All @@ -1212,6 +1219,23 @@ public bool IsMultipartRequest
return false;
}
}
#if NETCORE
internal string TenantId
{
get
{
if (string.IsNullOrEmpty(_tenantId) && HttpContext != null)
{
_tenantId = AppContext.TenantId;
}
return _tenantId;
}
set
{
_tenantId = value;
}
}
#endif
public IGxContext UtlClone()
{
//Context for new LUW
Expand Down Expand Up @@ -4053,6 +4077,9 @@ public void SetSubmitInitialConfig(IGxContext context)
this.SetPhysicalPath(context.GetPhysicalPath());
this.SetLanguageWithoutSession(context.GetLanguage());
this.ClientID = context.ClientID;
#if NETCORE
this.TenantId = (context as GxContext)?.TenantId;
#endif
InitializeSubmitSession(context, this);
}

Expand Down Expand Up @@ -4235,4 +4262,4 @@ public override string GetScriptPath()
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOp
public class CacheFactory
{
private static readonly IGXLogger log = GXLoggerFactory.GetLogger<CacheFactory>();

internal const string SUBDOMAIN = "%SUBDOMAIN%";
public static string CACHE_SD = "SD";
public static string CACHE_DB = "DB";
public static string CACHE_FILES = "FL";
Expand Down
41 changes: 40 additions & 1 deletion dotnet/src/dotnetframework/Providers/Cache/GxRedis/GxRedis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
#if NETCORE
using GeneXus.Application;
#endif
using GeneXus.Encryption;
using GeneXus.Services;
using GeneXus.Utils;
using StackExchange.Redis;
using StackExchange.Redis.KeyspaceIsolation;

namespace GeneXus.Cache
{
Expand All @@ -16,9 +20,14 @@ public sealed class Redis : ICacheService2

ConnectionMultiplexer _redisConnection;
IDatabase _redisDatabase;
#if NETCORE
bool _multitenant;
#endif
ConfigurationOptions _redisConnectionOptions;
private const int REDIS_DEFAULT_PORT = 6379;
public int redisSessionTimeout;
private string _instanceName;

public Redis(string connectionString)
{
_redisConnectionOptions = ConfigurationOptions.Parse(connectionString);
Expand All @@ -39,6 +48,8 @@ public Redis()
string address, password;
address = providerService.Properties.Get("CACHE_PROVIDER_ADDRESS");
password = providerService.Properties.Get("CACHE_PROVIDER_PASSWORD");
_instanceName = providerService.Properties.Get("CACHE_PROVIDER_INSTANCE_NAME");

if (!string.IsNullOrEmpty(password))
{
string ret = string.Empty;
Expand Down Expand Up @@ -74,7 +85,29 @@ IDatabase RedisDatabase
if (_redisDatabase == null)
{
_redisConnection = ConnectionMultiplexer.Connect(_redisConnectionOptions);
_redisDatabase = _redisConnection.GetDatabase();
IDatabase db = _redisConnection.GetDatabase();

if (!string.IsNullOrEmpty(_instanceName))
{
#if NETCORE
if (_instanceName == CacheFactory.SUBDOMAIN)
{
_multitenant = true;
GXLogging.Debug(log, "Using Redis multitenant (key prefix):" + CacheFactory.SUBDOMAIN);
_redisDatabase = db;
}
else
#endif
{
string prefixKey = _instanceName.EndsWith(":") ? _instanceName : _instanceName + ":";
_redisDatabase = db.WithKeyPrefix(_instanceName);
GXLogging.Debug(log, "Using Redis instance name (key prefix): " + prefixKey);
}
}
else
{
_redisDatabase = db;
}
}
return _redisDatabase;
}
Expand Down Expand Up @@ -221,6 +254,12 @@ private IEnumerable<RedisKey> Key(string cacheid, IEnumerable<string> key)
}
private string FormatKey(string cacheid, string key, Nullable<long> prefix)
{
#if NETCORE
if (_multitenant)
{
return String.Format("{0}:{1}_{2}_{3}", GxContext.Current.TenantId, cacheid, prefix, GXUtil.GetHash(key));
}
#endif
return String.Format("{0}_{1}_{2}", cacheid, prefix, GXUtil.GetHash(key));
}
private Nullable<long> KeyPrefix(string cacheid)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<PackageId>GeneXus.Redis</PackageId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="StackExchange.Redis" Version="2.2.4" />
<PackageReference Include="StackExchange.Redis" Version="2.6.122" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
</ItemGroup>
<ItemGroup>
Expand Down
Loading