From e4f4be05c6959200c27d4db0b4c67073052e2192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 5 Jan 2018 14:26:06 +0300 Subject: [PATCH] Added multi tenancy document and refactored solution. --- docs/Multi-Tenancy.md | 366 ++++++++++++++++++ .../AbpDesk.Web.Mvc/AbpDesk.Web.Mvc.csproj | 1 + src/AbpDesk/Web_PlugIns/AbpDesk.MongoBlog.dll | Bin 15360 -> 15360 bytes ....cs => AbpAspNetCoreMultiTenancyModule.cs} | 4 +- .../MultiTenancy/DomainTenantResolver.cs | 4 +- .../MultiTenancy/HeaderTenantResolver.cs | 13 +- ...bpHttpModule.cs => AbpHttpClientModule.cs} | 0 src/Volo.Abp.Http/Volo.Abp.Http.csproj | 1 + .../Volo/Abp/Http/AbpHttpModule.cs | 2 + ...antResolver.cs => ActionTenantResolver.cs} | 4 +- .../ConfigurationTenantStore.cs | 2 +- .../ConfigurationTenantStoreOptions.cs | 2 +- .../Volo/Abp/AspNetCore/App/AppModule.cs | 2 +- .../AspNetCoreMultiTenancy_Tests.cs | 1 - ...ltiTenantConnectionStringResolver_Tests.cs | 1 - .../MultiTenancy/MultiTenantManager_Tests.cs | 5 +- 16 files changed, 392 insertions(+), 16 deletions(-) create mode 100644 docs/Multi-Tenancy.md rename src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/{AbpAspNetMultiTenancyModule.cs => AbpAspNetCoreMultiTenancyModule.cs} (85%) rename src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/{AbpHttpModule.cs => AbpHttpClientModule.cs} (100%) rename src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/{SimpleTenantResolver.cs => ActionTenantResolver.cs} (78%) rename src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/{ConfigurationStore => }/ConfigurationTenantStore.cs (93%) rename src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/{ConfigurationStore => }/ConfigurationTenantStoreOptions.cs (81%) diff --git a/docs/Multi-Tenancy.md b/docs/Multi-Tenancy.md new file mode 100644 index 0000000000..5e3d834b45 --- /dev/null +++ b/docs/Multi-Tenancy.md @@ -0,0 +1,366 @@ +## Multi-Tenancy + +ABP Multi-tenancy module provides base functionality to create multi tenant applications. + +Wikipedia [defines](https://en.wikipedia.org/wiki/Multitenancy) multi-tenancy as like that: + +> Software **Multi-tenancy** refers to a software **architecture** in which a **single instance** of a software runs on a server and serves **multiple tenants**. A tenant is a group of users who share a common access with specific privileges to the software instance. With a multitenant architecture, a software application is designed to provide every tenant a **dedicated share of the instance including its data**, configuration, user management, tenant individual functionality and non-functional properties. Multi-tenancy contrasts with multi-instance architectures, where separate software instances operate on behalf of different tenants. + +### Volo.Abp.MultiTenancy.Abstractions Package + +Volo.Abp.MultiTenancy.Abstractions package defines fundamental interfaces to make your code "multi-tenancy ready". So, install it to your project using the package manager console (PMC): + +```` +Install-Package Volo.Abp.MultiTenancy.Abstractions +```` + +> This package is already installed by default with the startup template. So, most of the time, you don't need to install it manually. + +Then you can add **AbpMultiTenancyAbstractionsModule** dependency to your module: + +````C# +using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; + +namespace MyCompany.MyProject +{ + [DependsOn(typeof(AbpMultiTenancyAbstractionsModule))] + public class MyModule : AbpModule + { + //... + } +} +```` + +> With the "Multi-tenancy ready" concept, we intent to develop our code to be compatible with multi-tenancy approach. Then it can be used in a multi-tenant application or not, depending on the requirements of the final application. + +#### Define Entities + +You can implement **IMultiTenant** interface for your entities to make them multi-tenancy ready. Example: + +````C# +using System; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace MyCompany.MyProject +{ + public class Product : AggregateRoot, IMultiTenant + { + public Guid? TenantId { get; set; } //IMultiTenant defines TenantId property + + public string Name { get; set; } + + public float Price { get; set; } + } +} +```` + +IMultiTenant requires to define a **TenantId** property in the implementing entity (See entity documentation (TODO: link) for more about entities). + +#### Obtain Current Tenant's Id + +Your code may require to get current tenant's id (regardless of how it's retrieved actually). You can [inject](Dependency-Injection.md) and use **ICurrentTenant** interface for such cases. Example: + +````C# +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; + +namespace MyCompany.MyProject +{ + public class MyService : ITransientDependency + { + private readonly ICurrentTenant _currentTenant; + + public MyService(ICurrentTenant currentTenant) + { + _currentTenant = currentTenant; + } + + public void DoIt() + { + var tenantId = _currentTenant.Id; + //use tenantId in your code... + } + } +} +```` + +### Volo.Abp.MultiTenancy Package + +Volo.Abp.MultiTenancy is the actual package that makes your application multi-tenant. Install it into your project using PMC: + +```` +Install-Package Volo.Abp.MultiTenancy +```` + +Then you can add **AbpMultiTenancyAbstractionsModule** dependency to your module: + +````C# +using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; + +namespace MyCompany.MyProject +{ + [DependsOn(typeof(AbpMultiTenancyModule))] + public class MyModule : AbpModule + { + //... + } +} +```` + +> If you add AbpMultiTenancyModule dependency to your module, then you don't need to add AbpMultiTenancyAbstractionsModule dependency separately since AbpMultiTenancyModule already depends on it. + +#### Determining Current Tenant + +The first thing for a multi-tenant application is to determine the current tenant on the runtime. Volo.Abp.MultiTenancy package only provides abstractions (named as tenant resolver) for determining the current tenant, however it does not have any implementation out of the box. + +**Volo.Abp.AspNetCore.MultiTenancy** package has implementation to determine the current tenant from current web request (from subdomain, header, cookie, route... etc.). See Volo.Abp.AspNetCore.MultiTenancy Package section later in this document. + +##### Custom Tenant Resolvers + +You can add your custom tenant resolver to **MultiTenancyOptions** in your module's ConfigureServices method as like below: + +````C# +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; + +namespace MyCompany.MyProject +{ + [DependsOn(typeof(AbpMultiTenancyModule))] + public class MyModule : AbpModule + { + public override void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + options.TenantResolvers.Add(new MyCustomTenantResolver()); + }); + + //... + } + } +} +```` + +MyCustomTenantResolver must implement **ITenantResolver** as shown below: + +````C# +using Volo.Abp.MultiTenancy; + +namespace MyCompany.MyProject +{ + public class MyCustomTenantResolver : ITenantResolver + { + public void Resolve(ITenantResolveContext context) + { + context.TenantIdOrName = ... //find tenant id or tenant name from somewhere... + } + } +} +```` + +A tenant resolver can set **TenantIdOrName** if it can determine it. If not, just leave it as is to allow next resolver to determine it. + +#### Tenant Store + +Volo.Abp.MultiTenancy package defines **ITenantStore** to abstract data source from the framework. You can implement ITenantStore to work with any data source (like a relational database) that stores information of your tenants. + +... + +##### Configuration Data Store + +There is a built in (and default) tenant store, named ConfigurationTenantStore, that can be used to store tenants using standard [configuration system](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/) (with [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration) package). Thus, you can define tenants as hard coded or get from your appsettings.json file. + +###### Example: Define tenants as hard-coded + +````C# +using System; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Data; +using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; + +namespace MyCompany.MyProject +{ + [DependsOn(typeof(AbpMultiTenancyModule))] + public class MyModule : AbpModule + { + public override void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + options.Tenants = new[] + { + new TenantInformation( + Guid.Parse("446a5211-3d72-4339-9adc-845151f8ada0"), //Id + "tenant1" //Name + ), + new TenantInformation( + Guid.Parse("25388015-ef1c-4355-9c18-f6b6ddbaf89d"), //Id + "tenant2" //Name + ) + { + //tenant2 has a seperated database + ConnectionStrings = + { + {ConnectionStrings.DefaultConnectionStringName, "..."} + } + } + }; + }); + } + } +} +```` + +###### Example: Define tenants in appsettings.json + +First create your configuration from your appsettings.json file as you always do. + +````C# +using System.IO; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; + +namespace MyCompany.MyProject +{ + [DependsOn(typeof(AbpMultiTenancyModule))] + public class MyModule : AbpModule + { + public override void ConfigureServices(IServiceCollection services) + { + var configuration = BuildConfiguration(); + + services.Configure(configuration); + } + + private static IConfigurationRoot BuildConfiguration() + { + return new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .Build(); + } + } +} +```` + +Then add a "**Tenants**" section to your appsettings.json: + +````json +"Tenants": [ + { + "Id": "446a5211-3d72-4339-9adc-845151f8ada0", + "Name": "tenant1" + }, + { + "Id": "25388015-ef1c-4355-9c18-f6b6ddbaf89d", + "Name": "tenant2", + "ConnectionStrings": { + "Default": "...write tenant2's db connection string here..." + } + } + ] +```` + +##### Volo.Abp... Package (TODO) + +TODO: This package implements ITenantStore using a real database... + +#### Tenant Information + +ITenantStore works with **TenantInformation** class that has several properties for a tenant: + +* **Id**: Unique Id of the tenant. +* **Name**: Unique name of the tenant. +* **ConnectionStrings**: If this tenant has dedicated database(s) to store it's data, then connection strings can provide database connection strings (it may have a default connection string and connection strings per modules - TODO: Add link to Abp.Data package document). + +A multi-tenant application may require additional tenant properties, but these are the minimal requirements for the framework to work with multiple tenants. + +#### Change Tenant By Code + +TODO... + +### Volo.Abp.AspNetCore.MultiTenancy Package + +Volo.Abp.AspNetCore.MultiTenancy package integrate multi-tenancy to ASP.NET Core applications. To install it to your project, run the following command on PMC: + +```` +Install-Package Volo.Abp.AspNetCore.MultiTenancy +```` + +Then you can add **AbpAspNetCoreMultiTenancyModule** dependency to your module: + +````C# +using Volo.Abp.Modularity; +using Volo.Abp.AspNetCore.MultiTenancy; + +namespace MyCompany.MyProject +{ + [DependsOn(typeof(AbpAspNetCoreMultiTenancyModule))] + public class MyModule : AbpModule + { + //... + } +} +```` + +#### Determining Current Tenant From Web Request + +Volo.Abp.AspNetCore.MultiTenancy package adds following tenant resolvers to determine current tenant from current web request (ordered by priority). These resolvers are added and work out of the box: + +* **QueryStringTenantResolver**: Tries to find current tenant id from query string parameter. Parameter name is "__tenantId" by default. +* **RouteTenantResolver**: Tries to find current tenant id from route (URL path). Variable name is "__tenantId" by default. So, if you defined a route with this variable, then it can determine the current tenant from the route. +* **HeaderTenantResolver**: Tries to find current tenant id from HTTP header. Header name is "__tenantId" by default. +* **CookieTenantResolver**: Tries to find current tenant id from cookie values. Cookie name is "__tenantId" by default. + +##### Domain Tenant Resolver + +In a real application, most of times you will want to determine current tenant either by subdomain (like mytenant1.mydomain.com) or by the whole domain (like mytenant.com). If so, you can configure MultiTenancyOptions to add a domain tenant resolver. + +###### Example: Add a subdomain resolver + +````C# +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.MultiTenancy; +using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; + +namespace MyCompany.MyProject +{ + [DependsOn(typeof(AbpAspNetCoreMultiTenancyModule))] + public class MyModule : AbpModule + { + public override void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + //Subdomain format: {0}.mydomain.com (adding as the highest priority resolver) + options.TenantResolvers.Insert(0, new DomainTenantResolver("{0}.mydomain.com")); + }); + + //... + } + } +} +```` + +{0} is the the placeholder to determine current tenant's unique name. + +Instead of ``options.TenantResolvers.Insert(0, new DomainTenantResolver("{0}.mydomain.com"));`` you can use this shortcut: + +````C# +options.AddDomainTenantResolver("{0}.mydomain.com"); +```` + +###### Example: Add a domain resolver + +````C# +options.AddDomainTenantResolver("{0}.com"); +```` + diff --git a/src/AbpDesk/AbpDesk.Web.Mvc/AbpDesk.Web.Mvc.csproj b/src/AbpDesk/AbpDesk.Web.Mvc/AbpDesk.Web.Mvc.csproj index 538386ea40..b98d7ce2f5 100644 --- a/src/AbpDesk/AbpDesk.Web.Mvc/AbpDesk.Web.Mvc.csproj +++ b/src/AbpDesk/AbpDesk.Web.Mvc/AbpDesk.Web.Mvc.csproj @@ -21,6 +21,7 @@ + diff --git a/src/AbpDesk/Web_PlugIns/AbpDesk.MongoBlog.dll b/src/AbpDesk/Web_PlugIns/AbpDesk.MongoBlog.dll index e8b4663419530366f7417b0973d815e710d5722c..207e4f6c0792d8dc50f8671b4ed5af95a9fcc063 100644 GIT binary patch delta 167 zcmZpuXsDRb!4kmb{BL8=D?wXE1{kP^G8q{VV!N@3sUpNCZx*uFM5uP)f|!MD!fkfA v*k*Czox%b_LTd`rE#us#{IPdoimHy?{6LMBmC(); + services.AddAssemblyOf(); } } } diff --git a/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolver.cs b/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolver.cs index 48ab8981b9..95167fe177 100644 --- a/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolver.cs +++ b/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolver.cs @@ -5,6 +5,8 @@ using Volo.Abp.Text.Formatting; namespace Volo.Abp.AspNetCore.MultiTenancy { + //TODO: Create a better domain format. We can accept regex for example. + public class DomainTenantResolver : HttpTenantResolverBase { private readonly string _domainFormat; @@ -22,7 +24,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy } var hostName = httpContext.Request.Host.Host.RemovePreFix("http://", "https://"); - var extractResult = FormattedStringValueExtracter.Extract(hostName, _domainFormat, true); + var extractResult = FormattedStringValueExtracter.Extract(hostName, _domainFormat, ignoreCase: true); if (!extractResult.IsMatch) { diff --git a/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolver.cs b/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolver.cs index c5f1385c0c..3ca1c3623d 100644 --- a/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolver.cs +++ b/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HeaderTenantResolver.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; using Volo.Abp.MultiTenancy; namespace Volo.Abp.AspNetCore.MultiTenancy @@ -26,12 +27,18 @@ namespace Volo.Abp.AspNetCore.MultiTenancy if (tenantIdHeader.Count > 1) { - context.ServiceProvider.GetRequiredService>().LogWarning( - $"HTTP request includes more than one {tenantIdKey} header value. First one will be used. All of them: {tenantIdHeader.JoinAsString(", ")}" - ); + Log(context, $"HTTP request includes more than one {tenantIdKey} header value. First one will be used. All of them: {tenantIdHeader.JoinAsString(", ")}"); } return tenantIdHeader.First(); } + + protected virtual void Log(ITenantResolveContext context, string text) + { + context + .ServiceProvider + .GetRequiredService>() + .LogWarning(text); + } } } \ No newline at end of file diff --git a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpModule.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientModule.cs similarity index 100% rename from src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpModule.cs rename to src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientModule.cs diff --git a/src/Volo.Abp.Http/Volo.Abp.Http.csproj b/src/Volo.Abp.Http/Volo.Abp.Http.csproj index d7d9cb961e..11234632ef 100644 --- a/src/Volo.Abp.Http/Volo.Abp.Http.csproj +++ b/src/Volo.Abp.Http/Volo.Abp.Http.csproj @@ -16,6 +16,7 @@ + \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/AbpHttpModule.cs b/src/Volo.Abp.Http/Volo/Abp/Http/AbpHttpModule.cs index 9cefb07a90..d164cd2b31 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/AbpHttpModule.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/AbpHttpModule.cs @@ -1,11 +1,13 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Http.ProxyScripting.Configuration; using Volo.Abp.Http.ProxyScripting.Generators.JQuery; +using Volo.Abp.Json; using Volo.Abp.Modularity; namespace Volo.Abp.Http { [DependsOn(typeof(AbpHttpAbstractionsModule))] + [DependsOn(typeof(AbpJsonModule))] public class AbpHttpModule : AbpModule { public override void ConfigureServices(IServiceCollection services) diff --git a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/SimpleTenantResolver.cs b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ActionTenantResolver.cs similarity index 78% rename from src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/SimpleTenantResolver.cs rename to src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ActionTenantResolver.cs index f9329638ba..583eff8187 100644 --- a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/SimpleTenantResolver.cs +++ b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ActionTenantResolver.cs @@ -3,11 +3,11 @@ using JetBrains.Annotations; namespace Volo.Abp.MultiTenancy { - public class SimpleTenantResolver : ITenantResolver + public class ActionTenantResolver : ITenantResolver { private readonly Action _resolveAction; - public SimpleTenantResolver([NotNull] Action resolveAction) + public ActionTenantResolver([NotNull] Action resolveAction) { Check.NotNull(resolveAction, nameof(resolveAction)); diff --git a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationStore/ConfigurationTenantStore.cs b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationTenantStore.cs similarity index 93% rename from src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationStore/ConfigurationTenantStore.cs rename to src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationTenantStore.cs index 6bdb6503f6..968b71edf1 100644 --- a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationStore/ConfigurationTenantStore.cs +++ b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationTenantStore.cs @@ -3,7 +3,7 @@ using System.Linq; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; -namespace Volo.Abp.MultiTenancy.ConfigurationStore +namespace Volo.Abp.MultiTenancy { [Dependency(TryRegister = true)] public class ConfigurationTenantStore : ITenantStore, ITransientDependency diff --git a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationStore/ConfigurationTenantStoreOptions.cs b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationTenantStoreOptions.cs similarity index 81% rename from src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationStore/ConfigurationTenantStoreOptions.cs rename to src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationTenantStoreOptions.cs index 67a9b6bd4c..f4b38fcd95 100644 --- a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationStore/ConfigurationTenantStoreOptions.cs +++ b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationTenantStoreOptions.cs @@ -1,4 +1,4 @@ -namespace Volo.Abp.MultiTenancy.ConfigurationStore +namespace Volo.Abp.MultiTenancy { public class ConfigurationTenantStoreOptions { diff --git a/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/AppModule.cs b/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/AppModule.cs index 06fa19658c..4ac8682e42 100644 --- a/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/AppModule.cs +++ b/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/AppModule.cs @@ -12,7 +12,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.AspNetCore.App { [DependsOn( - typeof(AbpAspNetMultiTenancyModule), + typeof(AbpAspNetCoreMultiTenancyModule), typeof(AbpAspNetCoreTestBaseModule) )] public class AppModule : AbpModule diff --git a/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Tests.cs b/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Tests.cs index 953887fbf1..b193574662 100644 --- a/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Tests.cs +++ b/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Tests.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; using Shouldly; using Volo.Abp.MultiTenancy; -using Volo.Abp.MultiTenancy.ConfigurationStore; using Xunit; namespace Volo.Abp.AspNetCore.MultiTenancy diff --git a/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/Data/MultiTenancy/MultiTenantConnectionStringResolver_Tests.cs b/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/Data/MultiTenancy/MultiTenantConnectionStringResolver_Tests.cs index 34ccfaf1c3..fbaa5a42f8 100644 --- a/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/Data/MultiTenancy/MultiTenantConnectionStringResolver_Tests.cs +++ b/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/Data/MultiTenancy/MultiTenantConnectionStringResolver_Tests.cs @@ -2,7 +2,6 @@ using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.MultiTenancy; -using Volo.Abp.MultiTenancy.ConfigurationStore; using Xunit; namespace Volo.Abp.Data.MultiTenancy diff --git a/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenantManager_Tests.cs b/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenantManager_Tests.cs index adbb8a0b50..93ab9ca47b 100644 --- a/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenantManager_Tests.cs +++ b/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenantManager_Tests.cs @@ -1,7 +1,6 @@ using System; using Microsoft.Extensions.DependencyInjection; using Shouldly; -using Volo.Abp.MultiTenancy.ConfigurationStore; using Xunit; namespace Volo.Abp.MultiTenancy @@ -43,7 +42,7 @@ namespace Volo.Abp.MultiTenancy { services.Configure(options => { - options.TenantResolvers.Add(new SimpleTenantResolver(context => + options.TenantResolvers.Add(new ActionTenantResolver(context => { if (_tenantToBeResolved == _tenantA) { @@ -51,7 +50,7 @@ namespace Volo.Abp.MultiTenancy } })); - options.TenantResolvers.Add(new SimpleTenantResolver(context => + options.TenantResolvers.Add(new ActionTenantResolver(context => { if (_tenantToBeResolved == _tenantB) {