Activities of "MarekH"

Okay, let me explain our problem.

We have tiered application (multi-tenant) using PostgreSQL. Into this project, we have added our own API project which will be used as public API for other components. Here is the sln structure: As you can see, our API is called WebComHost. We have created (via abp suite) our custom entity called "Endpoint", we can add/edit/remove everything from UI as expected.

  1. Another application wants to call WebComHost API and update something in Endpoint table.
  2. This request contains TenantId to identify which tenant db should be updated.
  3. As first thing, we would like to switch to proper tenant DbContext using standard approach via _currentTenant.Change(tenantId) (suggested in #1219), here is code in controller method:
  4. When we call Test method, we are getting following error:
  5. An unhandled exception has occurred while executing the request.

System.InvalidOperationException: Unable to resolve service for type 'Volo.Abp.MultiTenancy.ICurrentTenant' while attempting to activate 'Expireon.WebComHost.Controllers.V1.EndpointController'. at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired) at lambda_method9(Closure , IServiceProvider , Object[] ) at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass4_0.&lt;CreateActivator>b__0(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<&gt;c__DisplayClass5_0.&lt;CreateControllerFactory&gt;g__CreateController|0(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()

Volo.Abp.MultiTenancy package is included in WebComHost project. Is it a correct approach how to access DbContext from different applicaiton?

Thanks

Hello @gterdem

sorry for not responding to your last message, but this project was mitigated from our side. I re-visited our source code and i have created new project with same parts:

*.HttpApi.Host (supplied by template) *.IdentityServer (supplied by template) *.Microservice (your additional project) (Web API)

As you mentioned we are using tiered appliaction. We added few entities into DbContext and they are nicely accessible from all default layers.

The issue comes when i want to access one of our entities from additional project (*.Microservice...). I cant really switch context based on tenantId (with _currentTenant.Change(randomTenantId)). Can we maybe schedule a quick call to show you the issue?

Thanks a lot!

Hi

this is an issue we have faced lately, when you use AppUser which is used to add new properties to IdentityUser throws exception in different modules. I suggest you to use IdentityUser instead of AppUser.

Hello

We have tried it with using IdentityUser insted of AppUser , But still we are not able to access any repoostories. As mentioned above we have a API Project Name : Microservice , We are trying to access database of tenant to perform CRUD Opration from the same project.

Issue: We are not able to switch or access any reporsitories in that Project

I have created a DEMO Project with the Microservice Project (In which we would like to access tenant database and perform CRUD oprations).

I am updating Link with using After tryng it with IdentityUser. https://drive.google.com/file/d/1nntKu7W6resMqoIY0bA8DGd00FwZnYu9/view

Thank you

We Tried to implement with PostGre Also Tried with creating new API Project and then gave refrence of existing Project as well as added required abp packages into it.

Also Added Module and depends on inside that new Project it gives us below error when starting debuging:

System.TypeLoadException: 'Could not load type 'Volo.Abp.Authorization.Permissions.IPermissionDefinitionManager' from assembly 'Volo.Abp.Authorization, Version=4.3.0.0, Culture=neutral, PublicKeyToken=null'.'

Sharing code of Module class here :

using FinalDestination.EntityFrameworkCore; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; using Volo.Abp; using FinalDestination.MultiTenancy; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Autofac; using Volo.Abp.Caching; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.Identity.AspNetCore; using Volo.Abp.Modularity; using Volo.Abp.Swashbuckle; using Volo.Abp.VirtualFileSystem; using Microsoft.OpenApi.Models; using Microsoft.Extensions.Configuration; using Microsoft.AspNetCore.Cors; using System.IO; using FinalDestination.MicroService.HealthChecks;

namespace FinalDestination.MicroService { [DependsOn( //typeof(FinalDestinationHttpApiModule), typeof(AbpAutofacModule), typeof(AbpCachingStackExchangeRedisModule), typeof(AbpAspNetCoreMvcUiMultiTenancyModule), typeof(AbpIdentityAspNetCoreModule), typeof(FinalDestinationApplicationModule), typeof(FinalDestinationEntityFrameworkCoreDbMigrationsModule), typeof(AbpSwashbuckleModule), typeof(AbpAspNetCoreSerilogModule) )] public class FinalDestinationMicroServiceModule : AbpModule { private const string DefaultCorsPolicyName = "Default"; public override void ConfigureServices(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); var hostingEnvironment = context.Services.GetHostingEnvironment();

        //ConfigureUrls(configuration);
        ConfigureConventionalControllers();
        ConfigureAuthentication(context, configuration);
        ConfigureSwagger(context, configuration);
        ConfigureCache(configuration);
        ConfigureVirtualFileSystem(context);
        //ConfigureRedis(context, configuration, hostingEnvironment);
        ConfigureCors(context, configuration);
        //ConfigureExternalProviders(context);
        ConfigureHealthChecks(context);
    }
    private void ConfigureHealthChecks(ServiceConfigurationContext context)
    {
        context.Services.AddFinalDestinationHealthChecks();
    }



    private void ConfigureCache(IConfiguration configuration)
    {
        Configure&lt;AbpDistributedCacheOptions&gt;(options =>
        {
            options.KeyPrefix = "FinalDestination:";
        });
    }

    private void ConfigureVirtualFileSystem(ServiceConfigurationContext context)
    {
        var hostingEnvironment = context.Services.GetHostingEnvironment();

        if (hostingEnvironment.IsDevelopment())
        {
            Configure&lt;AbpVirtualFileSystemOptions&gt;(options =>
            {
                options.FileSets.ReplaceEmbeddedByPhysical&lt;FinalDestinationDomainSharedModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}FinalDestination.Domain.Shared", Path.DirectorySeparatorChar)));
                options.FileSets.ReplaceEmbeddedByPhysical&lt;FinalDestinationDomainModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}FinalDestination.Domain", Path.DirectorySeparatorChar)));
                options.FileSets.ReplaceEmbeddedByPhysical&lt;FinalDestinationApplicationContractsModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}FinalDestination.Application.Contracts", Path.DirectorySeparatorChar)));
                options.FileSets.ReplaceEmbeddedByPhysical&lt;FinalDestinationApplicationModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}FinalDestination.Application", Path.DirectorySeparatorChar)));
                //options.FileSets.ReplaceEmbeddedByPhysical&lt;FinalDestinationHttpApiModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}FinalDestination.HttpApi", Path.DirectorySeparatorChar)));
            });
        }
    }

    private void ConfigureConventionalControllers()
    {
        Configure&lt;AbpAspNetCoreMvcOptions&gt;(options =>
        {
            options.ConventionalControllers.Create(typeof(FinalDestinationApplicationModule).Assembly);
        });
    }

    private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.Authority = configuration["AuthServer:Authority"];
                options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
                options.Audience = "FinalDestination";
            });
    }

    private static void ConfigureSwagger(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddAbpSwaggerGenWithOAuth(
            configuration["AuthServer:Authority"],
            new Dictionary&lt;string, string&gt;
            {
                {"FinalDestination", "FinalDestination MicroService API"}
            },
            options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo { Title = "FinalDestination MicroService API", Version = "v1" });
                options.DocInclusionPredicate((docName, description) => true);
                options.CustomSchemaIds(type => type.FullName);
            });
    }

    //private void ConfigureRedis(
    //    ServiceConfigurationContext context,
    //    IConfiguration configuration,
    //    IWebHostEnvironment hostingEnvironment)
    //{
    //    if (!hostingEnvironment.IsDevelopment())
    //    {
    //        var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
    //        context.Services
    //            .AddDataProtection()
    //            .PersistKeysToStackExchangeRedis(
    //            redis,
    //            "FinalDestination-Protection-Keys");
    //    }
    //}

    private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddCors(options =>
        {
            options.AddPolicy(DefaultCorsPolicyName, builder =>
            {
                builder
                    .WithOrigins(
                        configuration["App:CorsOrigins"]
                            .Split(",", StringSplitOptions.RemoveEmptyEntries)
                            .Select(o => o.RemovePostFix("/"))
                            .ToArray()
                    )
                    .WithAbpExposedHeaders()
                    .SetIsOriginAllowedToAllowWildcardSubdomains()
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
            });
        });
    }

  

    public override void OnApplicationInitialization(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();
        var env = context.GetEnvironment();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseAbpRequestLocalization();

        if (!env.IsDevelopment())
        {
            app.UseErrorPage();
        }

        app.UseCors(DefaultCorsPolicyName);

        app.UseStaticFiles();
        app.UseRouting();
        app.UseAuthentication();

        if (MultiTenancyConsts.IsEnabled)
        {
            app.UseMultiTenancy();
        }

        app.UseAuthorization();
        app.UseSwagger();
        app.UseAbpSwaggerUI(options =>
        {
            options.SwaggerEndpoint("/swagger/v1/swagger.json", "FinalDestination API");

            var configuration = context.GetConfiguration();
            options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
            options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]);
        });
        app.UseAuditing();
        app.UseAbpSerilogEnrichers();
        app.UseUnitOfWork();
        app.UseConfiguredEndpoints();
    }
}

}

I see that your Microservice project uses SQL your main project uses PostgreSQL. And both of them uses the same dbcontext. it'll not work this way.

We have used PostGre SQL in Microservice project and still we are not getting the data from tenant database. Can you please eleborate where it uses SQL ?

try

private readonly ICurrentTenant _currentTenant; 
 
 private async Task DoWorkAsync() 
        { 
 
            using (_currentTenant.Change(new Guid("xxxxxxxxx"))) 
            { 
                using (var uow = _unitOfWorkManager.Begin(requiresNew: true, isTransactional: false)) 
                { 
                    //............. 
                    await uow.CompleteAsync(); 
                } 
            } 
        } 

Hello Alper we have tried to use above method in the demo project. we are still not able to get the users list of the tenant which we have switched , we have 2 users for the tenant and we are getting count 0

  • ABP Framework version: v4.3
  • UI type: Angular
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): yes
  • Exception message and stack trace: Unable to access the action method which is used to switch tenant and get users list of that tenant
  • Steps to reproduce the issue: We have a Microservice project in our solution from which we are trying to connect the database of tenant by providing tenant Id to insert or update any data of particular tenant from the tenant database.
  • We created a controller inside that microservice project and trying to change the tenant using dbcontext but we are not able to call that method. after adding such reference of entityframeworkCore project
  • We have created a question related to that and we got that question credited back by team.
  • We are sharing Demo Project link and screen shot here in which are are trying to access the tenant database.
  • Demo Project Link : https://drive.google.com/file/d/1RZUKdUTNM7Az8t_IRr0i1oF_nVvVb17q/view?usp=sharing
