hi
https://abp.io/community/articles/using-elsa-3-with-the-abp-framework-a-comprehensive-guide-usqk8afg
hi
the Redis Cache should be cleared
No. Redis should not be cleared after every new deployment. Otherwise, the previous encryption/keys will be invalid.
https://abp.io/support/questions/9298/ABP-9-Upgrade---login-screen-409-error#answer-3a19e8d7-17da-d8d3-adf3-218e523e9630
hi
Can you share full debug/error logs?
Thanks.
liming.ma@volosoft.com
https://abp.io/support/questions/8622/How-to-enable-Debug-logs-for-troubleshoot-problems
Great
Check the full logs see:
If the redis was cleared, the log will show Creating key for every deployment.
[INF] Creating key {12da01ce-7e32-43e6-bc76-3bb8a969cccc} with creation date 2025-05-16 01:14:05Z, activation date 2025-05-16 01:14:05Z, and expiration date 2025-08-14 01:14:05Z.
[WRN] No XML encryptor configured. Key {12da01ce-7e32-43e6-bc76-3bb8a969cccc} may be persisted to storage in unencrypted form.
hi
For each deployment Redis container would be cleared or not?
You can check your deployment setting.
Is your Redis running in a container or on a physical machine?
Thanks.
ok.thanks
hi
Add a AddTenantToRoute
class then add it to aspnet core system.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Routing;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.MultiTenancy;
namespace MyCompanyName.MyProjectName.Web;
public class AddTenantToRoute : IPageRouteModelConvention, IApplicationModelConvention
{
public void Apply(PageRouteModel model)
{
var selectorCount = model.Selectors.Count;
var selectorModels = new List<SelectorModel>();
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
selectorModels.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Template = AttributeRouteModel.CombineTemplates("{__tenant:regex(^[a-zA-Z0-9]+$)}", selector.AttributeRouteModel!.Template!.RemovePreFix("/"))
}
});
}
foreach (var selectorModel in selectorModels)
{
model.Selectors.Add(selectorModel);
}
}
public void Apply(ApplicationModel application)
{
var controllers = application.Controllers;
foreach (var controller in controllers)
{
var selector = controller.Selectors.FirstOrDefault();
if (selector == null || selector.AttributeRouteModel == null)
{
controller.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Template = AttributeRouteModel.CombineTemplates("{__tenant:regex(^[[a-zA-Z0-9]]+$)}", controller.ControllerName)
}
});
controller.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Template = controller.ControllerName
}
});
}
else
{
var template = selector.AttributeRouteModel?.Template;
template = template.IsNullOrWhiteSpace() ? "{__tenant:regex(^[[a-zA-Z0-9]]+$)}" : AttributeRouteModel.CombineTemplates("{__tenant:regex(^[[a-zA-Z0-9]]+$)}", template.RemovePreFix("/"));
controller.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Template = template
}
});
}
}
}
}
public class MyRouteTenantResolveContributor : RouteTenantResolveContributor
{
public const string ContributorName = "MyRoute";
public override string Name => ContributorName;
protected override Task<string?> GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext)
{
var tenantId = httpContext.GetRouteValue(context.GetAbpAspNetCoreMultiTenancyOptions().TenantKey) ?? httpContext.Request.PathBase.ToString();
var tenantIdStr = tenantId?.ToString()?.RemovePreFix("/");
return Task.FromResult(!tenantIdStr.IsNullOrWhiteSpace() ? Convert.ToString(tenantIdStr) : null);
}
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
//...
PostConfigure<RazorPagesOptions>(options =>
{
options.Conventions.Add(new AddTenantToRoute());
});
PostConfigure<MvcOptions>(options =>
{
options.Conventions.Add(new AddTenantToRoute());
});
context.Services.ConfigureApplicationCookie(x =>
{
x.Cookie.Path = "/";
});
Configure<AbpTenantResolveOptions>(options =>
{
options.TenantResolvers.Add(new MyRouteTenantResolveContributor());
});
//...
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
//...
app.Use(async (httpContext, next) =>
{
var tenantMatch = Regex.Match(httpContext.Request.Path, "^/([^/.]+)(?:/.*)?$");
if (tenantMatch.Groups.Count > 1 && !string.IsNullOrEmpty(tenantMatch.Groups[1].Value))
{
var tenantName = tenantMatch.Groups[1].Value;
if (!tenantName.IsNullOrWhiteSpace())
{
var tenantStore = httpContext.RequestServices.GetRequiredService<ITenantStore>();
var tenantNormalizer = httpContext.RequestServices.GetRequiredService<ITenantNormalizer>();
var tenantInfo = await tenantStore.FindAsync(tenantNormalizer.NormalizeName(tenantName)!);
if (tenantInfo != null)
{
if (httpContext.Request.Path.StartsWithSegments(new PathString(tenantName.EnsureStartsWith('/')), out var matchedPath, out var remainingPath))
{
var originalPath = httpContext.Request.Path;
var originalPathBase = httpContext.Request.PathBase;
httpContext.Request.Path = remainingPath;
httpContext.Request.PathBase = originalPathBase.Add(matchedPath);
try
{
await next(httpContext);
}
finally
{
httpContext.Request.Path = originalPath;
httpContext.Request.PathBase = originalPathBase;
}
return;
}
}
}
}
await next(httpContext);
});
app.UseRouting();
app.MapAbpStaticAssets();
//...