Starts in:
2 DAYS
14 HRS
53 MIN
25 SEC
Starts in:
2 D
14 H
53 M
25 S
Open Closed

Data Seeding in monolith and microservice. #6950


User avatar
0
cangunaydin created
  • ABP Framework version: v8.0.0
  • Database System: EF Core (PostgreSQL)
  • Tiered (for MVC) or Auth Server Separated (for Angular): yes

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.

  • Is it possible to use IDataSeeder in microservice projects to seed data? For ex, for identity data seeding, if your microservice includes identity module you can just call _dataSeeder.Seed() method with a context and all the contributors should contribute to data seeding. Why this option is not used? As i see from microservice template, all the data seeding has been done one by one.

  • to test the idea i have injected IDataSeeder to event handler class. When tenant is created, the SeedAsync() method triggered. User has been created but there has been some problems with permissions (permissions are not created for the admin user of the new tenant). So another question regarding the situation, how does monolith app seeding the permissions for new tenant's admin with _dataSeeder.SeedAsync() method? And why it doesn't work on microservice startup template?

Thank you for the assistance.


25 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Have you checked this documentation?

    https://docs.abp.io/en/commercial/latest/startup-templates/microservice/database-migrations

  • User Avatar
    0
    cangunaydin created

    Hello again, yes i have read that, but the question over here is

    Why IDataSeeder is not directly triggered even on the fly migrations? Cause the microservice already includes those classes (classes that implements IDataSeedContributor)?

    To examplify it. Why don't we directly trigger IDataSeeder like i have shown here, when the tenant is created.

    Or another way of asking this is, why monolith app can seed the identity data with IDataSeeder and Identity MicroService can not with the same method? (so we need to use IIdentityDataSeeder explicitly)

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    I will forward this to our colleague.

  • User Avatar
    0
    cangunaydin created

    ok thank you @maliming

  • User Avatar
    0
    gterdem created
    Senior .NET Developer

    Hello cangunaydin,

    Basically, the IDataSeeder (https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs) finds all the related IDataSeedContributors in the DI container and runs the SeedAsync method.

    Some of the modules need some initial data in order to operate. Hence, they have their own DataSeedContributor, like IdentityDataSeedContributor or PermissionDataSeedContributor. Or you may have your own business related DataSeedContributor. All of these DataSeedContributors are added to DI and seeded via IDataSeeder. Notice that all of them are located under the Domain layer of the layered architectured module (or the application).

    In the monolith applications, IDataSeeder seeds the modules' DataSeedContributors because they are directly or indirectly referenced to the Domain of that module. That means they are already registered to the Dependency Injection Container.

    However in a microservice architecture, the modules are seperated into different microservices. All the microservices doesn't have references to all the modules. That's why you need to create different DataSeeders (like the IdentityDataSeeder in your example) to handle the seeding manually.

  • User Avatar
    0
    cangunaydin created

    Hello @gterdem, That's exactly what i think, and that's why i raised the question,

    If we continue from microservice example, for ex, in identityservice (Microservice) you have reference to identiy module, you indirectly referencing idataseedcontributor of the identity module. So why not call _dataseeder.Seed() method directly instead explicit calls to different dataseed service? I think you want to seed the data of the related microservice isn't it (which includes related modules)?

    For ex, IdentityService (in Microservice Template) includes (Volo.Abp.Identity.Pro.Domain and Volo.Abp.OpenIddict.Pro.Domain) which also includes related DataSeedContributors (for ex, IdentitySeedContributor) coming from those modules. Am i missing sth over here?

    here is the second part of my question

    Let's assume that i create one microservice containing all abp modules,(which was my monolith app). Let's name this MainService. Then created extra microservice. Let's name it ExtraService. In this case if i call IDataSeeder.Seed() method when new tenant is created according to your explanation everything should work fine. And MainService should create admin user and permissions. But i am seeing that permissions are not created. What can be the reason for that?

  • User Avatar
    0
    gterdem created
    Senior .NET Developer

    First of all IdentityDataSeedContributor is basically the same with the application template. The idea is as you can see, to override the default AdminEmail and AdminPassword.

    Second, Permissions are located under the Application.Contracts layer and the PermissionDefinitionProvider registers the permissions. Which means you need to find the permissions first to seed them.

    In the microservice template, this is a sample of how the permissions are seeded in the AdministrationServiceDataSeeder:

    public async Task SeedAsync(Guid? tenantId = null)
        {
            using (_currentTenant.Change(tenantId))
            {
                using (var uow = _unitOfWorkManager.Begin(requiresNew: true, isTransactional: true))
                {
                    var multiTenancySide = tenantId == null
                        ? MultiTenancySides.Host
                        : MultiTenancySides.Tenant;
    
                    var permissionNames = (await _permissionDefinitionManager
                        .GetPermissionsAsync())
                        .Where(p => p.MultiTenancySide.HasFlag(multiTenancySide))
                        .Where(p => !p.Providers.Any() || p.Providers.Contains(RolePermissionValueProvider.ProviderName))
                        .Select(p => p.Name)
                        .ToArray();
                    
                    _logger.LogInformation($"Seeding admin permissions.");
                    await _permissionDataSeeder.SeedAsync(
                        RolePermissionValueProvider.ProviderName,
                        "admin",
                        permissionNames,
                        tenantId
                    );
                    
                    _logger.LogInformation($"Seeding language data.");
                    await _languageManagementDataSeeder.SeedAsync();
    
                    await uow.CompleteAsync();
                }
            }
        }
    

    Why? Because it is using dynamic permission store which means each microservice is writing their own permissions to the AdministrationService database directly and the dataseeder is granting these permissions. Otherwise, AdministrationService will need to reference to all the microservices' Application.Contracts layers (which it was, before we implemented the dynamic permission store).

    See PermissionDataSeedContributor and PermissionDataSeeder for more details.

  • User Avatar
    0
    cangunaydin created

    Hello @gterdem, Thank you for the answer, but i think we are talking different things. I will try to explain what i am thinking step by step, hope i can manage that. I will talk about AdministrationService inside microservice template and how do I think about it.

    • PermissionManagement Module is part of administration service
    • So it includes PermissionDataSeedContributor that you have sent the link in the previous message.
    • When application started it registers the PermissionDataSeedContributor to the dependency injection system.
    • When you compare AdministrationServiceDataSeeder (omitting language management for now) and PermissionDataSeedContributor they are exactly doing same thing (correct me if i am wrong over here or i miss sth)

    PermissionDataSeedContributor

    
      var multiTenancySide = CurrentTenant.GetMultiTenancySide();
            var permissionNames = (await PermissionDefinitionManager.GetPermissionsAsync())
                .Where(p => p.MultiTenancySide.HasFlag(multiTenancySide))
                .Where(p => !p.Providers.Any() || p.Providers.Contains(RolePermissionValueProvider.ProviderName))
                .Select(p => p.Name)
                .ToArray();
    
            await PermissionDataSeeder.SeedAsync(
                RolePermissionValueProvider.ProviderName,
                "admin",
                permissionNames,
                context?.TenantId
            );
    
    

    AdministrationServiceDataSeeder

    var multiTenancySide = tenantId == null
        ? MultiTenancySides.Host
        : MultiTenancySides.Tenant;
    
    var permissionNames = (await _permissionDefinitionManager
        .GetPermissionsAsync())
        .Where(p => p.MultiTenancySide.HasFlag(multiTenancySide))
        .Where(p => !p.Providers.Any() || p.Providers.Contains(RolePermissionValueProvider.ProviderName))
        .Select(p => p.Name)
        .ToArray();
        
     _logger.LogInformation($"Seeding admin permissions.");
     await _permissionDataSeeder.SeedAsync(
         RolePermissionValueProvider.ProviderName,
         "admin",
         permissionNames,
         tenantId
     );
    
    • So as a conclusion, if i inject IDataSeeder to AdministrationServiceDataSeeder and call _dataSeeder.SeedAsync(), i am expecting the _dataSeeder.SeedAsync() should trigger PermissionDataSeedContributor, and seeding the data.

    what do i miss over here? can you point out? look at the image below, why this code won't work?


    Since i am curious about the question above, I do not use microservice template, i have a different setup. In my setup all abp modules are in one microservice, So i don't have any separated abp modules in different microservices, I am expecting data seeding to seed default static permissions but IDataSeeder not seeding the permission data when i create new tenant. That's why i raised the question at the first place. But if you can answer the above i suppose it would help with my problem.

  • User Avatar
    0
    gterdem created
    Senior .NET Developer

    I think I see your point. The reason can be the PermissionDefinitionManager not able to find the permissions in the database yet because it would be running very first in the module initializations.

    Can you make sure that the tenant permissions exist in the database when you run the dataseeder as you shared in the screenshot?

  • User Avatar
    0
    cangunaydin created

    Hello again, i don't think it is related with PermissionDefinitionManager. I did some tests. Actually Permissions are seeded in the db. But i am getting error on the ui side when i try to login here is the video for that. What i did is just to change dataseeding as i mentioned before.

    https://drive.google.com/file/d/1cXbxgi6WZF1_m7c9d8iDbqd49lpCU1C2/view?usp=sharing

    here is the code that i have changed, when the new tenant has been created it triggers.

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using ApproveIt.Shared.Hosting.Microservices.DbMigrations;
    using Doohlink.EntityFrameworkCore;
    using Microsoft.Extensions.Logging;
    using Volo.Abp.Data;
    using Volo.Abp.EventBus.Distributed;
    using Volo.Abp.Identity;
    using Volo.Abp.MultiTenancy;
    using Volo.Abp.Uow;
    using Volo.Saas.Tenants;
    
    namespace Doohlink.DbMigrations;
    
    public class AdzupDatabaseMigrationEventHandler
        : DatabaseMigrationEventHandlerBase<DoohlinkDbContext>,
            IDistributedEventHandler<TenantCreatedEto>,
            IDistributedEventHandler<TenantConnectionStringUpdatedEto>,
            IDistributedEventHandler<ApplyDatabaseMigrationsEto>
    {
        private readonly IdentityServiceDataSeeder _identityServiceDataSeeder;
        private readonly AdministrationServiceDataSeeder _administrationServiceDataSeeder;
        private readonly IDataSeeder _dataSeeder;
    
        public AdzupDatabaseMigrationEventHandler(
            ILoggerFactory loggerFactory,
            ICurrentTenant currentTenant,
            IUnitOfWorkManager unitOfWorkManager,
            ITenantStore tenantStore,
            ITenantRepository tenantRepository,
            IDistributedEventBus distributedEventBus,
            IdentityServiceDataSeeder identityServiceDataSeeder,
            AdministrationServiceDataSeeder administrationServiceDataSeeder,
            IDataSeeder dataSeeder) : base(
            loggerFactory,
            currentTenant,
            unitOfWorkManager,
            tenantStore,
            tenantRepository,
            distributedEventBus,
            DoohlinkDbProperties.ConnectionStringName)
        {
            _identityServiceDataSeeder = identityServiceDataSeeder;
            _administrationServiceDataSeeder = administrationServiceDataSeeder;
            _dataSeeder = dataSeeder;
        }
    
        public async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData)
        {
            if (eventData.DatabaseName != DatabaseName)
            {
                return;
            }
    
            try
            {
                var schemaMigrated = await MigrateDatabaseSchemaAsync(eventData.TenantId);
                await _identityServiceDataSeeder.SeedAsync(
                    tenantId: eventData.TenantId,
                    adminEmail: DoohlinkConsts.AdminEmailDefaultValue,
                    adminPassword: DoohlinkConsts.AdminPasswordDefaultValue
                );
                await _administrationServiceDataSeeder.SeedAsync(eventData.TenantId);
    
                if (eventData.TenantId == null && schemaMigrated)
                {
                    /* Migrate tenant databases after host migration */
                    await QueueTenantMigrationsAsync();
                }
            }
            catch (Exception ex)
            {
                await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex);
            }
        }
    
        public async Task HandleEventAsync(TenantCreatedEto eventData)
        {
            try
            {
                await MigrateDatabaseSchemaAsync(eventData.Id);
    
                await _dataSeeder.SeedAsync(
                    new DataSeedContext(eventData.Id)
                        .WithProperty(IdentityDataSeedContributor.AdminEmailPropertyName,
                            DoohlinkConsts.AdminEmailDefaultValue)
                        .WithProperty(IdentityDataSeedContributor.AdminPasswordPropertyName,
                            DoohlinkConsts.AdminPasswordDefaultValue)
                );
                // await _identityServiceDataSeeder.SeedAsync(
                //     tenantId: eventData.Id,
                //     adminEmail: eventData.Properties.GetOrDefault(IdentityDataSeedContributor.AdminEmailPropertyName) ??
                //                 DoohlinkConsts.AdminEmailDefaultValue,
                //     adminPassword:
                //     eventData.Properties.GetOrDefault(IdentityDataSeedContributor.AdminPasswordPropertyName) ??
                //     DoohlinkConsts.AdminPasswordDefaultValue
                // );
                // await _administrationServiceDataSeeder.SeedAsync(eventData.Id);
            }
            catch (Exception ex)
            {
                await HandleErrorTenantCreatedAsync(eventData, ex);
            }
        }
    
        public async Task HandleEventAsync(TenantConnectionStringUpdatedEto eventData)
        {
            if (eventData.ConnectionStringName != DatabaseName &&
                eventData.ConnectionStringName != ConnectionStrings.DefaultConnectionStringName ||
                eventData.NewValue.IsNullOrWhiteSpace())
            {
                return;
            }
    
            try
            {
                await MigrateDatabaseSchemaAsync(eventData.Id);
                await _identityServiceDataSeeder.SeedAsync(
                    tenantId: eventData.Id,
                    adminEmail: DoohlinkConsts.AdminEmailDefaultValue,
                    adminPassword: DoohlinkConsts.AdminPasswordDefaultValue
                );
                await _administrationServiceDataSeeder.SeedAsync(eventData.Id);
                /* You may want to move your data from the old database to the new database!
                 * It is up to you. If you don't make it, new database will be empty
                 * (and tenant's admin password is reset to IdentityServiceDbProperties.DefaultAdminPassword). */
            }
            catch (Exception ex)
            {
                await HandleErrorTenantConnectionStringUpdatedAsync(eventData, ex);
            }
        }
    }
    
    

    if i uncomment the lines that is commented(if i revert it like in microservice template), it works fine. What can be the reason i wonder? and i can see the permissions that is seeded in db for newly created tenant. (for idataseeder)

  • User Avatar
    0
    cangunaydin created

    I am also having some problems with localizations. I have 2 hosts that is running on my cluster. Let's calll them "Main Host" and "Side Host". Localizations are stored on Main Db. If I start the servers first time all the localizations are working fine. Then after some time if i restart the side server, all the "side" localizations are gone from UI. To fix that i need to flush the redis. Then everything is fixed again. What can be the reason for it? I removed DynamicLocalizationResourceContributor from both hosts. So i was suspicious about that, but even if revert it and try it again. It doesn't work. On application start if redis cache is empty, it gets it from db and hold it in the server memory i guess. The problem is related with redis i believe? and if i remove DynamicLocalizationResourceContributor does it mean it longer use Redis? or it doesn't write to redis or it doesn't read or write to redis?

  • User Avatar
    0
    ahmetfarukulu created

    if i uncomment the lines that is commented(if i revert it like in microservice template), it works fine. What can be the reason i wonder? and i can see the permissions that is seeded in db for newly created tenant. (for idataseeder)

    You can use the IDataSeeder just like monolith application templates if you want. However, we explicitly seed data for each microservice because a race condition could occur during the seeding process. For example, every microservice has a dependency on the Permission Entity Framework package. When it tries to retrieve a list of existing permissions in PermissionDataSeeder, two or more microservices execute the same point and insert the same permissions. IDataSeeder collects all contributors, and we can't limit the contributor types easily. That's why creating a custom seeding for each microservice is a more suitable solution.

    I created an empty microservice project and changed the data seeder just like you did. When I create the new tenant, there isn't any problem; everything works as expected. Can you share the logs when you get the exception?

    I removed DynamicLocalizationResourceContributor from both hosts. So i was suspicious about that, but even if revert it and try it again. It doesn't work. On application start if redis cache is empty, it gets it from db and hold it in the server memory i guess. The problem is related with redis i believe? and if i remove DynamicLocalizationResourceContributor does it mean it longer use Redis? or it doesn't write to redis or it doesn't read or write to redis?

    When the application starts, it tries to save existing localization files to the AbpLocalizationTexts table and caches these files in Redis. So, if you run both applications and clear the cache afterward, you can run one of your applications, and there shouldn't be any problem; all localizations are already inserted into the database, and it caches all localizations as expected. Make sure both application has Language Managemet Entity Framework dependency.

  • User Avatar
    0
    cangunaydin created

    Hello. Thank you for the feedback. I will try your suggestion.

    I created an empty microservice project and changed the data seeder just like you did. When I create the new tenant, there isn't any problem; everything works as expected. Can you share the logs when you get the exception?

    When i try with idataseeder, it also seems working at first look, but when you try to login to angular app with the admin user of the tenant, it is redirecting to error page.No errors on the server side. How can i find out what is going wrong on the angular side? my intuition is user doesn't have any permissions so it redirects you to error page. But i will do more thorough tests, and get back to you.

    My Project was a monolith project. Since it is modular now i am trying to change one of the modules to microservice. Do you have any project that i can look into? or a guide how to convert your module to microservice? What should be the dependencies for the host project of the module. What should be the dependencies for domain and infrastructure layer?

  • User Avatar
    0
    ahmetfarukulu created

    When i try with idataseeder, it also seems working at first look, but when you try to login to angular app with the admin user of the tenant, it is redirecting to error page.No errors on the server side. How can i find out what is going wrong on the angular side? my intuition is user doesn't have any permissions so it redirects you to error page. But i will do more thorough tests, and get back to you.

    If the user doesn't have any permission, then the AbpPermissionGrants table shouldn't have any record for the created tenant admin role. I've created an Angular microservice test application, and it's still working as expected. You can open DevTools (Right-click and inspect) and see the network tab to observe what's happening on the Angular side.

    My Project was a monolith project. Since it is modular now i am trying to change one of the modules to microservice. Do you have any project that i can look into? or a guide how to convert your module to microservice? What should be the dependencies for the host project of the module. What should be the dependencies for domain and infrastructure layer?

    There isn't any guide however you can inspect the microservice template.

    • First you can create a shared project layer for host(microservice) applications. There is folder named as shared in microservice template.
    • You can create service folder to the root and create a subfolder for each microservices.
    • Afterwards you can create an empty asp.net core application
      • Give the related dependencies such as shared projects and module that you wanna host. You can inspect the microservice/services. For module dependency Application, HttpApi, EntityFrameworkCore or MongoDB references should enough.
      • Create a module class
      • Create a DbMigrations.
  • User Avatar
    0
    cangunaydin created

    Hello again. Most of the things you have mentioned over here i did. But still having an error.

    when i try to login with the new created tenant, it seems like it logs in but then angular page is redirecting to the error page. There is no error on console either. Also no error on network segment. And no error on the logs. In what conditions angular app is redirecting the user to the error page? can i intercept or debug that part in angular app?

    this is the code that i use when new tenant is created.

    
     public async Task HandleEventAsync(TenantCreatedEto eventData)
        {
            try
            {
                await MigrateDatabaseSchemaAsync(eventData.Id);
    
                // await _identityServiceDataSeeder.SeedAsync(
                //     tenantId: eventData.Id,
                //     adminEmail: eventData.Properties.GetOrDefault(IdentityDataSeedContributor.AdminEmailPropertyName) ??
                //                 DoohlinkConsts.AdminEmailDefaultValue,
                //     adminPassword:
                //     eventData.Properties.GetOrDefault(IdentityDataSeedContributor.AdminPasswordPropertyName) ??
                //     DoohlinkConsts.AdminPasswordDefaultValue
                // );
                // await _administrationServiceDataSeeder.SeedAsync(eventData.Id);
                using (var uow = _unitOfWorkManager.Begin(requiresNew: true, isTransactional: true))
                {
                    await _dataSeeder.SeedAsync(
                        new DataSeedContext(eventData.Id)
                            .WithProperty(IdentityDataSeedContributor.AdminEmailPropertyName,
                                DoohlinkConsts.AdminEmailDefaultValue)
                            .WithProperty(IdentityDataSeedContributor.AdminPasswordPropertyName,
                                DoohlinkConsts.AdminPasswordDefaultValue)
                    );
    
                    await uow.CompleteAsync();
                }
    
                await _dataSeeder.SeedAsync();
            }
            catch (Exception ex)
            {
                await HandleErrorTenantCreatedAsync(eventData, ex);
            }
        }
    
    

    it creates new tenant but angular app is redirecting me to error page when i tried to login as admin.

    AbpPermissionGrants table have the records for the tenant. Can you tell me the conditions when angular app redirection to the error page is triggered. or how can i intercept or override it?

  • User Avatar
    0
    cangunaydin created

    And one more thing maybe it can help. I have added custom error handler to the angular app. the error i am getting is 403. But this doesn't come from http request. Dont know where it comes from.

    it is not an instance of http request as you can see.

  • User Avatar
    0
    cangunaydin created

    and another question about localization.

    As I mentioned earlier I have two hosting project. One is "Main" and the other is "ApproveIt" So when the angular request the localization from AbpApplicationLocalizationAppService. Sometimes it creates resource name: ApproveIt and sometimes it does not. Dont know the reason though. Because of that Localizations coming from ApproveIt is not translated in angular app.

    So the question is How Abp is creating the resource if it is another microservice project? As i see it, Main project not including ApproveIt.Domain.Shared module. Should it be included or not? How does Abp fix the localization resources for different microservices? When i check the microservice project it is not also included. Is there any configuration needs to be done for it?

    I have seen RemoteExternalLocalizationResource. But don't know how it works, if you can also explain that it would be helpful.

    it is kind of interesting cause the localization values are in db.

    Why it doesn't get the resource from the main app i wonder?

  • User Avatar
    0
    ahmetfarukulu created

    And one more thing maybe it can help. I have added custom error handler to the angular app. the error i am getting is 403. But this doesn't come from http request. Dont know where it comes from.

    it is not an instance of http request as you can see.

    I think the problem is not related to the data seeder; it's related to impersonation. You can follow the documentation steps. When you try to log in without impersonation, you can. If you want to login with impersonation basically, you need to set impersonation tenant permission on the authentication server configure service method.

            Configure<AbpAccountOptions>(options =>
            {
                options.TenantAdminUserName = "admin";
                options.ImpersonationTenantPermission = SaasHostPermissions.Tenants.Impersonation;
                options.ImpersonationUserPermission = IdentityPermissions.Users.Impersonation;
            });
    
  • User Avatar
    0
    ahmetfarukulu created

    Why it doesn't get the resource from the main app i wonder?

    Angular application uses the Application Localization endpoint, and if host applications have a dependency on language management, they can retrieve external resources from the database. However, when host applications start, they try to insert their localization resources into the database, and if an application takes the distributed lock, other applications have to wait. That's why the localization insertion process takes time for all applications, and afterwards, you need to wait for cache invalidation, or you can simply remove the cache to get the latest localization resources from the database.

  • User Avatar
    0
    cangunaydin created

    Hello @ahmetfarukulu, thank you for the replies, but the problem is not related with Impersonation, i can not login without impersonation either. Also When i dataseed it like microservice project, everything works fine. So i still think the problem is related with data seeding.

    For the localization, i believe it is sth related with redis cache invalidation as you mentioned.One thing bothering me though, if i restart the microservice every localization is gone, redis is still running and old cache values are still there. Why all the localizations are gone then? Is Abp deleting all the localizations in cache and recreating everything from scratch? Even if it is like that i wouldn't expect this behavior.

    And why the main module can not get the microservice resource name from the cache?

  • User Avatar
    0
    ahmetfarukulu created

    thank you for the replies, but the problem is not related with Impersonation, i can not login without impersonation either. Also When i dataseed it like microservice project, everything works fine. So i still think the problem is related with data seeding.

    Can you select the AbpUsers table you should see the admin user with related TenantId information if not then this is the reason why you can't login. Probably when you use IDataSeeder it cannot find the IdentityDataSeedContributor because your host application doesn't take dependency to Identity.Domain layer.

    In this picture you select the AbpPermissionGrants table however even admin role created for related tenant doesn't mean admin user created. Also when you try to impersonate or directly login there should be some logs on Authentication Host.

    For the localization, i believe it is sth related with redis cache invalidation as you mentioned.One thing bothering me though, if i restart the microservice every localization is gone, redis is still running and old cache values are still there. Why all the localizations are gone then? Is Abp deleting all the localizations in cache and recreating everything from scratch? Even if it is like that i wouldn't expect this behavior.

    And why the main module can not get the microservice resource name from the cache?

    When application start, it check the localization resources by md5 result if changes occurs then it try to update inserted resource. If both application use different key prefix that would be a reason for main module cannot get the microservice localization files from the cache.

  • User Avatar
    0
    cangunaydin created

    Hello again, I created new tenant to check your theory. i can see the user admin for the tenant in db. So don't think it is because of that.

    i can also see inside angular app when it requests api/abp/application-configuration?includeLocalizationResources=false endpoint. you can check the picture.

    From Auth Server. The logs seems normal.

    When application start, it check the localization resources by md5 result if changes occurs then it try to update inserted resource. If both application use different key prefix that would be a reason for main module cannot get the microservice localization files from the cache.

    for this i can assure that keys are same. first pic you see below is from shared project. Each project is dependent to this module like it is in microservice template.

  • User Avatar
    0
    ahmetfarukulu created

    i can see the user admin for the tenant in db. So don't think it is because of that.

    If you can see the current user information from the application-configuration endpoint, authentication is successful. The authentication server also hasn't any exceptions, so that means you can use authenticated API requests. The problem is caused on the Angular side. To make sure of this, could you send a HTTP request from the Swagger UI?

    Each project is dependent to this module like it is in microservice template.

    Redis configuration looks correct. Are you experiencing the same issue when using the ABP microservice template?

  • User Avatar
    0
    cangunaydin created

    If you can see the current user information from the application-configuration endpoint, authentication is successful. The authentication server also hasn't any exceptions, so that means you can use authenticated API requests. The problem is caused on the Angular side. To make sure of this, could you send a HTTP request from the Swagger UI?

    it didn't work from swagger, then i looked at the permissions that comes from application-configuration endpoint, then i see that it doesn't have Tenant.Dashboard permission, afterwards, When i was looking at it i realised, code that is posted over here also in my case, it didn't have CurrentTenant.Change(eventData.Id). So that's why it couldn't give the correct permissions to the newly created admin user :) What a waste of time :) Thanks anyway at least one thing has been fixed.

    for the localization it is very difficult to produce error each time. when i invalidate the redis cache everything works fine. So most of the time it works correct. Sometimes By restarting the app or running the dbmigrator is making the microservice resource disappear i couldn't find the real cause what makes it not getting the microservice resource. So i will let it go for now until i am sure how it behaves, it is annoying though. I am closing this ticket since it is almost one month since it is open. Thank you for the help.

  • User Avatar
    0
    ahmetfarukulu created

    it didn't work from swagger, then i looked at the permissions that comes from application-configuration endpoint, then i see that it doesn't have Tenant.Dashboard permission, afterwards, When i was looking at it i realised, code that is posted over here also in my case, it didn't have CurrentTenant.Change(eventData.Id). So that's why it couldn't give the correct permissions to the newly created admin user :)

    Strange, because when you send the current tenant id with eventData.Id it should work as expected since PermissionDataSeeder already change the current tenant by eventData.Id. It's same for IdentityDataSeeder too. Also in my microservice example i didn't change the current tenant when execute the IDataSeeder.SeedAsync method.

    Anyway, glad to see the problem fixed. Probably the problem is related to when you create the tenant; your tenant application didn't insert the related permissions into the AbpPermissions table.

Made with ❤️ on ABP v9.1.0-preview. Updated on November 20, 2024, 13:06