diff --git a/Volo.Abp.sln b/Volo.Abp.sln
index 4fba1e3103..d6a627317f 100644
--- a/Volo.Abp.sln
+++ b/Volo.Abp.sln
@@ -46,6 +46,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Volo.Abp.MultiTenancy", "sr
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Volo.Abp.MultiTenancy.Tests", "test\Volo.Abp.MultiTenancy.Tests\Volo.Abp.MultiTenancy.Tests.xproj", "{05271341-7A15-484C-9FD6-802A4193F4DE}"
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Volo.Abp.AspNetCore.MultiTenancy", "src\Volo.Abp.AspNetCore.MultiTenancy\Volo.Abp.AspNetCore.MultiTenancy.xproj", "{7CC7946B-E026-4F66-8D4F-4F78F4801D43}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -100,6 +102,10 @@ Global
{05271341-7A15-484C-9FD6-802A4193F4DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{05271341-7A15-484C-9FD6-802A4193F4DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{05271341-7A15-484C-9FD6-802A4193F4DE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7CC7946B-E026-4F66-8D4F-4F78F4801D43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7CC7946B-E026-4F66-8D4F-4F78F4801D43}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7CC7946B-E026-4F66-8D4F-4F78F4801D43}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7CC7946B-E026-4F66-8D4F-4F78F4801D43}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -122,5 +128,6 @@ Global
{B520B696-86C7-46D2-A359-C2E9013A7BED} = {82B41A0A-6068-410F-9C6B-2508CA763E21}
{58FA9F8F-216D-4C93-8929-D40D22B11CA7} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8}
{05271341-7A15-484C-9FD6-802A4193F4DE} = {37087D1B-3693-4E96-983D-A69F210BDE53}
+ {7CC7946B-E026-4F66-8D4F-4F78F4801D43} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8}
EndGlobalSection
EndGlobal
diff --git a/src/Volo.Abp.AspNetCore.MultiTenancy/Properties/AssemblyInfo.cs b/src/Volo.Abp.AspNetCore.MultiTenancy/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..e59be26506
--- /dev/null
+++ b/src/Volo.Abp.AspNetCore.MultiTenancy/Properties/AssemblyInfo.cs
@@ -0,0 +1,19 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Volo.Abp.AspNetCore.MultiTenancy")]
+[assembly: AssemblyTrademark("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("7cc7946b-e026-4f66-8d4f-4f78f4801d43")]
diff --git a/src/Volo.Abp.AspNetCore.MultiTenancy/Volo.Abp.AspNetCore.MultiTenancy.xproj b/src/Volo.Abp.AspNetCore.MultiTenancy/Volo.Abp.AspNetCore.MultiTenancy.xproj
new file mode 100644
index 0000000000..5d264e68e9
--- /dev/null
+++ b/src/Volo.Abp.AspNetCore.MultiTenancy/Volo.Abp.AspNetCore.MultiTenancy.xproj
@@ -0,0 +1,20 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ 7cc7946b-e026-4f66-8d4f-4f78f4801d43
+
+
+ .\obj
+ .\bin\
+ v4.6.1
+
+
+ 2.0
+
+
+
\ No newline at end of file
diff --git a/src/Volo.Abp.AspNetCore.MultiTenancy/project.json b/src/Volo.Abp.AspNetCore.MultiTenancy/project.json
new file mode 100644
index 0000000000..4690ae6dda
--- /dev/null
+++ b/src/Volo.Abp.AspNetCore.MultiTenancy/project.json
@@ -0,0 +1,14 @@
+{
+ "version": "1.0.0-*",
+
+ "dependencies": {
+ "NETStandard.Library": "1.6.1",
+ "Volo.Abp.MultiTenancy": "1.0.0-*"
+ },
+
+ "frameworks": {
+ "netstandard1.6": {
+ "imports": "dnxcore50"
+ }
+ }
+}
diff --git a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/AmbientTenantAccessor.cs b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/AmbientTenantAccessor.cs
new file mode 100644
index 0000000000..d7b70e1ad9
--- /dev/null
+++ b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/AmbientTenantAccessor.cs
@@ -0,0 +1,21 @@
+using System.Threading;
+using Volo.DependencyInjection;
+
+namespace Volo.Abp.MultiTenancy
+{
+ public class AmbientTenantAccessor : IAmbientTenantAccessor, ISingletonDependency //TODO: Should be IScopedDependency?
+ {
+ public AmbientTenantInfo AmbientTenant
+ {
+ get { return _tenant.Value; }
+ set { _tenant.Value = value; }
+ }
+
+ private readonly AsyncLocal _tenant;
+
+ public AmbientTenantAccessor()
+ {
+ _tenant = new AsyncLocal();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/CurrentTenantResolveContext.cs b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/CurrentTenantResolveContext.cs
index e68450fdee..9b0c17dfcb 100644
--- a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/CurrentTenantResolveContext.cs
+++ b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/CurrentTenantResolveContext.cs
@@ -2,7 +2,7 @@ namespace Volo.Abp.MultiTenancy
{
public class CurrentTenantResolveContext : ICurrentTenantResolveContext
{
- public ITenantInfo Tenant { get; set; }
+ public TenantInfo Tenant { get; set; }
public bool Handled { get; set; }
}
diff --git a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/IAmbientTenantAccessor.cs b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/IAmbientTenantAccessor.cs
new file mode 100644
index 0000000000..146ad48c5c
--- /dev/null
+++ b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/IAmbientTenantAccessor.cs
@@ -0,0 +1,22 @@
+using JetBrains.Annotations;
+
+namespace Volo.Abp.MultiTenancy
+{
+ public interface IAmbientTenantAccessor
+ {
+ AmbientTenantInfo AmbientTenant { get; set; }
+ }
+
+ public class AmbientTenantInfo
+ {
+ ///
+ /// Null for host.
+ ///
+ public TenantInfo Tenant { get; set; }
+
+ public AmbientTenantInfo([CanBeNull] TenantInfo tenant)
+ {
+ Tenant = tenant;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ICurrentTenantResolveContext.cs b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ICurrentTenantResolveContext.cs
index 61aa9273ec..73b89c1bd9 100644
--- a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ICurrentTenantResolveContext.cs
+++ b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ICurrentTenantResolveContext.cs
@@ -2,7 +2,7 @@ namespace Volo.Abp.MultiTenancy
{
public interface ICurrentTenantResolveContext
{
- ITenantInfo Tenant { get; set; }
+ TenantInfo Tenant { get; set; }
bool Handled { get; set; }
}
diff --git a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/IMultiTenancyManager.cs b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/IMultiTenancyManager.cs
index 43aa6db2e0..3b5f055c77 100644
--- a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/IMultiTenancyManager.cs
+++ b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/IMultiTenancyManager.cs
@@ -1,7 +1,11 @@
+using System;
+
namespace Volo.Abp.MultiTenancy
{
public interface IMultiTenancyManager
{
- ITenantInfo CurrentTenant { get; }
+ TenantInfo CurrentTenant { get; }
+
+ IDisposable ChangeTenant(TenantInfo tenantInfo);
}
}
\ No newline at end of file
diff --git a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ITenantInfo.cs b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ITenantInfo.cs
deleted file mode 100644
index eb72ef6e8f..0000000000
--- a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ITenantInfo.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Volo.Abp.MultiTenancy
-{
- public interface ITenantInfo
- {
- string Id { get; }
-
- string Name { get; }
- }
-}
\ No newline at end of file
diff --git a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyManager.cs b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyManager.cs
index e2b5665985..3bf70d6b45 100644
--- a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyManager.cs
+++ b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyManager.cs
@@ -5,17 +5,24 @@ namespace Volo.Abp.MultiTenancy
{
public class MultiTenancyManager : IMultiTenancyManager
{
- public ITenantInfo CurrentTenant => GetCurrentTenant();
+ public TenantInfo CurrentTenant => GetCurrentTenant();
+ private readonly IAmbientTenantAccessor _ambientTenantAccessor;
private readonly IEnumerable _currentTenantResolvers;
- public MultiTenancyManager(IEnumerable currentTenantResolvers)
+ public MultiTenancyManager(IAmbientTenantAccessor ambientTenantAccessor, IEnumerable currentTenantResolvers)
{
+ _ambientTenantAccessor = ambientTenantAccessor;
_currentTenantResolvers = currentTenantResolvers;
}
- protected virtual ITenantInfo GetCurrentTenant()
+ protected virtual TenantInfo GetCurrentTenant()
{
+ if (_ambientTenantAccessor.AmbientTenant != null)
+ {
+ return _ambientTenantAccessor.AmbientTenant.Tenant;
+ }
+
var context = new CurrentTenantResolveContext();
foreach (var currentTenantResolver in _currentTenantResolvers)
@@ -29,5 +36,17 @@ namespace Volo.Abp.MultiTenancy
return context.Tenant;
}
+
+ public IDisposable ChangeTenant(TenantInfo tenantInfo)
+ {
+ var oldValue = _ambientTenantAccessor.AmbientTenant;
+
+ _ambientTenantAccessor.AmbientTenant = new AmbientTenantInfo(tenantInfo);
+
+ return new DisposeAction(() =>
+ {
+ _ambientTenantAccessor.AmbientTenant = oldValue;
+ });
+ }
}
}
diff --git a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantInfo.cs b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantInfo.cs
index 83a6f6c3fd..00b27bb348 100644
--- a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantInfo.cs
+++ b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantInfo.cs
@@ -2,7 +2,7 @@ using JetBrains.Annotations;
namespace Volo.Abp.MultiTenancy
{
- public class TenantInfo : ITenantInfo
+ public class TenantInfo
{
public string Id { get; }
diff --git a/src/Volo.Abp/Volo/Abp/DisposeAction.cs b/src/Volo.Abp/Volo/Abp/DisposeAction.cs
new file mode 100644
index 0000000000..116249e58c
--- /dev/null
+++ b/src/Volo.Abp/Volo/Abp/DisposeAction.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Volo.Abp
+{
+ ///
+ /// This class can be used to provide an action when
+ /// Dipose method is called.
+ ///
+ public class DisposeAction : IDisposable
+ {
+ private readonly Action _action;
+
+ ///
+ /// Creates a new object.
+ ///
+ /// Action to be executed when this object is disposed.
+ public DisposeAction(Action action)
+ {
+ Check.NotNull(action, nameof(action));
+
+ _action = action;
+ }
+
+ public void Dispose()
+ {
+ _action();
+ }
+ }
+}
diff --git a/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenantManager_TenantResolver_Tests.cs b/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenantManager_TenantResolver_Tests.cs
index 2d12040219..b8027f0e12 100644
--- a/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenantManager_TenantResolver_Tests.cs
+++ b/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenantManager_TenantResolver_Tests.cs
@@ -1,4 +1,5 @@
using System;
+using NSubstitute;
using Shouldly;
using Xunit;
@@ -11,9 +12,9 @@ namespace Volo.Abp.MultiTenancy
{
//Arrange
- var manager = new MultiTenancyManager(new ITenantResolver[0]);
+ var manager = new MultiTenancyManager(Substitute.For(), new ITenantResolver[0]);
- //Act
+ //Assert
manager.CurrentTenant.ShouldBeNull();
}
@@ -25,9 +26,7 @@ namespace Volo.Abp.MultiTenancy
var fakeTenant = new TenantInfo(Guid.NewGuid().ToString(), "acme");
- //Act
-
- var manager = new MultiTenancyManager(new[]
+ var manager = new MultiTenancyManager(Substitute.For(), new[]
{
new TenantResolverAction(context =>
{
@@ -49,13 +48,11 @@ namespace Volo.Abp.MultiTenancy
var fakeTenant = new TenantInfo(Guid.NewGuid().ToString(), "acme");
- //Act
-
- var manager = new MultiTenancyManager(new[]
+ var manager = new MultiTenancyManager(Substitute.For(), new[]
{
new TenantResolverAction(context =>
{
- context.Tenant = new TenantInfo(Guid.NewGuid().ToString(), "skipped-tenant");
+ context.Tenant = new TenantInfo(Guid.NewGuid().ToString(), "skipped-tenant-1");
}),
new TenantResolverAction(context =>
{
@@ -64,7 +61,7 @@ namespace Volo.Abp.MultiTenancy
}),
new TenantResolverAction(context =>
{
- context.Tenant = new TenantInfo(Guid.NewGuid().ToString(), "skipped-tenant");
+ context.Tenant = new TenantInfo(Guid.NewGuid().ToString(), "skipped-tenant-2");
context.Handled = true;
})
});
@@ -73,5 +70,36 @@ namespace Volo.Abp.MultiTenancy
manager.CurrentTenant.ShouldBe(fakeTenant);
}
+
+ [Fact]
+ public void Should_Get_Ambient_Tenant_If_Changed()
+ {
+ //Arrange
+
+ var oldTenant = new TenantInfo(Guid.NewGuid().ToString(), "old-tenant");
+
+ var manager = new MultiTenancyManager(Substitute.For(), new[]
+ {
+ new TenantResolverAction(context =>
+ {
+ context.Tenant = oldTenant;
+ context.Handled = true;
+ })
+ });
+
+ manager.CurrentTenant.ShouldBe(oldTenant);
+
+ //Act
+
+ var overridedTenant = new TenantInfo(Guid.NewGuid().ToString(), "overrided-tenant");
+ using (manager.ChangeTenant(overridedTenant))
+ {
+ //Assert
+ manager.CurrentTenant.ShouldBe(overridedTenant);
+ }
+
+ //Assert
+ manager.CurrentTenant.ShouldBe(oldTenant);
+ }
}
}