Giter Club home page Giter Club logo

nservicebus.newtonsoft.json's Introduction

nservicebus.newtonsoft.json's People

Contributors

adamralph avatar andreasohlund avatar awright18 avatar bording avatar danielmarbach avatar davidboike avatar dbelcham avatar dependabot-preview[bot] avatar dependabot[bot] avatar dvdstelt avatar helenktsai avatar heskandari avatar internalautomation[bot] avatar janovesk avatar jbogard avatar johnsimons avatar jpalac avatar kbaley avatar kentdr avatar mauroservienti avatar mikeminutillo avatar particularbot avatar ramonsmits avatar seanfarmar avatar seanfeldman avatar simoncropp avatar soujay avatar timbussmann avatar tmasternak avatar williambza avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

nservicebus.newtonsoft.json's Issues

An enveloped message fails deserialization

I have a test case which fails - basically I have a message within a message.

Deserialization fails because json.net is trying to load type IBaseMessage_impl - the message mapper generated type. My reason for putting a message inside a message is weird I know but there is a good reason I can go into if you want.

I've fixed this in my own code by supplying JsonSerializerSettings with a SerializationBinder which converts types during serialization from IBaseMessage_impl back to IBaseMessage

I know a while ago you guys were using the ContractResolver and SerializationBinder settings for serialization - not sure what changed but the fix is basically to do that again. I've essentially copied the IMessageSerializer interface for my own project here and now have NSB use my serialization which handles enveloped messages.


[TestFixture]
public class With_enveloped_message
{
    [Test]
    public void Deserialize()
    {
        var messageMapper = new MessageMapper();
        var serializer = new JsonMessageSerializer(messageMapper, null, null, null, null);
        var messageTypes = new[]
        {
            typeof(IBaseMessage), typeof(IEnvelope)
        };
        messageMapper.Initialize(messageTypes);
        var message = messageMapper.CreateInstance<IBaseMessage>(x => x.SomeProperty = "test");
        var envelope = messageMapper.CreateInstance<IEnvelope>(x => x.Message = message);
        using (var stream = new MemoryStream())
        {
            serializer.Serialize(envelope, stream);

            stream.Position = 0;
            var result = (IEnvelope)serializer.Deserialize(stream, messageTypes)[0];

            Assert.AreEqual("test", (result.Message as IBaseMessage).SomeProperty);
        }

    }

    public interface IEnvelope : IMessage
    {
        object Message { get; set; }
    }

    public interface IBaseMessage : IMessage
    {
        string SomeProperty { get; set; }
    }
}

JsonIgnore attribute is not in effect while sending the messages

Hello,
I am using the below packages in my .net core 2.2 application.

<PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="2.2.0" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="2.3.0" />
    <PackageReference Include="NServiceBus" Version="7.2.0" />
    <PackageReference Include="NServiceBus.MSDependencyInjection" Version="0.1.4" />
    <PackageReference Include="NServiceBus.RabbitMQ" Version="5.1.2" />
    <PackageReference Include="NServiceBus.SagaAudit" Version="3.0.1" />
    <PackageReference Include="NServiceBus.Newtonsoft.Json" Version="2.2.0" />
    <PackageReference Include="NServiceBus.Serilog" Version="6.5.0" />
    <PackageReference Include="Serilog.Sinks.Trace" Version="2.1.0" />
    <PackageReference Include="Serilog.Formatting.Compact" Version="1.1.0" />
    <PackageReference Include="Steeltoe.Extensions.Configuration.CloudFoundryCore" Version="2.3.0" />
    <PackageReference Include="Steeltoe.Extensions.Logging.SerilogDynamicLogger" 
Version="2.3.0" />
    <PackageReference Include="Steeltoe.Management.CloudFoundryCore" Version="2.3.0" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="4.0.1" />

I have configured Newtonsoft Json serializer like below

var settings = new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
                ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            };

            var serialization = endpointConfiguration.UseSerialization<NewtonsoftSerializer>();
            serialization.Settings(settings);
            serialization.WriterCreator(s =>
            {
                var streamWriter = new StreamWriter(s, new UTF8Encoding(false));
                return new JsonTextWriter(streamWriter);
            });

