MessagePack-CSharp / MessagePack-CSharp

Extremely Fast MessagePack Serializer for C#(.NET, .NET Core, Unity, Xamarin). / msgpack.org[C#]
Other
5.61k stars 687 forks source link

MessagePack throws in Rhino environment when the same assembly is loaded multiple times #1821

Closed Hanning-Liu closed 3 months ago

Hanning-Liu commented 4 months ago

Bug description

I'm trying to use Rhino/Grasshopper, a 3d modeling and visual programming software, to send some Mesh geometry data via WIFI to another device. And the MessagePack only works fine for the first time. Then keep reporting error.

Repro steps

You can see the video.

Expected behavior

No error message.

Actual behavior

Report error message: MessagePackSerializationException: Failed to serialize MyClass value.

Rhino 8 currently support .NET Framework and .NET. But it needs a reboot to switch between these two platforms. .NET 7 doesn't. .NET Framework 4.8 works fine

Additional context

https://github.com/MessagePack-CSharp/MessagePack-CSharp/assets/42676581/64feee7c-6d76-49e6-b4fc-d274198bfc82

Hanning-Liu commented 4 months ago

I assume the error is related to memory use. Hope someone and help me!

AArnott commented 4 months ago

I don't think we can help you with merely a "MessagePackSerializationException: Failed to serialize MyClass value." as the reported error message. If you can include the full callstack and all inner exceptions, there's a better chance we can help.

Hanning-Liu commented 4 months ago

Thank you for your reply!

I can't find the full call stack. But I submitted an issue on the Rhino Forum: https://discourse.mcneel.com/t/get-an-error-when-using-c-script-component-to-get-nuget-package/182256/2

I will update this issue once I get any reply from there!

Hanning-Liu commented 4 months ago

@AArnott Hi, Here is a new reply by the developer of Rhino software. He talks about the possible reason. https://discourse.mcneel.com/t/get-an-error-when-using-c-script-component-to-get-nuget-package/182256/10?u=hani_leo

The C# Script component continously re-compiles your code every time you make a change. This means that there is an unnamed assembly in memory for every time you have changed the C# script. Each one of these assemblies end up containing a Script_Instance and MyClass implementation. The MessagePack library you are using in the example above has a dynamic type resolver that based on my quick inspection seem to get confused when the script is changed. It runs fine the first time, but on the second attempt (after editing the script and compiling a new assembly by the component backend), it gets confused on how to resolve and serialize the type MyClass. As I mentioned above this type is now in a completely different assembly but has the same name. I did not dig deeper into the code behind this library. Here is the the inner exception stack. Seems like there is an exception in the static constructor of the FormatterCache type.

at MessagePack.Resolvers.DynamicObjectResolver.GetFormatter[T]()
   at MessagePack.Resolvers.StandardResolver.FormatterCache`1..cctor()
--- End of stack trace from previous location ---
   at MessagePack.FormatterResolverExtensions.Throw(TypeInitializationException ex)
   at MessagePack.MessagePackSerializer.Serialize[T](MessagePackWriter& writer, T value, MessagePackSerializerOptions options)
   at MessagePack.MessagePackSerializer.Serialize[T](T value, MessagePackSerializerOptions options, CancellationToken cancellationToken)
   at Script_Instance.RunScript(Object x, Object y, Object& a) in rhinocode:///grasshopper/1/bc8f6a2e-38f3-4a28-ab06-7ff244bd8d2a/93d481be-7cf3-445f-af65-5520b5cf9f99:line 63
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
AArnott commented 3 months ago

I wonder if the assembly name changes each time it is recompiled and loaded. If the assembly name is unique each time, I would expect this to work. But if Rhino loads a new assembly with the same name each time, then you're in a decidedly unsupported scenario.

Hanning-Liu commented 3 months ago

Based on what the developer of Rhino said, I think the assemblies have the same name. And I think the bug should be fixed by the developer of Rhino. Since the C# script component recompiles each time the code is changed, the previously compiled assemblies are no longer useful and should not be stored in memory.

I will continue communicating on the McNeel forum. Thank you for your response!

AArnott commented 3 months ago

the previously compiled assemblies are no longer useful and should not be stored in memory.

This may be a runtime limitation. .NET Framework doesn't support unloading assemblies, and I don't think mono does either. The newer ".NET" supports assembly unloading under certain conditions. I wonder which of these Rhino is based on. Even if supported, unloading the old assembly requires that all references to that assembly be in the same AssemblyLoadContext and unloaded with it. This means MessagePack itself would also have to be loaded into the same ALC and unloaded with it, since MessagePack retains references to all types that it serializes for perf reasons.

Hanning-Liu commented 3 months ago

Rhino runs on .NET Framework on windows and mono on mac before version 8.

Now Rhino 8 on windows supports both .Net Framework 4.8 and .NET 7. I first tried run the MessagePack on .NET 7. But I get these errors, it can't find the attributes: Untitled-1

So I changed the runtime to .NET Framework, and it only works for the first time as we talked

AArnott commented 3 months ago

The attributes not being found isn't a runtime error -- that's an issue with build. Apparently MessagePack.Annotations isn't being referenced by the compiler.

Hanning-Liu commented 3 months ago

Yes, but this is weird. It can recognize all other package without this one.

AArnott commented 3 months ago

No denying it's weird... I'm just saying this isn't a MessagePack bug. Rhino is the odd one out here where all the issues are occurring, and MessagePack has proper dependencies between packages so that you shouldn't be getting attribute not found compiler errors, so all arrows point to Rhino being the problem and not something we can support. Sorry.

Hanning-Liu commented 3 months ago

Thank you for your help! I will continue communicating with Rhino developers!