-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
I have a class hierarchy with a base type and some derived types which I want to send through SignalR and use MessagePack format with compression. I added a reference to the Microsoft.AspNetCore.SignalR.Protocols.MessagePack to setup this configuration.
I have implemented MessagePack formatters to serialize my types and resolve the concrete type during deserialization.
The problem is that when I use MessagePackCompression.Lz4BlockArray
, deserialization throws an error.
I tried the the below test with the latest MessagePack version (currently 2.4.59), it does not throw the error, but Microsoft.AspNetCore.SignalR.Protocols.MessagePack references an earlier MessagePack version (2.1.90), and if the project only has the MessagePack reference through the AspNetCore nuget, it throws an error.
Is there a chance to upgrade the referenced MessagePack version in the Microsoft.AspNetCore.SignalR.Protocols.MessagePack project?
Expected Behavior
All tests should be green, regardless of compression type.
Steps To Reproduce
Code:
using MessagePack;
using MessagePack.Formatters;
using MessagePack.Resolvers;
using NUnit.Framework;
namespace MessagePackTest;
public class Tests
{
[TestCase(MessagePack.MessagePackCompression.None)]
[TestCase(MessagePack.MessagePackCompression.Lz4Block)]
[TestCase(MessagePack.MessagePackCompression.Lz4BlockArray)]
public void TestSerializationWithStandardOptions(MessagePackCompression compression)
{
Base instance = new Derived
{
Name = "Test Data"
};
TestSerialization(instance, MessagePackSerializerOptions.Standard, compression);
}
[TestCase(MessagePack.MessagePackCompression.None)]
[TestCase(MessagePack.MessagePackCompression.Lz4Block)]
[TestCase(MessagePack.MessagePackCompression.Lz4BlockArray)]
public void TestSerializationWithAspNetOptions(MessagePackCompression compression)
{
Base instance = new Derived
{
Name = "Test Data"
};
var options = new Microsoft.AspNetCore.SignalR.MessagePackHubProtocolOptions().SerializerOptions;
TestSerialization(instance, options, compression);
}
private static void TestSerialization<T>(T instance, MessagePackSerializerOptions options, MessagePackCompression compression)
{
options = options.WithResolver
(
CompositeResolver.Create(
new IMessagePackFormatter[] {
new BaseFormatter(),
new DerivedFormatter(),
},
new[]
{
options.Resolver
})
);
options = options
.WithCompression(compression);
var bytes = MessagePackSerializer.Serialize<T>(instance, options);
var deserialized = MessagePackSerializer.Deserialize<T>(bytes, options);
Assert.NotNull(deserialized);
}
}
public class BaseFormatter : IMessagePackFormatter<Base>
{
public Base Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
var typeName = options.Resolver.GetFormatterWithVerify<string>().Deserialize(ref reader, options);
var type = typeof(Base).Assembly.GetType(typeName);
var result = (Base)Activator.CreateInstance(type)!;
// ... Fill properties
return result;
}
public void Serialize(ref MessagePackWriter writer, Base value, MessagePackSerializerOptions options)
{
var type = value.GetType();
if (type == typeof(Base))
{
options.Resolver.GetFormatterWithVerify<string>().Serialize(ref writer, value.Type, options);
}
else
{
MessagePackSerializer.Serialize(type, ref writer, value, options);
}
}
}
public class DerivedFormatter : IMessagePackFormatter<Derived>
{
public Derived Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
return new()
{
Type = options.Resolver.GetFormatterWithVerify<string>().Deserialize(ref reader, options),
Name = options.Resolver.GetFormatterWithVerify<string>().Deserialize(ref reader, options),
};
}
public void Serialize(ref MessagePackWriter writer, Derived value, MessagePackSerializerOptions options)
{
options.Resolver.GetFormatterWithVerify<string>().Serialize(ref writer, value.Type, options);
options.Resolver.GetFormatterWithVerify<string>().Serialize(ref writer, value.Name, options);
}
}
public class Base
{
public string? Type { get; set; } = typeof(Base).FullName;
}
public class Derived : Base
{
public string? Name { get; set; }
public Derived()
{
Type = typeof(Derived).FullName;
}
}
csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<!--<PackageReference Include="MessagePack" Version="2.4.59" />-->
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="7.0.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit.Analyzers" Version="3.3.0" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
</ItemGroup>
</Project>
Exceptions (if any)
TestSerializationWithAspNetOptions(Lz4BlockArray)
Source: UnitTest1.cs line 25
Duration: 20 ms
Message:
MessagePack.MessagePackSerializationException : Failed to deserialize MessagePackTest.Base value.
----> MessagePack.MessagePackSerializationException : Unexpected msgpack code 146 (fixarray) encountered.
Stack Trace:
MessagePackSerializer.Deserialize[T](MessagePackReader& reader, MessagePackSerializerOptions options)
MessagePackSerializer.Deserialize[T](ReadOnlyMemory`1 buffer, MessagePackSerializerOptions options, CancellationToken cancellationToken)
Tests.TestSerialization[T](T instance, MessagePackSerializerOptions options, MessagePackCompression compression) line 53
Tests.TestSerializationWithAspNetOptions(MessagePackCompression compression) line 32
InvokeStub_Tests.TestSerializationWithAspNetOptions(Object, Object, IntPtr*)
MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
--MessagePackSerializationException
MessagePackReader.ThrowInvalidCode(Byte code)
MessagePackReader.GetStringLengthInBytesSlow(Byte code)
NullableStringFormatter.Deserialize(MessagePackReader& reader, MessagePackSerializerOptions options)
BaseFormatter.Deserialize(MessagePackReader& reader, MessagePackSerializerOptions options) line 62
MessagePackSerializer.Deserialize[T](MessagePackReader& reader, MessagePackSerializerOptions options)
.NET Version
7.0.103
Anything else?
No response