I have a message like below

 public class ShipOrder : ICommand
    {
        public string OrderId { get; set; }

        [JsonIgnore]
        public string OrderName { get; set; }
    }

Enabled Serilog tracing too. Upon running the application, I am able to see the property OrderName as part of sent message even though I wanted to exclude from serialization. Please find the logs below.

{"@t":"2019-11-29T10:42:02.6394421Z","@mt":"Sent message {OutgoingMessageType} {OutgoingMessageId}.","OutgoingMessage":{"OrderId":"c0652686-8cca-4697-946e-ce7c382fd0ee","OrderName":"Shoes","$type":"ShipOrder"},"UnicastRoutes":["Shipping"],"OriginatingHostId":"e96e4d21699770c86ae326d10b0df3e8","MessageIntent":"Send","OriginatingEndpoint":"Shipping","OriginatingMachine":"VW10P98","OriginatingSagaId":"5374c5c9-f4c7-4a05-ad0e-ab1400b04377","OriginatingSagaType":"Shipping.ShippingPolicy, Shipping, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","RelatedTo":"92c3a62b-af1a-43ab-9851-ab1400b04378","ReplyToAddress":"Shipping","OutgoingMessageId":"69d2667b-b2d0-406f-86a4-ab1400b057b8","OutgoingMessageType":"Messages.ShipOrder","CorrelationId":"765c1ee4-4495-4482-9e69-ab1400b04350","ConversationId":"a16fffa5-da76-402f-8830-ab1400b04350","IncomingMessageId":"92c3a62b-af1a-43ab-9851-ab1400b04378","IncomingMessageType":"Messages.OrderBilled","SourceContext":"Messages.OrderBilled","ProcessingEndpoint":"Shipping"}

{"@t":"2019-11-29T10:42:09.4894892Z","@mt":"Receive message {IncomingMessageType} {IncomingMessageId}.","IncomingMessage":{"OrderId":"c0652686-8cca-4697-946e-ce7c382fd0ee","OrderName":null,"$type":"ShipOrder"},"OriginatingHostId":"e96e4d21699770c86ae326d10b0df3e8","MessageIntent":"Send","NonDurableMessage":"False","OriginatingEndpoint":"Shipping","OriginatingMachine":"VW10P8","OriginatingSagaId":"5374c5c9-f4c7-4a05-ad0e-ab1400b04377","OriginatingSagaType":"Shipping.ShippingPolicy, Shipping, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","RelatedTo":"92c3a62b-af1a-43ab-9851-ab1400b04378","ReplyToAddress":"Shipping","TimeSent":"2019-11-29T10:42:02.6571900Z","IncomingMessageId":"69d2667b-b2d0-406f-86a4-ab1400b057b8","IncomingMessageType":"Messages.ShipOrder","CorrelationId":"765c1ee4-4495-4482-9e69-ab1400b04350","ConversationId":"a16fffa5-da76-402f-8830-ab1400b04350","SourceContext":"Messages.ShipOrder","ProcessingEndpoint":"Shipping"} 

My real issue is with EF Core entity classes and I wanted to exclude navigation properties to avoid infinite looping. But unfortunately huge payload is getting created even after placing JsonIgnore attribute. Also message attributes appear in pascal case, even though the CamelCasePropertyNamesContractResolver is specified as part of Json serialization settings. I am kind of puzzled here with these behaviors.

Relax Newtonsoft.Json dependency Upper Bound limitation

NServiceBus.Newtonsoft.Json.nuspec explicitly sets the Newtonsoft.Json upper bound to 8.0.0 here:

<dependency id="Newtonsoft.Json" version="[7.0.0, 8.0.0)" />

Latest version of Newtonsoft.Json is 9.0.1.

Is there a reason for setting the upper bound or can it be safely removed?

Context: I'm combining NServiceBus with the .NET Core configuration framework (not running on .net core, but regular dot net framework) which unfortunately has a ridiculously high json requirement, requiring 9.0.1: https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Json/

