question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Send / Receive -> Could not load assembly 'System.Private.CoreLib'

See original GitHub issue

Hi, I use EasyNetQ 6.3.1. When sending string value from asp .net core to .net console Sender var sender = RabbitHutch.CreateBus(_connectionString);
await Sender.SendReceive.SendAsync("ConsoleChat", message );

Receiver receiver = RabbitHutch.CreateBus("host=localhost"); receiver.SendReceive.Receive("ConsoleChat", x => x.Add<string>(e => { Console.WriteLine($"Message: {e}"); }));

I got error on EasyNetQ_Default_Error_Queue:

“Exchange”:“”,“Queue”:“ConsoleChat”,“Exception”:"EasyNetQ.EasyNetQException: Could not load assembly ‘System.Private.CoreLib’\r\n w EasyNetQ.DefaultTypeNameSerializer.GetTypeFromTypeNameKey(TypeNameKey typeNameKey)

it looks like serialization issue…

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:20 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
StevenBonePghcommented, Jun 23, 2021

EasyNetQ is pretty clear that it is an ‘Opinionated Wrapper’ over RabbitMq’s client libraries. Part of this ‘opinionated’ aspect is that the publisher and consumer would share the same opinions of how the messages in RabbitMq - both data and headers - should be formatted. Do not forget that this opinionated nature includes the error queue message and headers, queue naming, and more (though you are overriding the queue naming in your example).

The implication of the above is that you need to fully share the assembly, and types, of what is being published between publisher and consumer, and that these types are, in fact, able to be properly serialized and deserialized. Using this library in a way where the messages are either produced or consumed by a non EasyNetQ component is not one of the core scenarios EasyNetQ is intended to enable. It IS possible, but not easy. I mention this because of your mentioning ‘cross platform’.

There is a side benefit to publishing your own type (rather than the string) in that you can evolve the type being published to add additional fields if you are careful that on the deserialization/consumer side you can handle messages of the older format. This feature is impossible if you simply publish a serialized string.

If you absolutely MUST publish a string like your sample, or cannot share assemblies/types of the messages being published you are outside of the parts that EasyNetQ makes ‘Easy’. The issue you raised is one of a leaky abstraction in that the type you are publishing is a type that cannot be created using the default components of the library. This is one that is difficult, if not impossible, for EasyNetQ to fix. The underlying issue is that as part of the ‘opinionated’ nature, the type being published is serialized into the RabbitMQ message header Type - in your case it is serializing typeof(string) as System.String, System.Private.CoreLib which cannot be created on the consumer side using the default DefaultTypeNameSerializer implementation. I’d suggest that you replace ITypeNameSerializer in your consumer, by forking the EasyNetQ source for DefaultTypeNameSerializer with your own changes. There are two possible changes:

  • Reimplement DeSerialize using a solution similar to what you can see here. To be honest, I intended to create a PR long time ago to make some of the methods in the Default and Legacy TypeNameSerializer classes virtual, so one could override the method, replace the type name, and call to base for situations like this.
  • Add a method to the existing DefaultTypeNameSerializer code to pre-populate the deserializedTypes collection, and in the ctor (or elsewhere) call RegisterReplacementType("System.String, System.Private.CoreLib", typeof(string));
public void RegisterReplacementType([NotNull] string typeName, [NotNull] Type type)
{
    deserializedTypes.AddOrUpdate(typeName, type, (key, oldValue) => type);
}

Other Thoughts

If it is important for you to have the capability of cross-framework (in other words a publisher or consumer that is NOT EasyNetQ), I would suggest you abandon EasyNetQ. Sure, you can replace the default components, such as IMessageSerializationStrategy and ITypeNameSerializer, but at what point is it that you cross a threshold where replacing the bits of EasyNetQ (and suffering through breaking changes in EasyNetQ as time progresses) where the costs of customization outweigh the benefits of using an opinionated wrapper where the opinions are so divergent?

I use EasyNetQ, replacing some bits, such as Conventions and ITypeNameSerializer that enabled me to retain the name of the queue and process messages where the assembly and class name had changed across versions (where queued messages of the ‘old’ would still need to be processed using the ‘new’). On the consumer side, I replace the IConsumerErrorStrategy. And I rely on the mechanism of the error queue with an inbuilt hosepipe like mechanism to retry processing of failed messages. For the most part, the opinions of EasyNetQ match mine.

In other cases, I skip EasyNetQ altogether and use the RabbitMq library directly. In my case, I have an RPC scenario, combined with Priority Queues, where I need to handle timeouts on caller and callee in specific manners, as well as making sure in the event of a connection burp the caller’s initially randomly named return message queue is properly recreated with the same name so if a reply is being worked on after the burp it can still be delivered. Sure, I could replace some of the default EasyNetQ bits, but then it becomes a constant battle between the (forgive the overuse of the word) opinionated nature of both EasyNetQ and RabbitMq APIs against my own business requirements and the API that I wish to expose to the internal consumers where I could replace RabbitMq with other options in the future if needed/desired.

I could create (and have created) pull requests for both libraries to make them better equipped for my use cases, or to resolve blocking bugs. In these cases you are also subservient to the release cycles of both libraries, and it is rather difficult to find and fix bugs going through so many layers.

At a certain point you need to realize when the opinions of you and your libraries diverge enough that you need to abandon one of these opinions in order to develop an easy to use, understand, and maintain piece of software.

0reactions
Plinercommented, Sep 13, 2021

Thanks for this @StevenBonePgh 🔥

@robertok77 Feel free to raise a PR for changing DefaultTypeNameSerializer in any mentioned way.

PS I hope we also fine to have hardcoded system types translation inside DefaultTypeNameSerializer.

Read more comments on GitHub >

github_iconTop Results From Across the Web

'Could not load file or assembly 'System.Private.CoreLib ...
1 using .NET framework. I ran my code today after it works fine yesterday, but today I received this exception: System.IO.FileNotFoundException ...
Read more >
Could not load file or assembly 'System.Private.CoreLib ...
An unhandled exception of type 'System.IO.FileNotFoundException' occurred in Unknown Module. Could not load file or assembly 'System.Private.
Read more >
Could not load file or assembly 'System.Private.CoreLib
The system cannot find the file specified. This error occurs because Microsoft Store no longer accepts packages with mixed UWP and Desktop .NET ......
Read more >
How to solve "Could not load System.Private.CoreLib"
NET Core app, send it over to another system which uses .NET Framework 4.x and then I realize that objects can't be deserialized...
Read more >
Could not load type 'System.Object' from assembly ...
dll version 6.0.0.0 inside the gac a different error is coming, saying that Could not load type 'System.Object' from assembly 'System.Private.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found