Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
redleader
Aug 18, 2005

Engage according to operational parameters

NihilCredo posted:

i also think this is usually the cleanest option. no query filters, just a separate connection string per tenant.

the downside is that you have to be really drat sure you will never need to perform queries across multiple organisations

if you do need that, using one schema per tenant can be a decent compromise. you can specify the schema in the connection string, but still override it in the query if needed. at least if your db is mssql or postgres

another thing to be wary of with one-db-per-tenant (or indeed anything that varies the db connection string per tenant) is that ef core support is sketchy, iirc. you'll need to figure that bit out on your own

obviously not a concern if you're not using ef

Adbot
ADBOT LOVES YOU

ChocolatePancake
Feb 25, 2007
If you inject your ITenantProvider with your OnConfiguring method for entity framework, you can use a scoped database service no problem. I have used this approach several times, and it works well. I can probably get you some sample code tomorrow if you like.

Supersonic
Mar 28, 2008

You have used 43 of 300 characters allowed.
Tortured By Flan

ChocolatePancake posted:

If you inject your ITenantProvider with your OnConfiguring method for entity framework, you can use a scoped database service no problem. I have used this approach several times, and it works well. I can probably get you some sample code tomorrow if you like.

This would be appreciated! I've also been looking at Finbuckle Multitenant tonight which seems to be a potential solution as well.

ChocolatePancake
Feb 25, 2007
I've not used Finbuckle before, but it looks intriguing. This is what I do:

code:
//put your connection strings in your appSettings.json like this:
"ConnectionStrings": {
  "TenantADataModel": "data source=<rest of connection string here>;",
  "TenantBDataModel": "data source=<rest of connection string here>;"
},

 public partial class MyDbContext : DbContext
 {
     private readonly ITenantIdentifier tenantIdentifier;
     private readonly IConfiguration configuration;

     public MyDbContext(IConfiguration configuration, ITenantIdentifier tenantIdentifier)
     {
         this.configuration = configuration;
         this.tenantIdentifier = tenantIdentifier;
     }

     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
     {
         var connectionString = configuration
             .GetConnectionString(tenantIdentifier.GetCurrentTenantId() + "DataModel"); 
         optionsBuilder.UseSqlServer(connectionString);
     }	 
}

in Startup.cs:
 
services.AddSingleton<ITenantIdentifier, MyTenantIdentifier>();
services.AddDbContext<MyDbContext>();
From there you just inject your MyDbContext wherever you need it. Each request will get its own connection string based on the tenant ID.
This is with SqlServer, but should work the same with Postgres.

Hope that helps!

epswing
Nov 4, 2003

Soiled Meat
It'd be different for everyone, but what criteria is commonly used to set the TenantID in MyTenantIdentifier to "TenantA" or "TenantB" in an ASP.NET Core project (the currently logged in User? the subdomain?), and where is a reasonable place to store that information?

ChocolatePancake
Feb 25, 2007
We like to use subdomains, storing the mapping in a config file, makes it easier for us, but there's lots of ways to skin that cat.

biznatchio
Mar 31, 2001


Buglord
You don't even need to bury it in the DbContext OnConfiguring like that, you can do it right in your application's startup. The AddDbContext extension method for IServiceCollection has an overload to provide a function that takes IServiceProvider as one of its arguments, so you can get your tenant-providing service there and keep all your configuration during service registration where it belongs.


ChocolatePancake posted:

We like to use subdomains, storing the mapping in a config file, makes it easier for us, but there's lots of ways to skin that cat.

We do that for our IDP (mapping to tenant by hostname); then for all our application services we map based off the issuer of the passed OAuth access token.

But there are still some things that are difficult to make per-tenant; so we structure our web applications to have the initial WebApplication host built, and all that host does is look at the supplied bearer token to identify the issuer, then passes the request off to a separate tenant-specific host instance (one per tenant -- created on demand when the first request for a particular tenant hits the process), which then handles it exactly like it would if it were a single tenant application because it basically *is* just running lots of separate single tenant applications all in one process. You also don't get boned if you ever need to use a library that assumes a single tenant application; and you never ever accidentally do things like mix up memory caches cross-tenant or any of the other pitfalls you might fall for if you're not hypervigilant about making sure you never accidentally assume a single tenant.

biznatchio fucked around with this message at 04:37 on May 1, 2024

susan b buffering
Nov 14, 2016

epswing posted:

It'd be different for everyone, but what criteria is commonly used to set the TenantID in MyTenantIdentifier to "TenantA" or "TenantB" in an ASP.NET Core project (the currently logged in User? the subdomain?), and where is a reasonable place to store that information?

Our IDP just adds the tenant ID to the user's claims.

Adbot
ADBOT LOVES YOU

Calidus
Oct 31, 2011

Stand back I'm going to try science!

susan b buffering posted:

Our IDP just adds the tenant ID to the user's claims.

I really like this method.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply