diff --git a/Volo.Abp.sln b/Volo.Abp.sln
index ba0cb91ba9..efe6c1f39e 100644
--- a/Volo.Abp.sln
+++ b/Volo.Abp.sln
@@ -274,11 +274,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Permissions.Applic
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Permissions.Application", "src\Volo.Abp.Permissions.Application\Volo.Abp.Permissions.Application.csproj", "{90197499-CBB6-4C8C-90E6-8718CD755C04}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Caching", "src\Volo.Abp.Caching\Volo.Abp.Caching.csproj", "{A5B650AB-A67F-4A4C-9F81-7B5471CA1331}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Caching", "src\Volo.Abp.Caching\Volo.Abp.Caching.csproj", "{A5B650AB-A67F-4A4C-9F81-7B5471CA1331}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EventBus", "src\Volo.Abp.EventBus\Volo.Abp.EventBus.csproj", "{D9455AE7-2E0C-4647-9880-F5831BCEE3D8}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EventBus", "src\Volo.Abp.EventBus\Volo.Abp.EventBus.csproj", "{D9455AE7-2E0C-4647-9880-F5831BCEE3D8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EventBus.Tests", "test\Volo.Abp.EventBus.Tests\Volo.Abp.EventBus.Tests.csproj", "{8C327AA0-BBED-4F8B-A88E-1DD97B04E58F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EventBus.Tests", "test\Volo.Abp.EventBus.Tests\Volo.Abp.EventBus.Tests.csproj", "{8C327AA0-BBED-4F8B-A88E-1DD97B04E58F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Caching.Tests", "test\Volo.Abp.Caching.Tests\Volo.Abp.Caching.Tests.csproj", "{B417D97C-330A-42CE-BDC6-93355B0A959A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Serialization", "src\Volo.Abp.Serialization\Volo.Abp.Serialization.csproj", "{38EF3EC8-9915-4216-B646-4BEE07006943}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Serialization.Tests", "test\Volo.Abp.Serialization.Tests\Volo.Abp.Serialization.Tests.csproj", "{65FB5893-7CB6-4694-A692-7E666E347D29}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -734,6 +740,18 @@ Global
{8C327AA0-BBED-4F8B-A88E-1DD97B04E58F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C327AA0-BBED-4F8B-A88E-1DD97B04E58F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C327AA0-BBED-4F8B-A88E-1DD97B04E58F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B417D97C-330A-42CE-BDC6-93355B0A959A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B417D97C-330A-42CE-BDC6-93355B0A959A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B417D97C-330A-42CE-BDC6-93355B0A959A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B417D97C-330A-42CE-BDC6-93355B0A959A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {38EF3EC8-9915-4216-B646-4BEE07006943}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {38EF3EC8-9915-4216-B646-4BEE07006943}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {38EF3EC8-9915-4216-B646-4BEE07006943}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {38EF3EC8-9915-4216-B646-4BEE07006943}.Release|Any CPU.Build.0 = Release|Any CPU
+ {65FB5893-7CB6-4694-A692-7E666E347D29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {65FB5893-7CB6-4694-A692-7E666E347D29}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {65FB5893-7CB6-4694-A692-7E666E347D29}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {65FB5893-7CB6-4694-A692-7E666E347D29}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -870,6 +888,9 @@ Global
{A5B650AB-A67F-4A4C-9F81-7B5471CA1331} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8}
{D9455AE7-2E0C-4647-9880-F5831BCEE3D8} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8}
{8C327AA0-BBED-4F8B-A88E-1DD97B04E58F} = {37087D1B-3693-4E96-983D-A69F210BDE53}
+ {B417D97C-330A-42CE-BDC6-93355B0A959A} = {37087D1B-3693-4E96-983D-A69F210BDE53}
+ {38EF3EC8-9915-4216-B646-4BEE07006943} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8}
+ {65FB5893-7CB6-4694-A692-7E666E347D29} = {37087D1B-3693-4E96-983D-A69F210BDE53}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}
diff --git a/src/Volo.Abp.Caching/Volo.Abp.Caching.csproj b/src/Volo.Abp.Caching/Volo.Abp.Caching.csproj
index f588132fd6..e8779ef390 100644
--- a/src/Volo.Abp.Caching/Volo.Abp.Caching.csproj
+++ b/src/Volo.Abp.Caching/Volo.Abp.Caching.csproj
@@ -19,6 +19,7 @@
+
diff --git a/src/Volo.Abp.Caching/Volo.Abp.Caching.csproj.DotSettings b/src/Volo.Abp.Caching/Volo.Abp.Caching.csproj.DotSettings
new file mode 100644
index 0000000000..58ad6c8854
--- /dev/null
+++ b/src/Volo.Abp.Caching/Volo.Abp.Caching.csproj.DotSettings
@@ -0,0 +1,2 @@
+
+ CSharp71
\ No newline at end of file
diff --git a/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs b/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs
index 114f093812..aca65dd1f3 100644
--- a/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs
+++ b/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs
@@ -1,8 +1,10 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
+using Volo.Abp.Threading;
namespace Volo.Abp.Caching
{
+ [DependsOn(typeof(AbpThreadingModule))]
public class AbpCachingModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
@@ -11,6 +13,8 @@ namespace Volo.Abp.Caching
services.AddDistributedMemoryCache();
services.AddAssemblyOf();
+
+ services.AddSingleton(typeof(IDistributedCache<>), typeof(DistributedCache<>));
}
}
}
diff --git a/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs b/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs
new file mode 100644
index 0000000000..78bfd77cf0
--- /dev/null
+++ b/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Caching.Distributed;
+using Volo.Abp.Threading;
+
+namespace Volo.Abp.Caching
+{
+ public class DistributedCache : IDistributedCache
+ where TCacheItem : class
+ {
+ protected IDistributedCache Cache { get; }
+
+ public ICancellationTokenProvider CancellationTokenProvider { get; }
+
+ public DistributedCache(
+ IDistributedCache cache,
+ ICancellationTokenProvider cancellationTokenProvider)
+ {
+ Cache = cache;
+ CancellationTokenProvider = cancellationTokenProvider;
+ }
+
+ public async Task GetAsync(string key, CancellationToken token = default)
+ {
+ var cachedValue = await Cache.GetAsync(key, CancellationTokenProvider.FallbackToProvider(token));
+ if (cachedValue == null)
+ {
+ return null;
+ }
+
+ throw new NotImplementedException();
+ }
+
+ public Task SetAsync(string key, TCacheItem value, DistributedCacheEntryOptions options = null,
+ CancellationToken token = default)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public Task RemoveAsync(string key, CancellationToken token = default)
+ {
+ return Cache.RemoveAsync(key, CancellationTokenProvider.FallbackToProvider(token));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs b/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs
new file mode 100644
index 0000000000..e6da33bf67
--- /dev/null
+++ b/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs
@@ -0,0 +1,28 @@
+using System.Threading;
+using System.Threading.Tasks;
+using JetBrains.Annotations;
+using Microsoft.Extensions.Caching.Distributed;
+
+namespace Volo.Abp.Caching
+{
+ public interface IDistributedCache
+ where TCacheItem : class
+ {
+ Task GetAsync(
+ [NotNull] string key,
+ CancellationToken token = default
+ );
+
+ Task SetAsync(
+ [NotNull] string key,
+ [NotNull] TCacheItem value,
+ [CanBeNull] DistributedCacheEntryOptions options = null,
+ CancellationToken token = default
+ );
+
+ Task RemoveAsync(
+ string key,
+ CancellationToken token = default
+ );
+ }
+}
diff --git a/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/PermissionStore.cs b/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/PermissionStore.cs
index 2b84b3e8e5..ab8bc997cc 100644
--- a/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/PermissionStore.cs
+++ b/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/PermissionStore.cs
@@ -11,6 +11,7 @@ using Volo.Abp.Threading;
namespace Volo.Abp.Permissions
{
+ //TODO: Extract cache invalidate logic to another class
public class PermissionStore : AbpServiceBase, IPermissionStore, IAsyncEventHandler>, ITransientDependency
{
private readonly IPermissionGrantRepository _permissionGrantRepository;
diff --git a/src/Volo.Abp.Serialization/Volo.Abp.Serialization.csproj b/src/Volo.Abp.Serialization/Volo.Abp.Serialization.csproj
new file mode 100644
index 0000000000..b981aed64e
--- /dev/null
+++ b/src/Volo.Abp.Serialization/Volo.Abp.Serialization.csproj
@@ -0,0 +1,20 @@
+
+
+
+
+
+ netstandard2.0
+ Volo.Abp.Serialization
+ Volo.Abp.Serialization
+ $(AssetTargetFallback);portable-net45+win8+wp8+wpa81;
+ false
+ false
+ false
+
+
+
+
+
+
+
+
diff --git a/src/Volo.Abp.Serialization/Volo.Abp.Serialization.csproj.DotSettings b/src/Volo.Abp.Serialization/Volo.Abp.Serialization.csproj.DotSettings
new file mode 100644
index 0000000000..58ad6c8854
--- /dev/null
+++ b/src/Volo.Abp.Serialization/Volo.Abp.Serialization.csproj.DotSettings
@@ -0,0 +1,2 @@
+
+ CSharp71
\ No newline at end of file
diff --git a/src/Volo.Abp.Serialization/Volo/Abp/Serialization/AbpSerializationModule.cs b/src/Volo.Abp.Serialization/Volo/Abp/Serialization/AbpSerializationModule.cs
new file mode 100644
index 0000000000..e32cce6d64
--- /dev/null
+++ b/src/Volo.Abp.Serialization/Volo/Abp/Serialization/AbpSerializationModule.cs
@@ -0,0 +1,28 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.Modularity;
+using Volo.Abp.Reflection;
+
+namespace Volo.Abp.Serialization
+{
+ public class AbpSerializationModule : AbpModule
+ {
+ public override void PreConfigureServices(IServiceCollection services)
+ {
+ services.OnExposing(context =>
+ {
+ //Register types for IObjectSerializer if implements
+ context.ExposedTypes.AddRange(
+ ReflectionHelper.GetImplementedGenericTypes(
+ context.ImplementationType,
+ typeof(IObjectSerializer<>)
+ )
+ );
+ });
+ }
+
+ public override void ConfigureServices(IServiceCollection services)
+ {
+ services.AddAssemblyOf();
+ }
+ }
+}
diff --git a/src/Volo.Abp.Serialization/Volo/Abp/Serialization/Binary/BinarySerializationHelper.cs b/src/Volo.Abp.Serialization/Volo/Abp/Serialization/Binary/BinarySerializationHelper.cs
new file mode 100644
index 0000000000..31a9ff280b
--- /dev/null
+++ b/src/Volo.Abp.Serialization/Volo/Abp/Serialization/Binary/BinarySerializationHelper.cs
@@ -0,0 +1,126 @@
+using System;
+using System.IO;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
+
+namespace Volo.Abp.Serialization.Binary
+{
+ ///
+ /// This class is used to simplify serialization/deserialization operations.
+ /// Uses .NET binary serialization.
+ ///
+ public static class BinarySerializationHelper
+ {
+ ///
+ /// Serializes an object and returns as a byte array.
+ ///
+ /// object to be serialized
+ /// bytes of object
+ public static byte[] Serialize(object obj)
+ {
+ using (var memoryStream = new MemoryStream())
+ {
+ Serialize(obj, memoryStream);
+ return memoryStream.ToArray();
+ }
+ }
+
+ ///
+ /// Serializes an object into a stream.
+ ///
+ /// object to be serialized
+ /// Stream to serialize in
+ /// bytes of object
+ public static void Serialize(object obj, Stream stream)
+ {
+ CreateBinaryFormatter().Serialize(stream, obj);
+ }
+
+ ///
+ /// Deserializes an object from given byte array.
+ ///
+ /// The byte array that contains object
+ /// deserialized object
+ public static object Deserialize(byte[] bytes)
+ {
+ using (var memoryStream = new MemoryStream(bytes))
+ {
+ return Deserialize(memoryStream);
+ }
+ }
+
+ ///
+ /// Deserializes an object from given stream.
+ ///
+ /// The stream that contains object
+ /// deserialized object
+ public static object Deserialize(Stream stream)
+ {
+ return CreateBinaryFormatter().Deserialize(stream);
+ }
+
+ ///
+ /// Deserializes an object from given byte array.
+ /// Difference from is that; this method can also deserialize
+ /// types that are defined in dynamically loaded assemblies (like PlugIns).
+ ///
+ /// The byte array that contains object
+ /// deserialized object
+ public static object DeserializeExtended(byte[] bytes)
+ {
+ using (var memoryStream = new MemoryStream(bytes))
+ {
+ return CreateBinaryFormatter(true).Deserialize(memoryStream);
+ }
+ }
+
+ ///
+ /// Deserializes an object from given stream.
+ /// Difference from is that; this method can also deserialize
+ /// types that are defined in dynamically loaded assemblies (like PlugIns).
+ ///
+ /// The stream that contains object
+ /// deserialized object
+ public static object DeserializeExtended(Stream stream)
+ {
+ return CreateBinaryFormatter(true).Deserialize(stream);
+ }
+
+ private static BinaryFormatter CreateBinaryFormatter(bool extended = false)
+ {
+ if (extended)
+ {
+ return new BinaryFormatter
+ {
+ //TODO: AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
+ Binder = new ExtendedSerializationBinder()
+ };
+ }
+ else
+ {
+ return new BinaryFormatter();
+ }
+ }
+
+ ///
+ /// This class is used in deserializing to allow deserializing objects that are defined
+ /// in assemlies that are load in runtime (like PlugIns).
+ ///
+ private sealed class ExtendedSerializationBinder : SerializationBinder
+ {
+ public override Type BindToType(string assemblyName, string typeName)
+ {
+ var toAssemblyName = assemblyName.Split(',')[0];
+ foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ if (assembly.FullName.Split(',')[0] == toAssemblyName)
+ {
+ return assembly.GetType(typeName);
+ }
+ }
+
+ return Type.GetType(string.Format("{0}, {1}", typeName, assemblyName));
+ }
+ }
+ }
+}
diff --git a/src/Volo.Abp.Serialization/Volo/Abp/Serialization/DefaultObjectSerializer.cs b/src/Volo.Abp.Serialization/Volo/Abp/Serialization/DefaultObjectSerializer.cs
new file mode 100644
index 0000000000..009fab9fb2
--- /dev/null
+++ b/src/Volo.Abp.Serialization/Volo/Abp/Serialization/DefaultObjectSerializer.cs
@@ -0,0 +1,69 @@
+using System;
+using JetBrains.Annotations;
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Serialization.Binary;
+
+namespace Volo.Abp.Serialization
+{
+ public class DefaultObjectSerializer : IObjectSerializer, ITransientDependency
+ {
+ private readonly IServiceProvider _serviceProvider;
+
+ public DefaultObjectSerializer(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ }
+
+ public virtual byte[] Serialize(T obj)
+ {
+ if (obj == null)
+ {
+ return null;
+ }
+
+ //Check if a specific serializer is registered
+ using (var scope = _serviceProvider.CreateScope())
+ {
+ var specificSerializer = scope.ServiceProvider.GetService>();
+ if (specificSerializer != null)
+ {
+ return specificSerializer.Serialize(obj);
+ }
+ }
+
+ return AutoSerialize(obj);
+ }
+
+ [CanBeNull]
+ public virtual T Deserialize(byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ return default;
+ }
+
+ //Check if a specific serializer is registered
+ using (var scope = _serviceProvider.CreateScope())
+ {
+ var specificSerializer = scope.ServiceProvider.GetService>();
+ if (specificSerializer != null)
+ {
+ return specificSerializer.Deserialize(bytes);
+ }
+ }
+
+ return AutoDeserialize(bytes);
+ }
+
+ protected virtual byte[] AutoSerialize(T obj)
+ {
+ return BinarySerializationHelper.Serialize(obj);
+ }
+
+ protected virtual T AutoDeserialize(byte[] bytes)
+ {
+ return (T) BinarySerializationHelper.DeserializeExtended(bytes);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Volo.Abp.Serialization/Volo/Abp/Serialization/IObjectSerializer.cs b/src/Volo.Abp.Serialization/Volo/Abp/Serialization/IObjectSerializer.cs
new file mode 100644
index 0000000000..c8ba3ffc56
--- /dev/null
+++ b/src/Volo.Abp.Serialization/Volo/Abp/Serialization/IObjectSerializer.cs
@@ -0,0 +1,16 @@
+namespace Volo.Abp.Serialization
+{
+ public interface IObjectSerializer
+ {
+ byte[] Serialize(T obj);
+
+ T Deserialize(byte[] bytes);
+ }
+
+ public interface IObjectSerializer
+ {
+ byte[] Serialize(T obj);
+
+ T Deserialize(byte[] bytes);
+ }
+}
diff --git a/src/Volo.Abp/Volo.Abp.csproj b/src/Volo.Abp/Volo.Abp.csproj
index ced7db9c3c..ec47794004 100644
--- a/src/Volo.Abp/Volo.Abp.csproj
+++ b/src/Volo.Abp/Volo.Abp.csproj
@@ -24,6 +24,7 @@
+
diff --git a/src/Volo.Abp/Volo/Abp/AbpCommonModule.cs b/src/Volo.Abp/Volo/Abp/AbpCommonModule.cs
index 639e80fecc..9f4bb07e62 100644
--- a/src/Volo.Abp/Volo/Abp/AbpCommonModule.cs
+++ b/src/Volo.Abp/Volo/Abp/AbpCommonModule.cs
@@ -9,6 +9,7 @@ using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Security;
+using Volo.Abp.Serialization;
using Volo.Abp.Session;
using Volo.Abp.Settings;
using Volo.Abp.Validation;
@@ -29,6 +30,7 @@ namespace Volo.Abp
[DependsOn(typeof(AbpApiVersioningAbstractionsModule))]
[DependsOn(typeof(AbpMultiTenancyAbstractionsModule))]
[DependsOn(typeof(AbpCachingModule))]
+ [DependsOn(typeof(AbpSerializationModule))]
public class AbpCommonModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
diff --git a/test/Volo.Abp.Caching.Tests/Volo.Abp.Caching.Tests.csproj b/test/Volo.Abp.Caching.Tests/Volo.Abp.Caching.Tests.csproj
new file mode 100644
index 0000000000..65e3abae38
--- /dev/null
+++ b/test/Volo.Abp.Caching.Tests/Volo.Abp.Caching.Tests.csproj
@@ -0,0 +1,24 @@
+
+
+
+ netcoreapp2.0
+ latest
+ Volo.Abp.Caching.Tests
+ Volo.Abp.Caching.Tests
+ true
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/AbpCachingTestModule.cs b/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/AbpCachingTestModule.cs
new file mode 100644
index 0000000000..410c1c58bf
--- /dev/null
+++ b/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/AbpCachingTestModule.cs
@@ -0,0 +1,14 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.Modularity;
+
+namespace Volo.Abp.Caching
+{
+ [DependsOn(typeof(AbpCachingModule))]
+ public class AbpCachingTestModule : AbpModule
+ {
+ public override void ConfigureServices(IServiceCollection services)
+ {
+ services.AddAssemblyOf();
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs b/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs
new file mode 100644
index 0000000000..45f2b21da3
--- /dev/null
+++ b/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Threading.Tasks;
+using Shouldly;
+using Volo.Abp.TestBase;
+using Xunit;
+
+namespace Volo.Abp.Caching
+{
+ public class DistributedCache_Tests : AbpIntegratedTest
+ {
+ [Fact]
+ public async Task Should_Set_Get_And_Remove_Cache_Items()
+ {
+ var personCache = GetRequiredService>();
+
+ var cacheKey = Guid.NewGuid().ToString();
+ const string personName = "john nash";
+
+ //Get (not exists yet)
+ var cacheItem = await personCache.GetAsync(cacheKey);
+ cacheItem.ShouldBeNull();
+
+ //Set
+ cacheItem = new PersonCacheItem(personName);
+ await personCache.SetAsync(cacheKey, cacheItem);
+
+ //Get (it should be available now
+ cacheItem = await personCache.GetAsync(cacheKey);
+ cacheItem.ShouldNotBeNull();
+ cacheItem.Name.ShouldBe(personName);
+
+ //Remove
+ await personCache.RemoveAsync(cacheKey);
+
+ //Get (not exists since removed)
+ cacheItem = await personCache.GetAsync(cacheKey);
+ cacheItem.ShouldBeNull();
+ }
+ }
+}
diff --git a/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/PersonCacheItem.cs b/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/PersonCacheItem.cs
new file mode 100644
index 0000000000..a1011bc186
--- /dev/null
+++ b/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/PersonCacheItem.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Volo.Abp.Caching
+{
+ [Serializable]
+ public class PersonCacheItem
+ {
+ public string Name { get; private set; }
+
+ private PersonCacheItem()
+ {
+
+ }
+
+ public PersonCacheItem(string name)
+ {
+ Name = name;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Volo.Abp.Serialization.Tests/Volo.Abp.Serialization.Tests.csproj b/test/Volo.Abp.Serialization.Tests/Volo.Abp.Serialization.Tests.csproj
new file mode 100644
index 0000000000..d37bf44009
--- /dev/null
+++ b/test/Volo.Abp.Serialization.Tests/Volo.Abp.Serialization.Tests.csproj
@@ -0,0 +1,24 @@
+
+
+
+ netcoreapp2.0
+ latest
+ Volo.Abp.Serialization.Tests
+ Volo.Abp.Serialization.Tests
+ true
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/AbpSerializationTestModule.cs b/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/AbpSerializationTestModule.cs
new file mode 100644
index 0000000000..1204bc3f2f
--- /dev/null
+++ b/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/AbpSerializationTestModule.cs
@@ -0,0 +1,14 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.Modularity;
+
+namespace Volo.Abp.Serialization
+{
+ [DependsOn(typeof(AbpSerializationModule))]
+ public class AbpSerializationTestModule : AbpModule
+ {
+ public override void ConfigureServices(IServiceCollection services)
+ {
+ services.AddAssemblyOf();
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/ObjectSerializer_Tests.cs b/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/ObjectSerializer_Tests.cs
new file mode 100644
index 0000000000..5817c78c4e
--- /dev/null
+++ b/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/ObjectSerializer_Tests.cs
@@ -0,0 +1,38 @@
+using Shouldly;
+using Volo.Abp.Serialization.Objects;
+using Volo.Abp.TestBase;
+using Xunit;
+
+namespace Volo.Abp.Serialization
+{
+ public class ObjectSerializer_Tests : AbpIntegratedTest
+ {
+ private readonly IObjectSerializer _serializer;
+
+ public ObjectSerializer_Tests()
+ {
+ _serializer = GetRequiredService();
+ }
+
+ [Fact]
+ public void Should_Return_Null_For_Null_Object()
+ {
+ _serializer.Serialize(null).ShouldBeNull();
+ _serializer.Deserialize((byte[])null).ShouldBeNull();
+ }
+
+ [Fact]
+ public void Simple_Serialize_Deserialize()
+ {
+ _serializer.Deserialize(_serializer.Serialize(new Person("john"))).Name.ShouldBe("john");
+ }
+
+ [Fact]
+ public void Should_Use_Specific_Serializer_If_Available()
+ {
+ _serializer.Deserialize(_serializer.Serialize(new Car("xc40"))).Name.ShouldBe("xc40-serialized-deserialized");
+ }
+
+ //TODO: Other methods
+ }
+}
diff --git a/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/Objects/Car.cs b/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/Objects/Car.cs
new file mode 100644
index 0000000000..049c8cb91f
--- /dev/null
+++ b/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/Objects/Car.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Volo.Abp.Serialization.Objects
+{
+ [Serializable]
+ public class Car
+ {
+ public string Name { get; set; }
+
+ private Car()
+ {
+
+ }
+
+ public Car(string name)
+ {
+ Name = name;
+ }
+ }
+}
diff --git a/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/Objects/CarSerializer.cs b/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/Objects/CarSerializer.cs
new file mode 100644
index 0000000000..4c09a3ca93
--- /dev/null
+++ b/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/Objects/CarSerializer.cs
@@ -0,0 +1,21 @@
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Serialization.Binary;
+
+namespace Volo.Abp.Serialization.Objects
+{
+ public class CarSerializer : IObjectSerializer, ITransientDependency
+ {
+ public byte[] Serialize(Car obj)
+ {
+ obj.Name += "-serialized";
+ return BinarySerializationHelper.Serialize(obj);
+ }
+
+ public Car Deserialize(byte[] bytes)
+ {
+ var car = (Car)BinarySerializationHelper.DeserializeExtended(bytes);
+ car.Name += "-deserialized";
+ return car;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/Objects/Person.cs b/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/Objects/Person.cs
new file mode 100644
index 0000000000..2dcb4cf99e
--- /dev/null
+++ b/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/Objects/Person.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Volo.Abp.Serialization.Objects
+{
+ [Serializable]
+ public class Person
+ {
+ public string Name { get; private set; }
+
+ private Person()
+ {
+
+ }
+
+ public Person(string name)
+ {
+ Name = name;
+ }
+ }
+}