Answer

Yes We have added DependsOn attribute in FDDemoMicroserviceHostModule. We are still not able to access the dbContext.

Answer

hi

Please check PostGreController in FD.Demo.MicroService.Host project. We are trying to access appuserRepository for specific tenant but without any luck.

You can use CurrentTenant.Change to switch host and tenant.

[ApiController] 
public class PostGreController : AbpController 
{ 
 
    private readonly IAppUsers _appuserRepository; 
    private readonly IDbContextProvider<DemoDbContext> _dbContextProvider; 
 
    public PostGreController(IAppUsers appuserRepository, IDbContextProvider<DemoDbContext> dbContextProvider) 
    { 
        _appuserRepository = appuserRepository; 
        _dbContextProvider = dbContextProvider; 
    } 
 
 
    [Route("/api/v1/test")] 
    [HttpGet] 
    [ProducesResponseType((int)HttpStatusCode.Accepted)] 
    public async Task<IActionResult> test() 
    { 
        using (CurrentTenant.Change(null)) 
        { 
            var abcInHostDatabase = await _appuserRepository.GetListAsync(); 
        } 
 
        var ten1 = new Guid("your tenant id to switch tenant"); 
        using (CurrentTenant.Change(ten1)) 
        { 
            var abcInTenantDatabase = await _appuserRepository.GetListAsync(); 
        } 
 
 
        var demoDbContext = await _dbContextProvider.GetDbContextAsync(); 
 
        return Ok(); 
    } 
} 

Our general issue is, how to access DemoDBContext from FD.Demo.Microservice.Host project.

Reference FD.Demo.EntityFrameworkCore.csproj in your FD.Demo.Microservice.Host project.

var demoDbContext = await _dbContextProvider.GetDbContextAsync();

Hello Maliming,

As per your reply, I tried giving reference of FD.Demo.EntityFrameworkCore.csproj to my FD.Demo.Microservice.Host project but I am still getting the same error. Can we please schedule a call?

Answer

it gives a 500 error.

Can you share the error logs?

Hello maliming,

I have downloaded a sample code from Abp.io and added a microservice project named FD.Demo.MicroService.Host to it. I have created PostGreController in V1 folder of controller folder inside FD.Demo.MicroService.Host project. Now that controller contains a method test(API) which calls IAppUserRepository method (GetListAsync for get the list of users) in FD.Demo.Domain project and returns the list of users. When executing Test API of PostGreController from FD.Demo.MicroService.Host, swagger is showing 500 error. I have attached sample project file which is given below.

Steps:- 1)download the below project 2)Execute the microservice Test api

Project Link:- deleted

Our Purpose is to Change Tenant using CurrentTenant.Change() in MicroService. We are not able to access the Repository in MicroService Layer.We have added the Reference of FD.Demo.Domain for accessing Repository of AppUser. We are not getting any compile time error however we are not able to access the Repository on MicroService API.

Can you please check above example and let me know how can I Access the reposity in MicroService Layer.

Showing 1 to 10 of 26 entries
Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11