Skip to content

Instantly share code, notes, and snippets.

@GeorgeTsiokos
Created August 9, 2018 19:16
Show Gist options
  • Save GeorgeTsiokos/bb7ae7e94aa70bb2e7f8180fd86422ce to your computer and use it in GitHub Desktop.
Save GeorgeTsiokos/bb7ae7e94aa70bb2e7f8180fd86422ce to your computer and use it in GitHub Desktop.
Another Serializer
public interface ISerializer
{
bool TryDeserialize<T>([CanBeNull] byte[] value, [CanBeNull] out T result) where T : class;
bool TrySerialize<T>([CanBeNull] T value, [NotNull] out byte[] result, bool compress = false) where T : class;
}
internal sealed class LoggingSerializer : ISerializer
{
readonly ILogger<Serializer> _logger;
readonly ISerializer _serializer;
public LoggingSerializer(ILoggerFactory loggerFactory, [KeyFilter(nameof(Serializer))] ISerializer serializer)
{
_logger = loggerFactory.CreateLogger<Serializer>();
_serializer = serializer;
}
public bool TryDeserialize<T>(byte[] value, out T result) where T : class
{
try
{
return _serializer.TryDeserialize(value, out result);
}
catch (Exception exception)
{
_logger.LogWarning(exception, nameof(TryDeserialize));
result = default;
return false;
}
}
public bool TrySerialize<T>(T value, out byte[] result, bool compress = false) where T : class
{
{
try
{
return _serializer.TrySerialize(value, out result, compress);
}
catch (Exception exception)
{
_logger.LogWarning(exception, nameof(TrySerialize));
result = null;
return false;
}
}
}
}
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<Serializer>().Named<ISerializer>(nameof(Serializer)).SingleInstance();
builder.RegisterType<LoggingSerializer>().As<ISerializer>().SingleInstance().WithAttributeFiltering();
}
[DebuggerNonUserCode]
internal sealed class Serializer : ISerializer
{
readonly IMemoryCache _memoryCache;
CompressionLevel _compressionLevel;
public Serializer(IMemoryCache memoryCache, CompressionLevel compressionLevel = CompressionLevel.Optimal)
{
_memoryCache = memoryCache;
_compressionLevel = compressionLevel;
}
public bool TryDeserialize<T>(byte[] value, out T result) where T : class
{
if (null == value)
{
result = default;
return false;
}
if (value.Length == 0)
{
result = default;
}
else
{
var serializer = GetSerializer<T>();
using (var memoryStream = new MemoryStream(value, false))
{
var prefix = memoryStream.ReadByte();
switch (prefix)
{
case 48:
result = Deserialize<T>(serializer, memoryStream);
break;
case 49:
using (var brotliStream = new BrotliStream(memoryStream, CompressionMode.Decompress))
{
result = Deserialize<T>(serializer, brotliStream);
}
break;
default:
throw new Exception("Unexpected first byte value " + prefix);
}
}
}
return true;
}
private static T Deserialize<T>([NotNull] XmlObjectSerializer serializer, Stream stream) => (T)serializer.ReadObject(stream);
private XmlObjectSerializer GetSerializer<T>()
{
XmlObjectSerializer Factory(ICacheEntry entry) => new DataContractJsonSerializer(typeof(T));
return _memoryCache.GetOrCreate(typeof(T), Factory);
}
public bool TrySerialize<T>(T value, out byte[] result, bool compress = false) where T : class
{
if (null == value)
{
result = new byte[0];
}
else
{
var compressionLevel = compress ? _compressionLevel : CompressionLevel.NoCompression;
var serializer = GetSerializer<T>();
using (var memoryStream = new MemoryStream())
{
memoryStream.WriteByte(compress ? (byte)49 : (byte)48);
if (compress)
using (var brotliStream = new BrotliStream(memoryStream, compressionLevel, true))
{
Serialize(value, serializer, brotliStream);
}
else
{
Serialize(value, serializer, memoryStream);
}
result = memoryStream.ToArray();
}
}
return true;
}
private static void Serialize<T>(T value, [NotNull] XmlObjectSerializer serializer, Stream stream) where T : class => serializer.WriteObject(stream, value);
}
public static class SerializerExtensions
{
[CanBeNull]
public static T Deserialize<T>([NotNull] this ISerializer serializer, [CanBeNull] byte[] value) where T : class => serializer.TryDeserialize<T>(value, out var result) ? result : null;
[CanBeNull]
public static byte[] Serialize<T>([NotNull] this ISerializer serializer, [CanBeNull] T value, bool compress = false) where T : class => serializer.TrySerialize(value, out var result, compress) ? result : null;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment