Skip to content

Commit

Permalink
Add JSON, MessagePack and BinaryFormatter Serializer (#15)
Browse files Browse the repository at this point in the history
* Add JSON, MessagePack and BinaryFormatter Serializer
* Added ISerializer class to allow users to extend with additional serializers.
* Clean up Codacy static analysis errors
* Remove BinaryFotmatterObjectSerializer
  • Loading branch information
gregyjames authored Nov 30, 2024
1 parent 91c6a0e commit b561e91
Show file tree
Hide file tree
Showing 12 changed files with 116 additions and 20 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ static class Program

builder.Populate(services);

//Register an object Serializer
builder.RegisterType<MessagePackObjectSerializer>().As<IObjectSerializer>();

//Register the Redis Connection as single instance
builder.RegisterType<RedisConnectionManager>().SingleInstance();

Expand Down
8 changes: 6 additions & 2 deletions gj.autofac.caching.redis.tester/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Autofac.Extras.DynamicProxy;
using gj.autofac.caching.redis.Serialization;
using MessagePack;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -45,6 +47,8 @@ static Task Main()

builder.Populate(services);

builder.RegisterType<MessagePackObjectSerializer>().As<IObjectSerializer>();

//Register the Redis Connection as single instance
builder.RegisterType<RedisConnectionManager>().SingleInstance();

Expand All @@ -59,15 +63,15 @@ static Task Main()
var service = container.Resolve<IExampleService>();
var logger = container.Resolve<ILogger<ExampleService>>();

var id = 3;
var id = 16;

for (var i = 0; i < 5; i++)
{
TimeAndRun(async () => await service.AsyncFunctionTest(id), logger);
}
for (var i = 0; i < 5; i++)
{
TimeAndRun(async () => await service.AsyncActionTest(50), logger);
TimeAndRun(async () => await service.AsyncActionTest(id), logger);
}
for (var i = 0; i < 5; i++)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using gj.autofac.caching.redis;
using gj.autofac.caching.redis.Serialization;

namespace gj.autofac.caching.redis.tests;

[TestFixture]
[TestOf(typeof(BinaryFormatterUtils))]
public class BinaryFormatterUtilsTest
[TestOf(typeof(MessagePackObjectSerializer))]
public class JSONObjectSerializerTest
{
private TestData _data;
private JSONObjectSerializer _objectSerializer;

[SetUp]
public void Setup()
Expand All @@ -18,20 +20,21 @@ public void Setup()
Title = "TEST",
Completed = true
};
_objectSerializer = new JSONObjectSerializer();
}

[Test]
public void SerializationTest()
{
var arr = BinaryFormatterUtils.SerializeToBinary(_data);
var arr = _objectSerializer.SerializeToBinary(_data);
Assert.That(arr, Is.Not.Empty);
}

[Test]
public void DeserializationTest()
{
var arr = BinaryFormatterUtils.SerializeToBinary(_data);
var data2 = (TestData)BinaryFormatterUtils.DeserializeFromBinary(arr, typeof(TestData))!;
var arr = _objectSerializer.SerializeToBinary(_data);
var data2 = (TestData)_objectSerializer.DeserializeFromBinary(arr, typeof(TestData))!;
Assert.That(data2.Id, Is.EqualTo(8));
Assert.That(data2.UserId, Is.EqualTo(8));
Assert.That(data2.Title, Is.EqualTo("TEST"));
Expand Down
43 changes: 43 additions & 0 deletions gj.autofac.caching.redis.tests/MessagePackObjectSerializerTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using gj.autofac.caching.redis;
using gj.autofac.caching.redis.Serialization;

namespace gj.autofac.caching.redis.tests;

[TestFixture]
[TestOf(typeof(MessagePackObjectSerializer))]
public class MessagePackObjectSerializerTest
{
private TestData _data;
private MessagePackObjectSerializer _objectSerializer;

[SetUp]
public void Setup()
{
_data = new TestData
{
Id = 8,
UserId = 8,
Title = "TEST",
Completed = true
};
_objectSerializer = new MessagePackObjectSerializer();
}

[Test]
public void SerializationTest()
{
var arr = _objectSerializer.SerializeToBinary(_data);
Assert.That(arr, Is.Not.Empty);
}

[Test]
public void DeserializationTest()
{
var arr = _objectSerializer.SerializeToBinary(_data);
var data2 = (TestData)_objectSerializer.DeserializeFromBinary(arr, typeof(TestData))!;
Assert.That(data2.Id, Is.EqualTo(8));
Assert.That(data2.UserId, Is.EqualTo(8));
Assert.That(data2.Title, Is.EqualTo("TEST"));
Assert.That(data2.Completed, Is.True);
}
}
1 change: 1 addition & 0 deletions gj.autofac.caching.redis.tests/TestData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace gj.autofac.caching.redis.tests;

[MessagePackObject(keyAsPropertyName: true)]
[Serializable]
public class TestData
{
[JsonPropertyName("userId")]
Expand Down
3 changes: 3 additions & 0 deletions gj.autofac.caching.redis.tests/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Autofac.Extras.DynamicProxy;
using gj.autofac.caching.redis.Serialization;
using gj.autofac.caching.redis.tests.MockObjects;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -43,6 +44,8 @@ public void Setup()

//Register the Redis Connection as single instance
builder.Register<IConnectionMultiplexer>(_ => new MockMultiplexer()).As<IConnectionMultiplexer>();

builder.RegisterType<MessagePackObjectSerializer>().As<IObjectSerializer>();

builder.RegisterType<RedisConnectionManager>().SingleInstance();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
</PropertyGroup>

<ItemGroup>
Expand Down
11 changes: 6 additions & 5 deletions gj.autofac.caching.redis/RedisCacheInterceptor.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System.Reflection;
using Castle.DynamicProxy;
using gj.autofac.caching.redis.Serialization;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;

namespace gj.autofac.caching.redis;

public class RedisCacheInterceptor(ILogger<RedisCacheInterceptor> logger, RedisConnectionManager manager) : IInterceptor
public class RedisCacheInterceptor(ILogger<RedisCacheInterceptor> logger, RedisConnectionManager manager, IObjectSerializer serializer) : IInterceptor
{
private readonly IDatabase _redis = manager.Database; // Ensure this is properly initialized elsewhere

Expand Down Expand Up @@ -96,10 +97,10 @@ public void Intercept(IInvocation invocation)
}
}

private static void SetReturnValue(IInvocation invocation, RedisValue cachedValue, Type returnType)
private void SetReturnValue(IInvocation invocation, RedisValue cachedValue, Type returnType)
{
// Deserialize using the provided returnType
var value = BinaryFormatterUtils.DeserializeFromBinary(cachedValue!, returnType);
var value = serializer.DeserializeFromBinary(cachedValue!, returnType);

if (typeof(Task).IsAssignableFrom(invocation.Method.ReturnType))
{
Expand All @@ -122,7 +123,7 @@ private void HandleSyncMethod(IInvocation invocation, string cacheKey, int expir
invocation.Proceed();

// Serialize and cache the result
var serializedValue = BinaryFormatterUtils.SerializeToBinary(invocation.ReturnValue);
var serializedValue = serializer.SerializeToBinary(invocation.ReturnValue);
_redis.StringSet(cacheKey, serializedValue, TimeSpan.FromSeconds(expirationSeconds));
logger.LogDebug("[CACHE SET] {0}", cacheKey);
}
Expand All @@ -145,7 +146,7 @@ private void HandleSyncMethod(IInvocation invocation, string cacheKey, int expir
var resultProperty = task.GetType().GetProperty("Result");
var taskValue = resultProperty?.GetValue(task);

var serializedValue = BinaryFormatterUtils.SerializeToBinary(taskValue);
var serializedValue = serializer.SerializeToBinary(taskValue);
await _redis.StringSetAsync(cacheKey, serializedValue, TimeSpan.FromSeconds(expirationSeconds));

logger.LogDebug("[CACHE SET] {0}", cacheKey);
Expand Down
7 changes: 7 additions & 0 deletions gj.autofac.caching.redis/Serialization/IObjectSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace gj.autofac.caching.redis.Serialization;

public interface IObjectSerializer
{
public byte[] SerializeToBinary(object? obj);
public object? DeserializeFromBinary(byte[] binaryData, Type type);
}
29 changes: 29 additions & 0 deletions gj.autofac.caching.redis/Serialization/JSONObjectSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Text;
using Newtonsoft.Json;

namespace gj.autofac.caching.redis.Serialization;

public class JSONObjectSerializer: IObjectSerializer
{
/// <summary>
/// Serializes an object to binary using JSON.
/// </summary>
/// <param name="obj">The object to serialize.</param>
/// <returns>The binary representation of the object.</returns>
public byte[] SerializeToBinary(object? obj)
{
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(obj));
}

/// <summary>
/// Deserializes binary data to the specified type using JSON.
/// </summary>
/// <param name="binaryData">The binary data to deserialize.</param>
/// <param name="type">The type to deserialize into.</param>
/// <returns>The deserialized object.</returns>
public object? DeserializeFromBinary(byte[] binaryData, Type type)
{
string resultString = Encoding.UTF8.GetString(binaryData);
return JsonConvert.DeserializeObject(resultString, type);
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
using MessagePack;
namespace gj.autofac.caching.redis.Serialization;

namespace gj.autofac.caching.redis;

internal static class BinaryFormatterUtils
public class MessagePackObjectSerializer: IObjectSerializer
{
/// <summary>
/// Serializes an object to binary using MessagePack.
/// </summary>
/// <param name="obj">The object to serialize.</param>
/// <returns>The binary representation of the object.</returns>
internal static byte[] SerializeToBinary(object? obj)
public byte[] SerializeToBinary(object? obj)
{
if (obj == null)
{
throw new ArgumentNullException(nameof(obj));
}

// Serialize the object using MessagePack
return MessagePackSerializer.Serialize(obj);
return MessagePack.MessagePackSerializer.Serialize(obj);
}

/// <summary>
Expand All @@ -26,7 +24,7 @@ internal static byte[] SerializeToBinary(object? obj)
/// <param name="binaryData">The binary data to deserialize.</param>
/// <param name="type">The type to deserialize into.</param>
/// <returns>The deserialized object.</returns>
internal static object? DeserializeFromBinary(byte[] binaryData, Type type)
public object? DeserializeFromBinary(byte[] binaryData, Type type)
{
if (binaryData == null || binaryData.Length == 0)
{
Expand All @@ -39,6 +37,6 @@ internal static byte[] SerializeToBinary(object? obj)
}

// Deserialize the object using MessagePack
return MessagePackSerializer.Deserialize(type, binaryData);
return MessagePack.MessagePackSerializer.Deserialize(type, binaryData);
}
}
3 changes: 3 additions & 0 deletions gj.autofac.caching.redis/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ static class Program

builder.Populate(services);

//Register an object Serializer to use
builder.RegisterType<MessagePackObjectSerializer>().As<IObjectSerializer>();

//Register the Redis Connection as single instance
builder.RegisterType<RedisConnectionManager>().SingleInstance();

Expand Down

0 comments on commit b561e91

Please sign in to comment.