Created
August 9, 2018 19:16
-
-
Save GeorgeTsiokos/bb7ae7e94aa70bb2e7f8180fd86422ce to your computer and use it in GitHub Desktop.
Another Serializer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
protected override void Load(ContainerBuilder builder) | |
{ | |
builder.RegisterType<Serializer>().Named<ISerializer>(nameof(Serializer)).SingleInstance(); | |
builder.RegisterType<LoggingSerializer>().As<ISerializer>().SingleInstance().WithAttributeFiltering(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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