I'm investigating an alternative implementation for database initialisation that doesn't rely upon #if #elif..... (doens't work for .Net code in VS2017 known issue) to select customer specific database initialisers. One approach which seems sensible for both development and CI/CD environments is the following:
I'm interested to gauge peoples option of this approach to me it seems a scalable solution to the problem, my only concern is loading the assembly at runtime but I guess strong naming and code signing the assembly will mitigate the risk.
This is the type of DI init I want to change remove dependency on #if....
private void DatabaseInitialiseDefinitions(ContainerBuilder builder)
{
#if site1
builder.RegisterType<site1ResourceIdentityDefinitions>()
.As<IResourceIdentityDefinition>()
.SingleInstance();
builder.RegisterType<site1UserDefinitions>()
.As<IUserDefinitions>()
.SingleInstance();
#elif site2
builder.RegisterType<site2ResourceIdentityDefinition>()
.As<IResourceIdentityDefinition>()
.SingleInstance();
builder.RegisterType<site2UserDefinitions>()
.As<IUserDefinitions>()
.SingleInstance();
#elif site3
builder.RegisterType<site3ResourceIdentityDefinition>()
.As<IResourceIdentityDefinition>()
.SingleInstance();
builder.RegisterType<site3UserDefinitions>()
.As<IUserDefinitions>()
.SingleInstance();
}
If it was just one place that you need to do this - then factory pattern (see the example of replacing compiler directives) to return tenant implementation or something similar is an option.
If it is more tenant-specific versions doing it with DI directly is a lot simpler than build time. Even if you just optionally register additional tenant implementations a DI container like Autofac will pull out the last matching registration unless you ask for an IEnumerable of services. If it was me I would use Dependency Injection and treat the app as multi-tenant. It may be that each app runs in isolation but the code is still multi-tenant.
If you had lots of registrations I'd use child containers to hold registrations that are specific to each tenant.
If you used Autofac then this extension would work - https://github.com/autofac/Autofac.AspNetCore.Multitenant or https://github.com/autofac/Autofac.Multitenant (if not .Net Core)
We have used it with multiple strategies to identify the tenant - simplest was simply a configuration setting in app.config that told it which tenant it was running as. The current one is based on hostname so all tenants run under one app. If it was a local application I'd expect a setting in a config that told it which tenant to be.