diff --git a/src/Infrastructure/DependencyInjection/MultiTenantServiceScopeFactory.cs b/src/Infrastructure/DependencyInjection/MultiTenantServiceScopeFactory.cs
index f07c16d..339039c 100644
--- a/src/Infrastructure/DependencyInjection/MultiTenantServiceScopeFactory.cs
+++ b/src/Infrastructure/DependencyInjection/MultiTenantServiceScopeFactory.cs
@@ -9,11 +9,18 @@ namespace MultiTenant.AspNetCore.Infrastructure.DependencyInjection
/// Factory for creating tenant specific service providers
///
///
- internal class MultiTenantServiceProviderFactory(IServiceCollection containerBuilder, Action tenantServiceConfiguration) where T : ITenantInfo
+ internal class MultiTenantServiceProviderFactory where T : ITenantInfo
{
-
+
+ public MultiTenantServiceProviderFactory(IServiceCollection containerBuilder, Action tenantServiceConfiguration)
+ {
+ this.containerBuilder = containerBuilder;
+ this.tenantServiceConfiguration = tenantServiceConfiguration;
+ }
//Cache compiled providers
private readonly ConcurrentDictionary> CompiledProviders = new();
+ private readonly IServiceCollection containerBuilder;
+ private readonly Action tenantServiceConfiguration;
public IServiceProvider GetServiceProviderForTenant(T tenant)
{
@@ -36,9 +43,16 @@ public IServiceProvider GetServiceProviderForTenant(T tenant)
/// Factory wrapper for creating service scopes
///
///
- internal class MultiTenantServiceScopeFactory(MultiTenantServiceProviderFactory ServiceProviderFactory, IMultiTenantContextAccessor multiTenantContextAccessor) : IMultiTenantServiceScopeFactory where T : ITenantInfo
+ internal class MultiTenantServiceScopeFactory : IMultiTenantServiceScopeFactory where T : ITenantInfo
{
+ private readonly MultiTenantServiceProviderFactory serviceProviderFactory;
+ private readonly IMultiTenantContextAccessor multiTenantContextAccessor;
+ public MultiTenantServiceScopeFactory(MultiTenantServiceProviderFactory ServiceProviderFactory, IMultiTenantContextAccessor multiTenantContextAccessor)
+ {
+ serviceProviderFactory = ServiceProviderFactory;
+ this.multiTenantContextAccessor = multiTenantContextAccessor;
+ }
///
/// Create scope
///
@@ -46,7 +60,7 @@ internal class MultiTenantServiceScopeFactory(MultiTenantServiceProviderFacto
public IServiceScope CreateScope()
{
var tenant = multiTenantContextAccessor.TenantInfo ?? throw new InvalidOperationException("Tenant context is not available");
- return ServiceProviderFactory.GetServiceProviderForTenant(tenant).CreateScope();
+ return serviceProviderFactory.GetServiceProviderForTenant(tenant).CreateScope();
}
}
}
diff --git a/src/Infrastructure/Middleware/MultiTenantContextAccessorMiddleware.StartupFilter.cs b/src/Infrastructure/Middleware/MultiTenantContextAccessorMiddleware.StartupFilter.cs
index 4c8c0f9..56bb185 100644
--- a/src/Infrastructure/Middleware/MultiTenantContextAccessorMiddleware.StartupFilter.cs
+++ b/src/Infrastructure/Middleware/MultiTenantContextAccessorMiddleware.StartupFilter.cs
@@ -8,7 +8,7 @@ namespace MultiTenant.AspNetCore.Infrastructure.Middleware
/// Register the multitenant context accessor middleware with the app pipeline.
///
///
- internal class MultiTenantContextAccessorStartupFilter() : IStartupFilter where T : ITenantInfo
+ internal class MultiTenantContextAccessorStartupFilter : IStartupFilter where T : ITenantInfo
{
///
/// Adds the multitenant request services middleware to the app pipeline.
diff --git a/src/Infrastructure/Middleware/MultiTenantContextAccessorMiddleware.cs b/src/Infrastructure/Middleware/MultiTenantContextAccessorMiddleware.cs
index 20a9bd3..e6758ea 100644
--- a/src/Infrastructure/Middleware/MultiTenantContextAccessorMiddleware.cs
+++ b/src/Infrastructure/Middleware/MultiTenantContextAccessorMiddleware.cs
@@ -8,14 +8,30 @@ namespace MultiTenant.AspNetCore.Infrastructure.Middleware
///
///
///
- internal class MultiTenantContextAccessorMiddleware(
+ internal class MultiTenantContextAccessorMiddleware where T : ITenantInfo
+ {
+ private readonly RequestDelegate next;
+ private readonly IHttpContextAccessor httpContextAccessor;
+ private readonly IMultiTenantContextAccessor tenantAccessor;
+ private readonly ITenantLookupService tenantResolver;
+ private readonly ITenantResolutionStrategy tenantResolutionStrategy;
+ private readonly IOptions> options;
+
+ public MultiTenantContextAccessorMiddleware(
RequestDelegate next,
IHttpContextAccessor httpContextAccessor,
IMultiTenantContextAccessor TenantAccessor,
ITenantLookupService TenantResolver,
ITenantResolutionStrategy TenantResolutionStrategy,
- IOptions> Options) where T : ITenantInfo
- {
+ IOptions> Options)
+ {
+ this.next = next;
+ this.httpContextAccessor = httpContextAccessor;
+ tenantAccessor = TenantAccessor;
+ tenantResolver = TenantResolver;
+ tenantResolutionStrategy = TenantResolutionStrategy;
+ options = Options;
+ }
///
/// Set the services for the tenant to be our specific tenant services
@@ -24,13 +40,13 @@ internal class MultiTenantContextAccessorMiddleware(
///
public async Task Invoke(HttpContext context)
{
- var options = Options.Value!;
+ var options = this.options.Value!;
//Set context if missing so it can be used by the tenant services to resolve the tenant
httpContextAccessor.HttpContext ??= context;
//Get the tenant identifier
- var identifier = await TenantResolutionStrategy.GetTenantIdentifierAsync();
+ var identifier = await tenantResolutionStrategy.GetTenantIdentifierAsync();
if(identifier == null && options.MissingTenantBehavior == MissingTenantBehavior.ThrowException)
throw new InvalidOperationException("Tenant identifier could not be resolved using configured strategy");
if(identifier == null && options.MissingTenantBehavior == MissingTenantBehavior.UseDefault)
@@ -39,13 +55,13 @@ public async Task Invoke(HttpContext context)
//Set the tenant context
if (identifier != null)
{
- var tenant = await TenantResolver.GetTenantAsync(identifier);
+ var tenant = await tenantResolver.GetTenantAsync(identifier);
if(tenant == null && options.MissingTenantBehavior == MissingTenantBehavior.ThrowException)
throw new InvalidOperationException($"No tenant found matching '{identifier}'");
if(tenant == null && options.MissingTenantBehavior == MissingTenantBehavior.UseDefault)
tenant = options.DefaultTenant;
- TenantAccessor.TenantInfo ??= tenant;
+ tenantAccessor.TenantInfo ??= tenant;
}
await next.Invoke(context);
diff --git a/src/Infrastructure/Middleware/MultiTenantMiddleware.cs b/src/Infrastructure/Middleware/MultiTenantMiddleware.cs
index 3392ced..e2c1532 100644
--- a/src/Infrastructure/Middleware/MultiTenantMiddleware.cs
+++ b/src/Infrastructure/Middleware/MultiTenantMiddleware.cs
@@ -13,11 +13,20 @@ namespace MultiTenant.AspNetCore.Infrastructure.Middleware
///
///
///
- internal class MultiTenantMiddleware(RequestDelegate next, IApplicationBuilder builder, Action configurePipeline)
+ internal class MultiTenantMiddleware
where T : ITenantInfo
{
+ public MultiTenantMiddleware(RequestDelegate next, IApplicationBuilder builder, Action configurePipeline)
+ {
+ this.next = next;
+ this.builder = builder;
+ this.configurePipeline = configurePipeline;
+ }
//Cache compiled pipelines
private readonly ConcurrentDictionary> _pipelinesCache = new();
+ private readonly RequestDelegate next;
+ private readonly IApplicationBuilder builder;
+ private readonly Action configurePipeline;
///
/// Set the services for the tenant to be our specific tenant services
diff --git a/src/Infrastructure/Middleware/MultiTenantRequestServicesMiddleware.StartupFilter.cs b/src/Infrastructure/Middleware/MultiTenantRequestServicesMiddleware.StartupFilter.cs
index 521eb2c..72885d4 100644
--- a/src/Infrastructure/Middleware/MultiTenantRequestServicesMiddleware.StartupFilter.cs
+++ b/src/Infrastructure/Middleware/MultiTenantRequestServicesMiddleware.StartupFilter.cs
@@ -8,7 +8,7 @@ namespace MultiTenant.AspNetCore.Infrastructure.Middleware
///
/// The tenant specific tenant services configuration.
///
- internal class MultitenantRequestServicesStartupFilter() : IStartupFilter where T : ITenantInfo
+ internal class MultitenantRequestServicesStartupFilter : IStartupFilter where T : ITenantInfo
{
///
/// Adds the multitenant request services middleware to the app pipeline.
diff --git a/src/Infrastructure/Middleware/MultiTenantRequestServicesMiddleware.cs b/src/Infrastructure/Middleware/MultiTenantRequestServicesMiddleware.cs
index 3809cf3..3fbab11 100644
--- a/src/Infrastructure/Middleware/MultiTenantRequestServicesMiddleware.cs
+++ b/src/Infrastructure/Middleware/MultiTenantRequestServicesMiddleware.cs
@@ -10,12 +10,21 @@ namespace MultiTenant.AspNetCore.Infrastructure.Middleware
///
///
///
- internal class MultiTenantRequestServicesMiddleware(
- RequestDelegate next,
- IMultiTenantServiceScopeFactory multiTenantServiceProviderScopeFactory,
- IHttpContextAccessor httpContextAccessor) where T : ITenantInfo
+ internal class MultiTenantRequestServicesMiddleware where T : ITenantInfo
{
+ private readonly RequestDelegate next;
+ private readonly IMultiTenantServiceScopeFactory multiTenantServiceProviderScopeFactory;
+ private readonly IHttpContextAccessor httpContextAccessor;
+ public MultiTenantRequestServicesMiddleware(
+ RequestDelegate next,
+ IMultiTenantServiceScopeFactory multiTenantServiceProviderScopeFactory,
+ IHttpContextAccessor httpContextAccessor)
+ {
+ this.next = next;
+ this.multiTenantServiceProviderScopeFactory = multiTenantServiceProviderScopeFactory;
+ this.httpContextAccessor = httpContextAccessor;
+ }
///
/// Set the services for the tenant to be our specific tenant services
///
diff --git a/src/Infrastructure/Options/MultiTenantOptionsCache.cs b/src/Infrastructure/Options/MultiTenantOptionsCache.cs
index 330d6d1..90a211a 100644
--- a/src/Infrastructure/Options/MultiTenantOptionsCache.cs
+++ b/src/Infrastructure/Options/MultiTenantOptionsCache.cs
@@ -8,12 +8,15 @@ namespace MultiTenant.AspNetCore.Infrastructure.Options
///
///
///
- internal class MultiTenantOptionsCache(IMultiTenantContextAccessor multiTenantContextAccessor) : IOptionsMonitorCache
+ internal class MultiTenantOptionsCache : IOptionsMonitorCache
where TOptions : class where T : ITenantInfo
{
-
- private readonly IMultiTenantContextAccessor multiTenantContextAccessor = multiTenantContextAccessor ??
+ public MultiTenantOptionsCache(IMultiTenantContextAccessor multiTenantContextAccessor)
+ {
+ this.multiTenantContextAccessor = multiTenantContextAccessor ??
throw new ArgumentNullException(nameof(multiTenantContextAccessor));
+ }
+ private readonly IMultiTenantContextAccessor multiTenantContextAccessor;
private readonly ConcurrentDictionary> tenantCaches = new();
///
diff --git a/src/Infrastructure/Options/MultiTenantOptionsManager.cs b/src/Infrastructure/Options/MultiTenantOptionsManager.cs
index f361624..32e198d 100644
--- a/src/Infrastructure/Options/MultiTenantOptionsManager.cs
+++ b/src/Infrastructure/Options/MultiTenantOptionsManager.cs
@@ -2,8 +2,16 @@
namespace MultiTenant.AspNetCore.Infrastructure.Options
{
- internal class MultiTenantOptionsManager(IOptionsFactory factory, IOptionsMonitorCache cache) : IOptionsSnapshot where TOptions : class
+ internal class MultiTenantOptionsManager : IOptionsSnapshot where TOptions : class
{
+ private readonly IOptionsFactory factory;
+ private readonly IOptionsMonitorCache cache;
+
+ public MultiTenantOptionsManager(IOptionsFactory factory, IOptionsMonitorCache cache)
+ {
+ this.factory = factory;
+ this.cache = cache;
+ }
public TOptions Value => Get(Microsoft.Extensions.Options.Options.DefaultName);
public TOptions Get(string? name)
diff --git a/src/Infrastructure/Strategies/HostResolutionStrategy.cs b/src/Infrastructure/Strategies/HostResolutionStrategy.cs
index 4398ff3..2481564 100644
--- a/src/Infrastructure/Strategies/HostResolutionStrategy.cs
+++ b/src/Infrastructure/Strategies/HostResolutionStrategy.cs
@@ -5,9 +5,13 @@ namespace MultiTenant.AspNetCore.Infrastructure.Strategies
///
/// Resolve the host to a tenant identifier
///
- internal class HostResolutionStrategy(IHttpContextAccessor httpContextAccessor) : ITenantResolutionStrategy
+ internal class HostResolutionStrategy : ITenantResolutionStrategy
{
- private readonly IHttpContextAccessor _httpContextAccessor = httpContextAccessor;
+ public HostResolutionStrategy(IHttpContextAccessor httpContextAccessor)
+ {
+ _httpContextAccessor = httpContextAccessor;
+ }
+ private readonly IHttpContextAccessor _httpContextAccessor;
///
/// Get the tenant identifier
diff --git a/src/MultiTenant.AspNetCore.csproj b/src/MultiTenant.AspNetCore.csproj
index b816084..97acfd6 100644
--- a/src/MultiTenant.AspNetCore.csproj
+++ b/src/MultiTenant.AspNetCore.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net6.0
enable
enable
MultiTenant.AspNetCore
diff --git a/src/Registration/TenantBuilder.cs b/src/Registration/TenantBuilder.cs
index ec14084..8c8afbd 100644
--- a/src/Registration/TenantBuilder.cs
+++ b/src/Registration/TenantBuilder.cs
@@ -15,8 +15,16 @@ namespace MultiTenant.AspNetCore.Builder
/// Tenant builder
///
///
- public class TenantBuilder(IServiceCollection Services, MultiTenantOptions options) where T : ITenantInfo
+ public class TenantBuilder where T : ITenantInfo
{
+ private readonly IServiceCollection services;
+ private readonly MultiTenantOptions options;
+
+ public TenantBuilder(IServiceCollection Services, MultiTenantOptions options)
+ {
+ services = Services;
+ this.options = options;
+ }
///
/// Register the tenant resolver implementation
///
@@ -25,8 +33,8 @@ public class TenantBuilder(IServiceCollection Services, MultiTenantOptions
///
public TenantBuilder WithResolutionStrategy() where V : class, ITenantResolutionStrategy
{
- Services.TryAddSingleton();
- Services.TryAddSingleton(typeof(ITenantResolutionStrategy), typeof(V));
+ services.TryAddSingleton();
+ services.TryAddSingleton(typeof(ITenantResolutionStrategy), typeof(V));
return this;
}
@@ -47,7 +55,7 @@ public TenantBuilder WithHostResolutionStrategy()
///
public TenantBuilder WithTenantLookupService() where V : class, ITenantLookupService
{
- Services.TryAddSingleton, V>();
+ services.TryAddSingleton, V>();
return this;
}
@@ -60,7 +68,7 @@ public TenantBuilder WithTenantLookupService() where V : class, ITenantLoo
public TenantBuilder WithInMemoryTenantLookupService(IEnumerable tenants)
{
var service = new InMemoryLookupService(tenants);
- Services.TryAddSingleton>(service);
+ services.TryAddSingleton>(service);
return this;
}
@@ -74,11 +82,11 @@ public TenantBuilder WithTenantedServices(Action conf
{
//Replace the default service provider with a multitenant service provider
if (!options.DisableAutomaticPipelineRegistration)
- Services.Insert(0, ServiceDescriptor.Transient(provider => new MultitenantRequestServicesStartupFilter()));
+ services.Insert(0, ServiceDescriptor.Transient(provider => new MultitenantRequestServicesStartupFilter()));
//Register the multi-tenant service provider
- Services.AddSingleton>();
- Services.AddSingleton(new MultiTenantServiceProviderFactory(Services, configuration));
+ services.AddSingleton>();
+ services.AddSingleton(new MultiTenantServiceProviderFactory(services, configuration));
return this;
}
@@ -91,19 +99,19 @@ public TenantBuilder WithTenantedServices(Action conf
///
public TenantBuilder WithTenantedConfigure(Action tenantOptionsConfiguration) where TOptions : class
{
- Services.AddOptions();
+ services.AddOptions();
- Services.TryAddSingleton, MultiTenantOptionsCache>();
- Services.TryAddScoped>((sp) =>
+ services.TryAddSingleton, MultiTenantOptionsCache>();
+ services.TryAddScoped>((sp) =>
{
return new MultiTenantOptionsManager(sp.GetRequiredService>(), sp.GetRequiredService>());
});
- Services.TryAddSingleton>((sp) =>
+ services.TryAddSingleton>((sp) =>
{
return new MultiTenantOptionsManager(sp.GetRequiredService>(), sp.GetRequiredService>());
});
- Services.AddSingleton, ConfigureOptions>((IServiceProvider sp) =>
+ services.AddSingleton, ConfigureOptions>((IServiceProvider sp) =>
{
var tenantAccessor = sp.GetRequiredService>();
return new ConfigureOptions((options) => tenantOptionsConfiguration(options, tenantAccessor.TenantInfo));
diff --git a/src/Services/AsyncLocalMultiTenantContextAccessor.cs b/src/Services/AsyncLocalMultiTenantContextAccessor.cs
index b2c465e..418d6e0 100644
--- a/src/Services/AsyncLocalMultiTenantContextAccessor.cs
+++ b/src/Services/AsyncLocalMultiTenantContextAccessor.cs
@@ -41,7 +41,7 @@ public W? TenantInfo
///
/// https://github.com/aspnet/HttpAbstractions/pull/1066
///
- private class TenantInfoHolder()
+ private class TenantInfoHolder
{
public W? Context;
}
diff --git a/src/Services/InMemoryLookupService.cs b/src/Services/InMemoryLookupService.cs
index b464660..1be0e5e 100644
--- a/src/Services/InMemoryLookupService.cs
+++ b/src/Services/InMemoryLookupService.cs
@@ -1,10 +1,16 @@
namespace MultiTenant.AspNetCore.Services
{
- internal class InMemoryLookupService(IEnumerable Tenants) : ITenantLookupService where T : ITenantInfo
+ internal class InMemoryLookupService : ITenantLookupService where T : ITenantInfo
{
+ private readonly IEnumerable tenants;
+
+ public InMemoryLookupService(IEnumerable Tenants)
+ {
+ tenants = Tenants;
+ }
public Task GetTenantAsync(string identifier)
{
- return Task.FromResult(Tenants.SingleOrDefault(t => t.Identifier == identifier));
+ return Task.FromResult(tenants.SingleOrDefault(t => t.Identifier == identifier));
}
}
}
diff --git a/test/MultiTenant.AspNetCore.Tests.csproj b/test/MultiTenant.AspNetCore.Tests.csproj
index adec023..3271eda 100644
--- a/test/MultiTenant.AspNetCore.Tests.csproj
+++ b/test/MultiTenant.AspNetCore.Tests.csproj
@@ -1,7 +1,7 @@
-
+
- net8.0
+ net6.0
enable
enable
@@ -10,7 +10,7 @@
-
+
diff --git a/test/TestTenant.cs b/test/TestTenant.cs
index dea832b..db5b3c4 100644
--- a/test/TestTenant.cs
+++ b/test/TestTenant.cs
@@ -1,8 +1,12 @@
-namespace MultiTenant.AspNetCore.Tests
+using System.ComponentModel.DataAnnotations;
+
+namespace MultiTenant.AspNetCore.Tests
{
internal class TestTenant : ITenantInfo
{
- public required string Id { get; set; }
- public required string Identifier { get; set; }
+ [Required]
+ public string Id { get; set; }
+ [Required]
+ public string Identifier { get; set; }
}
}