autofac / Autofac

An addictive .NET IoC container
https://autofac.org
MIT License
4.49k stars 836 forks source link

MultiTenant discovery asp.net core 3.1 #1101

Closed simo-92 closed 4 years ago

simo-92 commented 4 years ago

Hi, I already searched on StackOverflow for a similar problem, but i have not found anything. I'm building a multitenant asp.net core 3.1 app with several database (one for each tenant and one master database). My tenant identification strategy involve a db call to the master database. As written in the documentation, the identification strategy should not have calls to the database since it is called at each dependency resolution. Then i used another solution for tenant identification (Finbuckle.MultiTenant). With Finbukle when a request arrives his identification strategy is called, i put the db call in his identification strategy (for optimization i can cache the result) and a tenantInfo object is set in the HttpContext. Then In the AutoFac identification strategy i try to read the object setted by FinBuckle but is not possibile because the Autofac identification Strategy is called before the FinBuckle ones.
My Program.cs is:

 public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacMultitenantServiceProviderFactory(Startup.ConfigureMultitenantContainer))
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

Startup.cs:

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMultiTenant().WithStrategy<TestStategy>(ServiceLifetime.Singleton).WithStore<CustomTestStore>(ServiceLifetime.Singleton); //enable the multitenant support from finbukle

            services.AddControllers();

            services.AddAutofacMultitenantRequestServices();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {

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

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseMultiTenant() //finbukle

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

        public void ConfigureContainer(ContainerBuilder builder)
        {
             builder.RegisterType<TestDiA>().As<ITestDI>().InstancePerTenant();
        }

        public static MultitenantContainer ConfigureMultitenantContainer(IContainer container)
        {
            // This is the MULTITENANT PART. Set up your tenant-specific stuff here.
            var strategy = new MyAutofacTenantIdentificationStrategy(container.Resolve<IHttpContextAccessor>());
            var mtc = new MultitenantContainer(strategy, container);
            return mtc;
        }
    }

Autofac tenant resolution strategy

 public class MyAutofacTenantIdentificationStrategy : ITenantIdentificationStrategy
    {
        private readonly IHttpContextAccessor httpContextAccessor;
        public MyAutofacTenantIdentificationStrategy(
          IHttpContextAccessor httpContextAccessor
        )
        {
            this.httpContextAccessor = httpContextAccessor;
        }
        public bool TryIdentifyTenant(out object tenantId)
        {
            tenantId = null;
            var context = httpContextAccessor.HttpContext;
            if (context == null)
                return false;

            var identifier = context.getTenatInfo()?.Identifier ?? null; //getTenantInfo is a method that extract the tenant info object setted by finbukle
            tenantId = identifier;
            return (tenantId != null || tenantId == (object)"");
        }
    }

I'm really new in this area, so I apologize if I ask a trivial question. There is a way of solving the problem with this approach? Thank's

tillig commented 4 years ago

You may have searched Stack Overflow but you didn't ask the question there. Please ask "How do I...?" questions on Stack Overflow and tag them autofac. If you find an issue or have an enhancement request, please file a new issue.