Is Castle Dynamic Proxy IInvocation really different in .net Core and Framework?

547 Views Asked by At

I have code that uses Castle DynamicProxy to proxy code invocation. In Intercept(IInvocation invocation), I use NewtonSoft to Json serialize the invocation.

Newtonsoft.Json.JsonConvert.SerializeObject(invocation.Method);

In Framework this yields a pretty succinct thing that looks like this:

{
"Name": "FastLoadDataAsJson",
"AssemblyName": "TinyData, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
"ClassName": "Dimension2.Core.Database.TinyData",
"Signature": "Byte[] FastLoadDataAsJson(System.String, System.String, System.String)",
"Signature2": "System.Byte[] FastLoadDataAsJson(System.String, System.String, System.String)",
"MemberType": 8,
"GenericArguments": null
}

In a .Net Core project the same serialization call first gives this exception:

Self referencing loop detected for property 'ManifestModule' with type 'System.Reflection.RuntimeModule'. Path 'Module.Assembly'.'

I can get around it using the setting Newtonsoft.Json.ReferenceLoopHandling.Ignore

But JSON I get back is 93,000 lines long!!! What on earth is going on? It seems the invocation is drastically different. Besides just the length, the properties are different, for example there is no a Signature nor Signature2 property.

The Framework succinct Json seems entirely appropriate to describe the invocation we need to make. So why is Core so different? I worry that I am missing something important about Castle, Core, or both.

1

There are 1 best solutions below

0
Jonathon Rossi On

The IInvocation.Method property is of type System.Reflection.MethodInfo, JSON serializing that object with JSON.NET is unrelated to Castle Core.

Looking at .NET Framework's serialization functionality shows where JSON.NET is getting those from. .NET Core does not support binary serialization and so JSON.NET would be using its usual serialization of public properties, causing it to run into cyclic references.

[Serializable]
internal class MemberInfoSerializationHolder : ISerializable, IObjectReference 
{
    //...
    public static void GetSerializationInfo(
        SerializationInfo info,
        String name,
        RuntimeType reflectedClass,
        String signature,
        String signature2,
        MemberTypes type,
        Type[] genericArguments)
    {
        if (info == null)
            throw new ArgumentNullException("info");
        Contract.EndContractBlock();

        String assemblyName = reflectedClass.Module.Assembly.FullName;
        String typeName = reflectedClass.FullName;

        info.SetType(typeof(MemberInfoSerializationHolder));
        info.AddValue("Name", name, typeof(String));
        info.AddValue("AssemblyName", assemblyName, typeof(String));
        info.AddValue("ClassName", typeName, typeof(String));
        info.AddValue("Signature", signature, typeof(String));
        info.AddValue("Signature2", signature2, typeof(String));
        info.AddValue("MemberType", (int)type);
        info.AddValue("GenericArguments", genericArguments, typeof(Type[]));
    }
    //...
}

(https://referencesource.microsoft.com/#mscorlib/system/reflection/memberinfoserializationholder.cs)