mirror of https://github.com/abpframework/abp.git
25 changed files with 605 additions and 3 deletions
@ -0,0 +1,2 @@ |
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> |
|||
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String></wpf:ResourceDictionary> |
|||
@ -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<TCacheItem> : IDistributedCache<TCacheItem> |
|||
where TCacheItem : class |
|||
{ |
|||
protected IDistributedCache Cache { get; } |
|||
|
|||
public ICancellationTokenProvider CancellationTokenProvider { get; } |
|||
|
|||
public DistributedCache( |
|||
IDistributedCache cache, |
|||
ICancellationTokenProvider cancellationTokenProvider) |
|||
{ |
|||
Cache = cache; |
|||
CancellationTokenProvider = cancellationTokenProvider; |
|||
} |
|||
|
|||
public async Task<TCacheItem> 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)); |
|||
} |
|||
} |
|||
} |
|||
@ -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<TCacheItem> |
|||
where TCacheItem : class |
|||
{ |
|||
Task<TCacheItem> 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 |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<AssemblyName>Volo.Abp.Serialization</AssemblyName> |
|||
<PackageId>Volo.Abp.Serialization</PackageId> |
|||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,2 @@ |
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> |
|||
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String></wpf:ResourceDictionary> |
|||
@ -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<T> if implements
|
|||
context.ExposedTypes.AddRange( |
|||
ReflectionHelper.GetImplementedGenericTypes( |
|||
context.ImplementationType, |
|||
typeof(IObjectSerializer<>) |
|||
) |
|||
); |
|||
}); |
|||
} |
|||
|
|||
public override void ConfigureServices(IServiceCollection services) |
|||
{ |
|||
services.AddAssemblyOf<AbpSerializationModule>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,126 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Runtime.Serialization; |
|||
using System.Runtime.Serialization.Formatters.Binary; |
|||
|
|||
namespace Volo.Abp.Serialization.Binary |
|||
{ |
|||
/// <summary>
|
|||
/// This class is used to simplify serialization/deserialization operations.
|
|||
/// Uses .NET binary serialization.
|
|||
/// </summary>
|
|||
public static class BinarySerializationHelper |
|||
{ |
|||
/// <summary>
|
|||
/// Serializes an object and returns as a byte array.
|
|||
/// </summary>
|
|||
/// <param name="obj">object to be serialized</param>
|
|||
/// <returns>bytes of object</returns>
|
|||
public static byte[] Serialize(object obj) |
|||
{ |
|||
using (var memoryStream = new MemoryStream()) |
|||
{ |
|||
Serialize(obj, memoryStream); |
|||
return memoryStream.ToArray(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Serializes an object into a stream.
|
|||
/// </summary>
|
|||
/// <param name="obj">object to be serialized</param>
|
|||
/// <param name="stream">Stream to serialize in</param>
|
|||
/// <returns>bytes of object</returns>
|
|||
public static void Serialize(object obj, Stream stream) |
|||
{ |
|||
CreateBinaryFormatter().Serialize(stream, obj); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Deserializes an object from given byte array.
|
|||
/// </summary>
|
|||
/// <param name="bytes">The byte array that contains object</param>
|
|||
/// <returns>deserialized object</returns>
|
|||
public static object Deserialize(byte[] bytes) |
|||
{ |
|||
using (var memoryStream = new MemoryStream(bytes)) |
|||
{ |
|||
return Deserialize(memoryStream); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Deserializes an object from given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream that contains object</param>
|
|||
/// <returns>deserialized object</returns>
|
|||
public static object Deserialize(Stream stream) |
|||
{ |
|||
return CreateBinaryFormatter().Deserialize(stream); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Deserializes an object from given byte array.
|
|||
/// Difference from <see cref="Deserialize(byte[])"/> is that; this method can also deserialize
|
|||
/// types that are defined in dynamically loaded assemblies (like PlugIns).
|
|||
/// </summary>
|
|||
/// <param name="bytes">The byte array that contains object</param>
|
|||
/// <returns>deserialized object</returns>
|
|||
public static object DeserializeExtended(byte[] bytes) |
|||
{ |
|||
using (var memoryStream = new MemoryStream(bytes)) |
|||
{ |
|||
return CreateBinaryFormatter(true).Deserialize(memoryStream); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Deserializes an object from given stream.
|
|||
/// Difference from <see cref="Deserialize(Stream)"/> is that; this method can also deserialize
|
|||
/// types that are defined in dynamically loaded assemblies (like PlugIns).
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream that contains object</param>
|
|||
/// <returns>deserialized object</returns>
|
|||
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(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This class is used in deserializing to allow deserializing objects that are defined
|
|||
/// in assemlies that are load in runtime (like PlugIns).
|
|||
/// </summary>
|
|||
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)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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>(T obj) |
|||
{ |
|||
if (obj == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
//Check if a specific serializer is registered
|
|||
using (var scope = _serviceProvider.CreateScope()) |
|||
{ |
|||
var specificSerializer = scope.ServiceProvider.GetService<IObjectSerializer<T>>(); |
|||
if (specificSerializer != null) |
|||
{ |
|||
return specificSerializer.Serialize(obj); |
|||
} |
|||
} |
|||
|
|||
return AutoSerialize(obj); |
|||
} |
|||
|
|||
[CanBeNull] |
|||
public virtual T Deserialize<T>(byte[] bytes) |
|||
{ |
|||
if (bytes == null) |
|||
{ |
|||
return default; |
|||
} |
|||
|
|||
//Check if a specific serializer is registered
|
|||
using (var scope = _serviceProvider.CreateScope()) |
|||
{ |
|||
var specificSerializer = scope.ServiceProvider.GetService<IObjectSerializer<T>>(); |
|||
if (specificSerializer != null) |
|||
{ |
|||
return specificSerializer.Deserialize(bytes); |
|||
} |
|||
} |
|||
|
|||
return AutoDeserialize<T>(bytes); |
|||
} |
|||
|
|||
protected virtual byte[] AutoSerialize<T>(T obj) |
|||
{ |
|||
return BinarySerializationHelper.Serialize(obj); |
|||
} |
|||
|
|||
protected virtual T AutoDeserialize<T>(byte[] bytes) |
|||
{ |
|||
return (T) BinarySerializationHelper.DeserializeExtended(bytes); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
namespace Volo.Abp.Serialization |
|||
{ |
|||
public interface IObjectSerializer |
|||
{ |
|||
byte[] Serialize<T>(T obj); |
|||
|
|||
T Deserialize<T>(byte[] bytes); |
|||
} |
|||
|
|||
public interface IObjectSerializer<T> |
|||
{ |
|||
byte[] Serialize(T obj); |
|||
|
|||
T Deserialize(byte[] bytes); |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netcoreapp2.0</TargetFramework> |
|||
<LangVersion>latest</LangVersion> |
|||
<AssemblyName>Volo.Abp.Caching.Tests</AssemblyName> |
|||
<PackageId>Volo.Abp.Caching.Tests</PackageId> |
|||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.Caching\Volo.Abp.Caching.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -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<AbpCachingTestModule>(); |
|||
} |
|||
} |
|||
} |
|||
@ -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<AbpCachingTestModule> |
|||
{ |
|||
[Fact] |
|||
public async Task Should_Set_Get_And_Remove_Cache_Items() |
|||
{ |
|||
var personCache = GetRequiredService<IDistributedCache<PersonCacheItem>>(); |
|||
|
|||
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(); |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netcoreapp2.0</TargetFramework> |
|||
<LangVersion>latest</LangVersion> |
|||
<AssemblyName>Volo.Abp.Serialization.Tests</AssemblyName> |
|||
<PackageId>Volo.Abp.Serialization.Tests</PackageId> |
|||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.Serialization\Volo.Abp.Serialization.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -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<AbpSerializationTestModule>(); |
|||
} |
|||
} |
|||
} |
|||
@ -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<AbpSerializationTestModule> |
|||
{ |
|||
private readonly IObjectSerializer _serializer; |
|||
|
|||
public ObjectSerializer_Tests() |
|||
{ |
|||
_serializer = GetRequiredService<IObjectSerializer>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Return_Null_For_Null_Object() |
|||
{ |
|||
_serializer.Serialize<Person>(null).ShouldBeNull(); |
|||
_serializer.Deserialize<Person>((byte[])null).ShouldBeNull(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Simple_Serialize_Deserialize() |
|||
{ |
|||
_serializer.Deserialize<Person>(_serializer.Serialize(new Person("john"))).Name.ShouldBe("john"); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Use_Specific_Serializer_If_Available() |
|||
{ |
|||
_serializer.Deserialize<Car>(_serializer.Serialize(new Car("xc40"))).Name.ShouldBe("xc40-serialized-deserialized"); |
|||
} |
|||
|
|||
//TODO: Other methods
|
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Serialization.Binary; |
|||
|
|||
namespace Volo.Abp.Serialization.Objects |
|||
{ |
|||
public class CarSerializer : IObjectSerializer<Car>, 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; |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue