IAdvancedBus.Get<Interface> fails with serialization exception
See original GitHub issueDescription
When calling IAdvancedBus.Get<T> with an interface parameter type, instanced to a class containing Struct types, a serialization exception is thrown. This is inconsistent with the behavior of Consume method that allows proper deserialization of such examples.
Expected behavior IAdvancedBus.Get allows deserializing such types correctly.
Possible root cause
https://github.com/EasyNetQ/EasyNetQ/blob/master/Source/EasyNetQ/BasicGetResult.cs specifies a where T : class
constraint on type, which excludes Struct types (like int) from serialization.
https://github.com/EasyNetQ/EasyNetQ/blob/a1d28cca528d6675b90960a8e6f410f0515ce559/Source/EasyNetQ/IMessage.cs does not.
Possible partial workaround
Serialization will be performed correctly if a custom TypeNameHandling = TypeNameHandling.Objects
is used to initialize the JsonSerializerSettings.
Anyway this will lead to an exception in https://github.com/EasyNetQ/EasyNetQ/blob/master/Source/EasyNetQ/RabbitAdvancedBus.cs, line 636, at the type comparison.
Stack trace example Newtonsoft.Json.JsonSerializationExceptio n: Could not create an instance of type *****************. Type is an interface or abstract class and cannot be instantiated. Path ***, line 1, position 41. at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty con tainerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty m ember, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonPro perty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType) at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings) at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings) at EasyNetQ.DefaultMessageSerializationStrategy.DeserializeMessage[T](MessageProperties properties, Byte[] body) at EasyNetQ.RabbitAdvancedBus.Get[T](IQueue queue)
Setup EasyNetQ 0.50.7.399 Json.NET 6.0.7
Reproduction
See following test case (unfortunately attachment type is not supported). First test passes, second test throws the exception.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EasyNetQ;
using EasyNetQ.Topology;
using NUnit.Framework;
namespace Common.Tests.Messages
{
public interface TestInterface
{
}
public class TestClass : TestInterface
{
public TestClass()
{
Test = 50;
}
public int Test { get; set; }
}
public class EasyNetQFailureExample
{
private IAdvancedBus bus;
private IQueue queue;
private IExchange exchange;
private string key = "testqueue";
[SetUp]
public void SetUp()
{
string rabbitConnString = String.Format("host={0};virtualHost={1};username={2};password={3};prefetchcount=1",
"localhost", "/", "guest", "guest");
var rabbitBus = RabbitHutch.CreateBus(rabbitConnString);
bus = rabbitBus.Advanced;
exchange = bus.ExchangeDeclare("testExchange", ExchangeType.Direct, durable: false);
queue = bus.QueueDeclare(key, durable: false, maxPriority: 10);
bus.Bind(exchange, queue, key);
}
[TearDown]
public void TearDown()
{
bus.Dispose();
}
[Test]
public void TestConsume()
{
Action<IMessage<TestInterface>, MessageReceivedInfo> testAction =
(message, info) => Console.WriteLine(message.Body.GetType());
bus.Consume(queue, testAction);
IMessage<TestInterface> msg = new Message<TestInterface>(new TestClass());
bus.Publish(exchange, key, true, false, msg);
}
[Test]
public void TestGet()
{
IMessage<TestInterface> msg = new Message<TestInterface>(new TestClass());
bus.Publish(exchange, key, true, false, msg);
IBasicGetResult<TestInterface> result = bus.Get<TestInterface>(queue);
if (result.MessageAvailable)
{
Console.WriteLine(result.Message.Body.GetType());
}
else
{
Console.WriteLine("No message available");
}
}
}
}
Issue Analytics
- State:
- Created 8 years ago
- Reactions:1
- Comments:5 (3 by maintainers)
Top GitHub Comments
A workaround exploiting deserialization code for IMessage:
@ldenardo Actually, your workaround is exactly what we need to fix this issue.
The behaviour of jsonserializer is actually described here. So, the fix is to pass
Type
to serializer explicitly.