Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

58 Comments

  1. Great job,
    Thanks for sharing with the community.
    I wanna know what should we do if we want to place the tenant name as a subdomain in endpoints?
    Thank you.

  2. hello excellent work from Multitenancy, but how could I implement this in blazor wasm? Could you help me with this issue I want to do something like what you describe in your article but in blazor

  3. Thank you, a good overview (which I found most useful) and thorough walkthrough. Clarified some questions for me.

  4. Fantastic! Very well written; very simple and straightforward solution to the multitenancy problem. Thanks for sharing. I am eagerly following fullstackhero and BlazorHero. Keep up the good work.

  5. Nice article. Want to add that in a project I recently worked with, there was another way of detecting tenant — from the refer URL of the request. Because every tenant had a different frontend, it worked fine.

  6. Very nice article. I have only one question. You registered tenant service as transient, but probably scoped would be good also, and maybe better for performance, in case if one request will use many middlewares and services where such service would be needed. Am I right or I missed something?

  7. Great article, very simplified explanation of multitenancy in ASP.NET Core.

    Thanks and keep doing a great work!

  8. Hi, Thanks for sharing and well explained!
    I have a question, if tenant details need to be crossed checked with the database, how we can go about it?
    The main issue I have is if I inject a DbContext into TenantService then I cannot access TeanatService from DbContext as it causes a cyclic injection.
    Thanks, much appreciated!

    1. In this article, My approach was to store tenant details within appsettings. For advanced cases, you would need to store the tenant data into the database, using a separate DbContext – TenantDbContext. I have a working model already implemented and tested. Please refer to https://github.com/fullstackhero/dotnet-webapi-boilerplate

      More specifically , this one https://github.com/fullstackhero/dotnet-webapi-boilerplate/blob/main/src/Infrastructure/Services/General/TenantManager.cs

      Regards

    1. You can use one database per tenant, which is already mentioned in this article. I am not sure of any use case where you need one user to use a single database. However you could still use this approach and just register one user per tenant.

  9. Fantastic work Mukesh. You make programming so worth it.
    I am looking forward to the fullstackhero project. It will be great for development.

    One quick question. Can I implement this tutorial in blazorhero?

    Regards,
    George

  10. Great article, but when I tried to create a new project by following your article, for some reason I cannot create migration. The error says:
    “Unable to create an object of type ‘ApplicationDbContext’. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728“.

    I tried to download your source code and try to add new migration as well and got same error. Any idea why is this happening and how to fix it?

      1. I ran into the same issue, for me what worked was this:
        Go to the next step where Kesh added in everything to the Startup.cs … do that, then the migration will work

    1. Did you use net6.0 with only Program.cs file instead of having Program.cs and Startup.cs as net5.0 in this tutorial?
      Just copy Program.cs and Startup.cs from this tutorial to your Multitenant.Api and try again.

  11. Pretty much as too the point and well written as one could possible ask for, on a really good topic.
    Fantastic articulation, thanks for writing!

  12. Great Job! This is something, that I was really glad to find out. Could you also advise, how to deal with multi-tenancy with async processing of emitted events to message-broker from multi-tenant system? Also, it is interesting if is it worth moving multi-tenancy configs into separate microservice if you have multiple microservices (even with different programming languages)?

    1. Hello Mukesh Murugan Congratulations for your post, its excellent.
      I need your help. Can you guid me as make the folloging:

      1.- How to get all products but without tenant name in headers? Imagine a catalog products the all tenants in a view.
      With the demo, i can get all products by tenant. If I don’t enter a tenant name in header, give me a error.

      2.- In this post, you use a values for default in appconfig, as: java, charlie.
      2.1.- I want register users (Tenants) and use them. How to you make?

      Sorry for my english, I’m learning 🙂

      Thanks for your post, and I have been learnign with your descriptions.
      I hope your soon answer.
      Regards, Nelson

  13. Hello Mukesh! This article looks perfect and promising. But I would like to ask if an application serves multiple database instance, then we are referring that to multi-tenancy, right? Am writing it according to the diagram you shared, one app with multi databases for each tenant. Just to clear it up.

  14. Hey,

    What an amazing article, thanks so much for sharing this. If you wanted to take this one step further by using sql RLS and set the connection context when a connection is opened

    Something like:

    SqlCommand cmd = conn.CreateCommand();
    cmd.CommandText = @”exec sp_set_session_context @key=N’CompanyID’, @value=@CompanyID”;
    cmd.Parameters.AddWithValue(“@CompanyID”, CompanyIDint);
    cmd.ExecuteNonQuery();

    Where and how would you do this given the implementation above? I’ve read that you have to use the DbConnectionInterceptor, but not 100% sure where this would have to be implemented.

    Thanks again for a great article.

  15. Hi Mukesh,
    Thank you for all your blogs, very helpful
    I’m following your steps using .Net6 API Template, after everything is in place, I try to do a Add-Migration and I get an error:

    “An error occurred while accessing the Microsoft.Extensions.Hosting services. Continuing without the application service provider. Error: Cannot access a disposed object.
    Object name: ‘ConfigurationManager’.
    Unable to create an object of type ‘ApplicationDbContext’. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

    I download this project from Github, and I change the TargetFramework to .Net6 and I can create the migration.
    Now when I use the .Net 6 template o Program.cs, I got the same error, no code has been changed, just the Program.cs
    This is what I add to your Project Program.cs, can you help me to find out what change? :

    using Core.Interfaces;
    using Core.Options;
    using Infrastructure.Extensions;
    using Infrastructure.Services;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;

    var builder = WebApplication.CreateBuilder(args);
    var config = builder.Configuration;
    // Add services to the container.

    builder.Services.AddHttpContextAccessor();
    builder.Services.AddControllers();
    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();

    builder.Services.AddTransient();
    builder.Services.AddTransient();

    builder.Services.Configure(config.GetSection(nameof(TenantSettings)));
    builder.Services.AddAndMigrateTenantDatabases(config);

    var app = builder.Build();

    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
    app.UseSwagger();
    app.UseSwaggerUI();
    }

    app.UseHttpsRedirection();

    app.UseAuthorization();

    app.MapControllers();

    app.Run();

  16. This is a very comprehensive architecture.
    What do you think if I implement a generic repository using this instead of each entity with its own interface?

  17. Great post, thanks for sharing.. I just ask myself, why we really do need that tenancy-id.. I mean, for each tenant you got an own connection-string (which makes sense) and then you store for each product the same tenant-id in the table? why do we need that? You would need that tenancy-id if you got multiple tenants share the same database, but isn’t this the reason why you want to create a database for each tenant? Am I wrong?

  18. Did you have any issues when it comes to seeding data for tenanted entities, especially when writing integration tests? I’m using IEntityTypeConfiguration for all my entities instead of OnModelCreating (and no migrations either), so when I seed test data, the entity modification code in DbContext.SaveChanges() kicks in and assigns the current tenant ID to the entity, overriding the value that I configured in my test data.

  19. Hello Mukesh
    Have you or anyone implemented the functionality to store the tenant data into the database over this project or over this same architecture? Any kind of help and support will be appreciated. Thanks a lot in advance.
    Br
    Aryan

      1. Thanks a lot, for your prompt response, Mukesh 🙂
        By the way, the project in this article and the full-stack hero web app-boilerplate are done with a similar architecture?
        I guess this article is done with N-Layer architecture and full-stack hero web app-boilerplate is done in clean architecture?
        Br
        Aryan

  20. Hi,
    This does not seem near to completion.
    Can you please tell us
    1. How would you create database on the fly when new organization signs up? (Not on application start)
    2. How do you determine tenant id on the fly (which database to check in case of dedicated DBs) on login ?
    3. How would handle database crash during migrating new changes while application is being used by any tenant because migration needs to be applied on every database available.

  21. Really good step by step doc

    Can you let me know how we could modify this code to create tenant with new db at runtime?
    Able to create connection string in appsettings.json under tenants, but how to call AddAndMigrateTenantDatabases from custom controller, that’s the problem

    Could you please help on this front?

  22. Thanks for sharing but when I tried to add “AppDataContextFactory”. It didn’t work. Kindly assist

    “public class AppDataContextFactory : IDesignTimeDbContextFactory
    {
    private readonly ITenantService _tenantService;

    public AppDataContextFactory(ITenantService tenantService)
    {
    _tenantService = tenantService;
    }

    public ApplicationDbContext CreateDbContext(string[] args)
    {
    var tenantConnectionString = _tenantService.GetConnectionString();

    var optionsBuilder = new DbContextOptionsBuilder();
    // optionsBuilder.UseSqlServer(tenantConnectionString);
    optionsBuilder.UseSqlServer(m => m.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName));

    return new ApplicationDbContext(optionsBuilder.Options, _tenantService);
    }”

  23. Hello Mukesh,
    I really enjoyed the project you wrote. There are ideas that will form the basis of the project I am working on. However, there is a part where I am stuck. I couldn’t find a solution to anyone I asked. Could you please examine it? I’m stuck and can’t move forward.
    https://github.com/msbeden/MultiTenantCore

    Thank you very much in advance. Good work.

  24. Great article! You’re right, there’s not many articles that cover advanced aspects of multitenancy. I will be giving your a repo a star!

  25. I build your sample into a prototype of my new API/Angular app. One of the two i have not right in my mind. I am using ASP Identity. So in my opinion the token need to be verified against the database. So my question is where can i see that the verification process takes place after selecting the right dbContext. Second; When i use a second dbcontext for selecting the tenant, how do i prevent the verification process use that dbcontext for verification the token.

  26. How to extend the Multi-Tenant to Worker service/Background service. The same service should run for each tenant and Db to be stored for respective DB.

  27. How do you implement the update the database using the previous migration?
    e.g. update-database 20210830190011_initial

  28. Hi Mukesh,
    I think you should add a disclaimer at the beginning of the article that this is for educational purposes.
    It’s a good example to understand how multitenancy works, but it’s not the solution you ended up using in Fullstackhero (fsh usesFinbuckle). It’s good to know upfront so users understand what they invest their time and effort into.