ABP Framework version: v8.1.4
UI Type: Angular
Database System: EF Core ( PostgreSQL)
Tiered (for MVC) or Auth Server Separated (for Angular): yes
Exception message and full stack trace: [17:50:42 INF] fail: 11/16/2024 17:50:42.340 CoreEventId.SaveChangesFailed[10000] (Microsoft.EntityFrameworkCore.Update) An exception occurred in the database while saving changes for context type 'Doohlink.PlaylistManagement.EntityFrameworkCore.PlaylistManagementDbContext'. Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details. ---> Npgsql.PostgresException (0x80004005): 23503: insert or update on table "PlaylistManagementPlaylistFiles" violates foreign key constraint "FK_PlaylistManagementPlaylistFiles_PlaylistManagementFiles_Fil~"
DETAIL: Key (FileId)=(3a1647cd-ead1-7bbc-8095-7c274e70176b) is not present in table "PlaylistManagementFiles".
Steps to reproduce the issue: Hello, I have a general question about data filtering. I have 3 tables in my database Playlist,File and PlaylistFile. you can see the entities and aggregate roots below.
File
public class File : AggregateRoot<Guid>, IMultiTenant, ISoftDelete
{
public bool IsDeleted { get; protected set; }
public Guid? TenantId { get; protected set; }
public string Name { get; private set; }= null!;
//rest of the code
}
Playlist
public class Playlist : FullAuditedAggregateRoot<Guid>, IMultiTenant
{
public Guid? TenantId { get; protected set; }
public string Name { get; private set; } = null!;
public string? Description { get; set; }
//rest of the code
}
PlaylistFile
public class PlaylistFile:CreationAuditedAggregateRoot<Guid>,ISoftDelete
{
public bool IsDeleted { get; protected set; }
public Guid PlaylistId { get; private set; }
public Guid FileId { get; private set; }
//rest of the code
}
so as you can see playlist and file is having imultitenant interface but since playlistfile belongs to two other table, i preferred to not make it imultitenat. The problem i am having is when i use separete db for a tenant. since PlaylistFile doesn't have imultitenant interface, when i use separate db for tenant even if the current tenant is the tenant with separate db connection string, it tries to insert it to the shared database. Here is an example from an app service.
public async Task CreateBatchAsync(Guid playlistId, CreateOrUpdatePlaylistFilesDto input)
{
await _playlistRepository.GetAsync(playlistId);
var newFileIds = input.FileIds.ToList();
var playlistFiles = await _playlistFileManager.CreateBatchAsync(playlistId, newFileIds);
foreach (var playlistFile in playlistFiles)
{
await _playlistFileRepository.InsertAsync(playlistFile);
}
}
in this code _playlistRepository is looking at the separate db since it has imultitenant interface but when i try to insert the records through _playlistFileRepository it takes the shared connection string. And i am getting exception since no fileid is present on the shared db. Is this common behavior? I know that i can give imultitenant interface to PlaylistFile aggregate root, but i do not prefer that since it is a table that will reflect the tenantid from their parent table. Is there any other way to fix it?
1 processor, IResultBox
1 resultBox, ServerEndPoint& server) in //src/StackExchange.Redis/ConnectionMultiplexer.cs:line 1966at StackExchange.Redis.ConnectionMultiplexer.TryPushMessageToBridgeAsync[T](Message message, ResultProcessor1 processor, IResultBox
1 resultBox, ServerEndPoint& server) in //src/StackExchange.Redis/ConnectionMultiplexer.cs:line 2004
at StackExchange.Redis.ConnectionMultiplexer.ExecuteAsyncImpl[T](Message message, ResultProcessor1 processor, Object state, ServerEndPoint server) in /_/src/StackExchange.Redis/ConnectionMultiplexer.cs:line 2182 at StackExchange.Redis.RedisBase.ExecuteAsync[T](Message message, ResultProcessor
1 processor, ServerEndPoint server) in //src/StackExchange.Redis/RedisBase.cs:line 54at StackExchange.Redis.RedisDatabase.KeyDeleteAsync(RedisKey[] keys, CommandFlags flags) in //src/StackExchange.Redis/RedisDatabase.cs:line 769
at Volo.Abp.Caching.StackExchangeRedis.AbpRedisCache.RemoveManyAsync(IEnumerable1 keys, CancellationToken token) at Volo.Abp.Caching.DistributedCache
2.<>c__DisplayClass63_0.<g__RemoveRealCache|0>d.MoveNext()The Problem i am facing is related with redis cache. If you use Redis Cluster instead of single instance of redis, you are facing an issue that some values are remaining in redis cache or they are not the same with the values in db. This brings the unstable behavior in the application. To give an example. 1- Change Database Connection Strings for a tenant. 2- Then try to login with that tenant, it will use the new connection string. 3- Afterwards try to revert it back to shared database. 4- You will get the error and it is not going to delete it from redis cache. 5- Even in database it is using the shared database, it will still use the connection string, since it stayed in cache in that way.
ps: it can be also vice versa( from redis cache it is gonna come an empty connection strings while in db there are connection strings). So the point is cache not becoming stable with database.
/// <summary>
/// Apply pending EF Core schema migrations to the database.
/// Returns true if any migration has applied.
/// </summary>
protected virtual async Task<bool> MigrateDatabaseSchemaAsync(Guid? tenantId)
{
var result = false;
Logger.LogError($"MigrateDatabaseSchemaAsync tenantId: {tenantId}");
using (CurrentTenant.Change(tenantId))
{
using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false))
{
async Task<bool> MigrateDatabaseSchemaWithDbContextAsync()
{
var dbContext = await uow.ServiceProvider
.GetRequiredService<IDbContextProvider<TDbContext>>()
.GetDbContextAsync();
if ((await dbContext.Database.GetPendingMigrationsAsync()).Any())
{
await dbContext.Database.MigrateAsync();
Logger.LogError($"Migrated Database for tenant: {tenantId}");
return true;
}
return false;
}
Logger.LogError($"Starting migration for {tenantId}");
if (tenantId == null)
{
//Migrating the host database
Logger.LogInformation($"Migrating database of host. Database Name = {DatabaseName}");
Logger.LogError($"Migrating database of host. Database Name = {DatabaseName}");
result = await MigrateDatabaseSchemaWithDbContextAsync();
}
else
{
var tenantConfiguration = await TenantStore.FindAsync(tenantId.Value);
Logger.LogError("Tenant Configuration: "+tenantConfiguration?.Name);
Logger.LogError("Connection string values: " + (tenantConfiguration?.ConnectionStrings?.Values != null ? string.Join(", ", tenantConfiguration.ConnectionStrings.Values) : "null"));
Logger.LogError($"Connections strings is null: {tenantConfiguration?.ConnectionStrings != null}");
Logger.LogError($"tenantConfiguration.ConnectionStrings.Default is null or whitespace: {tenantConfiguration?.ConnectionStrings?.Default.IsNullOrWhiteSpace()}");
Logger.LogError($"tenantConfiguration.ConnectionStrings.GetOrDefault is null or whitespace: {tenantConfiguration?.ConnectionStrings?.GetOrDefault(DatabaseName).IsNullOrWhiteSpace()}");
if (tenantConfiguration != null
&& tenantConfiguration.ConnectionStrings != null
&& (!tenantConfiguration.ConnectionStrings.Default.IsNullOrWhiteSpace() || !tenantConfiguration.ConnectionStrings.GetOrDefault(DatabaseName).IsNullOrWhiteSpace()))
{
//Migrating the tenant database (only if tenant has a separate database)
Logger.LogInformation($"Migrating separate database of tenant. Database Name = {DatabaseName}, TenantId = {tenantId}");
Logger.LogError($"Migrating separate database of tenant. Database Name = {DatabaseName}, TenantId = {tenantId}");
result = await MigrateDatabaseSchemaWithDbContextAsync();
Logger.LogError($"Migrated separate database of tenant. Database Name = {DatabaseName}, TenantId = {tenantId}");
Logger.LogError("Connection string values: " + (tenantConfiguration?.ConnectionStrings?.Values != null ? string.Join(", ", tenantConfiguration.ConnectionStrings.Values) : "null"));
}
}
await uow.CompleteAsync();
}
}
return result;
}
The tenant configuration here
var tenantConfiguration = await TenantStore.FindAsync(tenantId.Value);
is giving me an empty connection strings time to time even if connection strings are defined in my database. I fix this by changing it to a single instance of redis cache, but it could be nice to use redis-cluster for performance. if you want to try, you can use helm chart that is provided by bitnami from this link. https://github.com/bitnami/charts/tree/main/bitnami/redis-cluster
Hello. I didn't switch to abp studio. I still use abp cli for my app. But my application is deployed on Kubernetes Cluster on azure. I have some manifest files to deploy the application. What i wonder is, If i use abp studio, can i debug my app remotely from my local machine. Even if i do not use the helm charts that abp studio is produced? So i want to deploy my app as usual but use abp studio to debug it. Is it possible to do sth like that?
Hello, I am trying to programmatically select an item from the left menu and make it expanded or selected. I am injecting NavbarService, and tried to use expandItems() method. But it didn't work. Is there any example to programmatically select a menu item when the page is loading? this
this.navbarService.navbarItems$.subscribe(items => {
items.forEach(item => {
if (item.text === 'Approve It') {
item.expanded = true;
} else {
item.expanded = false;
}
this.changeDetectorRef.markForCheck();
});
});
or this
this.navbarService.expandItems();
not working.
Hello i have upgraded my project from 8.1.1 to 8.1.3 soon. It was a smooth transition but afterwards i realized, if i do a call to backend and backend do not return anything as response then leptonx theme is redirecting the page to an error page.
When i do the same call through postman what i get is 204 response.
what can be the reason that ui is redirected to error page. Whenever http call is 204 response instead of 200 response?
Hello, I have created a new angular project that will run side by side with the original project. I have created the angular project from scratch and manage to make it work here is my package.json
{
"name": "angular-extra",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve --port 4201 --open",
"build": "ng build",
"build:prod": "ng build --configuration production",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"lint": "ng lint"
},
"private": true,
"dependencies": {
"@abp/ng.components": "~8.1.3",
"@abp/ng.core": "~8.1.3",
"@abp/ng.oauth": "~8.1.3",
"@abp/ng.setting-management": "~8.1.3",
"@abp/ng.theme.shared": "~8.1.3",
"@volo/abp.commercial.ng.ui": "~8.1.3",
"@volo/abp.ng.openiddictpro": "~8.1.3",
"@volo/abp.ng.language-management": "~8.1.3",
"@volosoft/abp.ng.theme.lepton-x": "~3.1.3",
"@angular/animations": "~17.1.0",
"@angular/common": "~17.1.0",
"@angular/compiler": "~17.1.0",
"@angular/core": "~17.1.0",
"@angular/forms": "~17.1.0",
"@angular/localize": "~17.1.0",
"@angular/platform-browser-dynamic": "~17.1.0",
"@angular/platform-browser": "~17.1.0",
"@angular/router": "~17.1.0",
"rxjs": "~7.8.0",
"tslib": "^2.0.0",
"zone.js": "~0.14.0",
"@stripe/stripe-js": "^2.1.1"
},
"devDependencies": {
"@abp/ng.schematics": "~8.1.3",
"@angular-devkit/build-angular": "~17.1.0",
"@angular-eslint/builder": "~17.2.0",
"@angular-eslint/eslint-plugin": "~17.2.0",
"@angular-eslint/eslint-plugin-template": "~17.2.0",
"@angular-eslint/schematics": "~17.2.0",
"@angular-eslint/template-parser": "~17.2.0",
"@angular/cli": "~17.1.0",
"@angular/compiler-cli": "~17.1.0",
"@angular/language-service": "~17.1.0",
"@types/jasmine": "~3.6.0",
"@types/node": "^20.0.0",
"@typescript-eslint/eslint-plugin": "6.9.1",
"@typescript-eslint/parser": "6.9.1",
"eslint": "^8.0.0",
"jasmine-core": "~4.0.0",
"karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.1.0",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.0.0",
"typescript": "~5.3.0"
}
}
Whenever i run it, i am getting an locale error.
I know this questions have been asked. And the solution was try to downgrade Angular version to 17.1.x. I have deleted all the node_modules dir. Also yarn.lock file and clear the cache. It still gives me the error. And you can see angular version is 17.1.3 from here.
if i create a new project from scratch there is no problem. when i look at the sources tab in google chrome dev. I am seeing that @angular/common is not loaded. I think the problem is happening because of that. You can see not working angular project below.
and here is the sources from the new abp project.
what can be the reason that my new angular project that is created with angular cli do not load @angular/common/locales but new abp template has it? what am i forgetting to include here?
(Volo.Saas.Host.Dtos.SaasTenantCreateDto) on controller Volo.Saas.Host.TenantController (Volo.Saas.Host.HttpApi). [20:03:59 WRN] ---------- RemoteServiceErrorInfo ----------
{
"code": null,
"message": "Your request is not valid!",
"details": "The following errors were detected during validation.\r\n - The ExtraProperties field is required.\r\n",
"data": {},
"validationErrors": [
{
"message": "The ExtraProperties field is required.",
"members": [
"connectionStrings.Databases[0].ExtraProperties"
]
}
]
}
[20:03:59 WRN] ModelState is not valid! See ValidationErrors for details. Volo.Abp.Validation.AbpValidationException: ModelState is not valid! See ValidationErrors for details.
When i create a new tenant with separate connection string, I am getting an error. When i inspect it from chrom dev console, it seems like null has been assigned to extra properties value. That's why i believe I am getting a validation error. you can see the picture.
How can i fix this can you suggest a solution?
Hello i use web assembly inside my angular app. I need to enable shared array buffer for that to work.I need to add two headers from the server which is
"Cross-Origin-Embedder-Policy": "require-corp", "Cross-Origin-Opener-Policy": "same-origin"
to do that i edited my package.json.
this was working with lepton theme 3.0.0, now i have upgraded my project to v3.1.1 when the page is loading it tries to get a font file
and i am getting an error because of require-corp
is it possible in lepton x theme, to load this font with cross origin anonymous instead of directly importing the url https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy#avoiding_coep_blockage_with_cors
and also is there any workaround i can use to fix the issue?
Hello, I have a monolith abp application, which i created separate modules inside. Now i have created host application on one of my modules to use it as a microservice.
While i am converting the app to support microservice. I have realized that monolith app use IDataSeeder for data seeding then all the classes that implements IDataSeedContributor is contributing to data seed process. And this is working perfectly. For ex: when i create a new tenant, it also creates the admin user, and give permissions.
But when i was looking at the abp microservice startup template i have seen that, for identity,openiddict,permissions and language there are different data seeders. These implementations are custom implementations and do not use IDataSeeder. so here is my questions.
Thank you for the assistance.
Hello, I am having strange issue about the authentication from console app. here is my code to do the auth.
this code works fine when I use email address as username, but when i switch to username ("admin"). it doesn't login and it gives me invalid_grant(invalid username or password!) exception.
is this expected behavior or is there a way to login with username or email address?