1- We use multitenancy with db per tenant approach. 2- We store all tenants and connection strings inside host database naturally 3- We have a seperate application which created with suite and this application works with our platform 4- We gave this application inside editions , for example if tenant has standard edition than we don't show anything about this application but if edition is premium tenant and users can see this application and pages 5- This application has its own ef core context and own entities , also has identity and abp spesific tables , too 6 - When we login, we login with tenant and I think when we login with tenant , the abp backend changes our connection string depends on logged in tenant connection string ? 7- After login with tenant if this application spesific entities don't implement IMultiTenant interface than we got error because of wrong connection string but the interesting thing system knows my current tenant Id but the connection string is not correct . 8- When we add IMultitTenant to these entities it resolves correctly. 9- But all abp tables don't have TenantId right ? However they could work correctly ? 10 - So why we need to add IMultiTenant interface to our spesific entities which is stored in tenant depended database already ? When we login it should be getting correct connection string , right ?
I hope it is clear. Thank you.
Hello,
I think there are misunderstandings , could we arrange a desktop sharing session and I can show you from my computer the issue , It will be more understandable I think , Is it ok ?
Thank you.
hello, So then this is a bug in FileManagement Module , right ? Will you fix it in next versions ? Because we don't want to add module directly into our project because of maintenance issues depends on version changing. I'll try anyway your answer with overriding these files in my project.
Thank you.
Hello, I sent a sample project .
Thank you.
Hello again , we found the solution I want to share : Actually there is already a warning which we ignored "Inherit your controllers from this class" : We basically write methods into this base controller so we couldn't see in swagger.
/* **Inherit your controllers from this class.**
*/
public abstract class EasyCrmController : AbpController
{
protected EasyCrmController()
{
LocalizationResource = typeof(EasyCrmResource);
}
}
But when inherit from this controller class like below and create another controller, issue resolved automatically.
[Route("api/test")]
public class TestController : EasyCrmController
{
[HttpGet]
[Route("")]
public Task<List<TestModel>> GetAsync()
{
return Task.FromResult(new List<TestModel>
{
new TestModel {Name = "John", BirthDate = new DateTime(1942, 11, 18)},
new TestModel {Name = "Adams", BirthDate = new DateTime(1997, 05, 24)}
});
}
}
Solution is ok but why do we need to inherit from base controller to see methods in swagger ? Is is about dependency injection in HttpApiHost application or something else ? Could you explain the reason ?
Thank you .
Hello, In my domain module I add CustomIdentityDataSeeder and CustomIdentityDataSeedContributor classes like below. In the note section we described the situation. Because of dependency injection issues maybe this class hits 2 times . At first time admin email comes with admin@abp.io email second time I could use my custom email . But how does it admin@abp.io default email hit at the first time. How could I prevent it because I think I've already overriden these classes . I don't want to check like if blocks.
Thank you
CustomIdentityDataSeedContributor
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.Identity;
namespace Custom.XXX.Identity
{
public class CustomIdentityDataSeedContributor : IdentityDataSeedContributor
{
protected CustomIdentityDataSeeder CustomIdentityDataSeeder { get; }
public CustomIdentityDataSeedContributor(CustomIdentityDataSeeder identityDataSeeder)
: base(identityDataSeeder)
{
CustomIdentityDataSeeder = identityDataSeeder;
}
public override Task SeedAsync(DataSeedContext context)
{
return CustomIdentityDataSeeder.SeedAsync(
"custom@Custom.com",
"Pass1234+",
context?.TenantId
);
}
}
}
CustomIdentityDataSeeder
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Guids;
using Volo.Abp.Identity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;
using IdentityRole = Volo.Abp.Identity.IdentityRole;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
namespace Custom.XXX.Identity
{
public class CustomIdentityDataSeeder : IdentityDataSeeder
{
public CustomIdentityDataSeeder(IGuidGenerator guidGenerator,
IIdentityRoleRepository roleRepository,
IIdentityUserRepository userRepository,
ILookupNormalizer lookupNormalizer,
IdentityUserManager userManager,
IdentityRoleManager roleManager,
ICurrentTenant currentTenant,
IOptions<IdentityOptions> identityOptions)
: base(guidGenerator, roleRepository, userRepository, lookupNormalizer, userManager, roleManager, currentTenant, identityOptions)
{
}
[UnitOfWork]
public override async Task<IdentityDataSeedResult> SeedAsync(string adminEmail, string adminPassword, Guid? tenantId = null)
{
var result = new IdentityDataSeedResult();
Check.NotNullOrWhiteSpace(adminEmail, nameof(adminEmail));
Check.NotNullOrWhiteSpace(adminPassword, nameof(adminPassword));
string adminUserName = "custom";
** //NOTE we dont want to check like below for abp.io user
if (adminEmail == "admin@abp.io")
{
return result;
}**
if (tenantId!= Guid.Empty && tenantId != null)
{
adminUserName = "custom2";
if(adminEmail == "custom@Custom.com")
{
adminEmail = "custom2@Custom.com";
}
}
using (CurrentTenant.Change(tenantId))
{
//"admin" user
var adminUser = await UserRepository.FindByNormalizedUserNameAsync(
LookupNormalizer.NormalizeName(adminUserName)
);
if (adminUser != null)
{
return result;
}
adminUser = new IdentityUser(
GuidGenerator.Create(),
adminUserName,
adminEmail,
tenantId
)
{
Name = adminUserName
};
(await UserManager.CreateAsync(adminUser, adminPassword)).CheckErrors();
result.CreatedAdminUser = true;
//"admin" role
const string adminRoleName = "admin";
var adminRole = await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName(adminRoleName));
if (adminRole == null)
{
adminRole = new IdentityRole(
GuidGenerator.Create(),
adminRoleName,
tenantId
)
{
IsStatic = true,
IsPublic = true
};
(await RoleManager.CreateAsync(adminRole)).CheckErrors();
result.CreatedAdminRole = true;
}
(await UserManager.AddToRoleAsync(adminUser, adminRoleName)).CheckErrors();
return result;
}
}
}
}