Unable to handle event hierarchy without concrete message implementation

When you have a message that implements multiple interfaces, and a message handler for one of those interfaces, NServiceBus may throw an exception stating that it cannot find a handler for the other interface.

For example, assume the following event hierarchy:

public interface IItemChanged { }
public interface ICustomerChanged : IItemChanged { }
public class CustomerChangedEvent : ICustomerChanged { }

And a message handler like this:

class SomeMessageHandler : IHandleMessages<ICustomerChanged>
{
  // ...
}

At runtime, the endpoint may throw an exception claiming that no handler could be found for IItemChanged.

InvalidOperationException: No handlers could be found for message type: IItemChanged

This only happens if the message handler exists in an endpoint that does not have a reference to the concrete message class (i.e. CustomerChangedEvent). When this happens, the endpoint needs to generate a proxy class to contain the message properties.

It should create the fewest number of proxies. In the example, this would be ICustomerChanged.

Unfortunately, this is dependent on the order the interface types are provided to the serializer. If the order is ICustomerChanged, IItemChanged then only one proxy is generated, and it satisfies all of the interfaces.

If the order is instead IItemChanged, ICustomerChanged then two proxies are generated, one for each interface. In this case, the receive pipeline attempts to handle both as separate invocations of the Incoming Logical Message context, and the first one fails as there is no handler for it.

The order is dependent on this algorithm in core.

If the concrete type is passed to the serializer, then it does not need a proxy and it can deserialize into the concrete type, which already satisfies the interfaces, so there's nothing else to do.

Workaround

The workaround is to ensure that the subscribing endpoint has access to the concrete type. This allows the serializer to deserialize the data into the concrete type and it will be handled normally.

Custom ContractResolver gets overwritten

In order to have more fine-grained control of the serialization process I would like to provide a custom contract resolver to the serializer. Normally this is passed in using a JsonSerializerSettings instance like this:

config.UseSerialization<NewtonsoftSerializer>()
    .Settings(new JsonSerializerSettings
     {
        ContractResolver = new CamelCasePropertyNamesContractResolver()
    });

When creating the serializer, this code overwrites the ContractResolver passed in.

Incompatible with latest version of NSB

I believe the latest version of NSB has a different interface for implementing a custom serialiser.

Using this serialiser with the latest version now returns the error:

"Method 'ProvidedByFeature' on type 'NServiceBus.Newtonsoft.Json.NewtonsoftSerializer' from assembly 'NServiceBus.Newtonsoft.Json, Version=0.2.0.0, Culture=neutral, PublicKeyToken=9fc386479f8a226c' is overriding a method that is not visible from that assembly"

UTF-8 BOM (Byte Order Mark) is incorrectly added to the serialized message bodies

UPDATE: See #53 (comment) for more information.

Who's affected

Anyone manually deserializing NServiceBus messages using custom code.

Symptoms

  1. The first 3 bytes of the serialized message body are BOM bytes (0xEF,0xBB,0xBF)
  2. An attempt to deserialize messages using JsonConvert.DeserializeObject() throws an exception "Newtonsoft.Json: Unexpected character encountered while parsing value: ?. Path '', line 0, position 0."

Backported to

Original issue

The BOM for UTF-8 is currently added to outgoing messages:

_messageSession.Send(new SaySomethingCommand {Message = "Hello World"});

Becomes:

{"Message":"Hello World"}

However, looking at the bytes, the BOM is added:

EFBBBF7B224D657373616765223A2248656C6C6F20576F726C64227D

Which, decoding, looks like:

{"Message":"Hello World"}

If you try to manually deserialize through JSON.NET, say for an integration scenario, Azure Functions, Web Jobs etc:

var body = Encoding.UTF8.GetString(message.Body);
var command = JsonConvert.DeserializeObject<SaySomethingCommand>(body);

This will fail with the message:

Newtonsoft.Json: Unexpected character encountered while parsing value: ?. Path '', line 0, position 0.

Per the RFC:

Implementations MUST NOT add a byte order mark to the beginning of a JSON text.

The JSON in the message, because it includes a BOM, isn't actually valid JSON.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.