JamesNK / Newtonsoft.Json

Json.NET is a popular high-performance JSON framework for .NET
https://www.newtonsoft.com/json
MIT License
10.77k stars 3.25k forks source link

Loop referencing exceptions only with .Net Core 2.2 #2066

Open Anthony-Breneliere opened 5 years ago

Anthony-Breneliere commented 5 years ago

I have got a loop referencing exception with .Net Core 2.2 but not Framework .NET 4.72, when serializing mocked objects with moq. Shouldn't the behavior be the same ? Here is the code to reproduce the exception:

using Moq;
using System;
using System.Runtime.Serialization;

namespace ConsoleApp1
{
    public interface IAction
    {
        string Description { get; }
        object Argument { get; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var actionMock = new Mock<IAction>().SetupAllProperties();
            // actionMock.As<ISerializable>();
            Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(actionMock.Object));
        }
    }
}

Result: Newtonsoft.Json.JsonSerializationException: 'Self referencing loop detected for property 'Object' with type 'Castle.Proxies.IActionProxy'. Path 'Mock'.'

With .Net Framework the object actionMock.Object is properly serialized.

Moq is 4.10.1 and Newtonsoft.Json 12.0.2

dbc2 commented 5 years ago

Json.NET's implementation of self-referencing loop detection depends on the object.Equals() implementations of the underlying objects. For details see:

If the implementations of object.Equals() for mocked objects differ between .Net Core 2.2 and .NET Framework 4.72, you'll get different results for reference loop detection.

Using your own equality comparer on both frameworks, e.g. ObjectReferenceEqualityComparer<object> from IEqualityComparer<T> that uses ReferenceEquals, may make the two frameworks behave consistently.

Also, did you see How to mock (with Moq) an interface that is serialized by Newtonsoft.json?? The error looks to be identical.