Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.Net Standard 4.7.1 Could not load System.Private.CoreLib during serialization

I'm working on migrating most of my project to .Net Standard 2.0.

Last part of the project in .net standard 4.7.1 is a WCF front end. This executable communicate with a .net core application throught a library Akka.net by ClientServiceReceptionist.

Network communication between application by akka.net work. Except when an it try to serialize a ReadOnlyCollection.

In this case the system try to load a "System.Private.CoreLib.dll" that is not available.

enter image description here

I readed many issues with .net 4.6 using .net standard 2.0 libraries that must have been corrected in 4.7.1. I pass from package.config to PackageReference.

I tryed to used NewtonSoft as a serializer in place of Hyperion without progress.

Does anyone have an idea, a solution ?

Edit : 07-05-2018

enter image description here

The issue is throw in the WCF Entry Points when i sent a ClusterClient.Send object throught the ClusterClientReceptionist.

The object sent contains only boolean, string, Guid and array of string properties.

Edit 08-05-2018

The object sent look like this :

{
  (string) "Path": "/user/ProcessOrderWorkflow",
  "Message": {
    "Order": {
      "Data": {
        (string)"Sentence": "i love my name",
        "Options": {
            (boolean)"Simplify" : true,
            (IReadOnlyCollection<string>) LanguageAffinity : [ "FR", "EN" ]
        }
      },
      "OrderQuery": {
        "Verb": {
          (string)"Verb": "Extract"
        },
        "Arguments": [
          {
            (string)"Argument": "Sentence"
          },
          {
            (string)"Argument": "Meaning"
          }
        ]
      },
      (Guid)"ProcessId": "0bfef4a5-c8a4-4816-81d1-6f7bf1477f65"
    },
    (string)"ReturnTypeFullName": "Viki.Api.Server.Data.SentenceMeaningMsg,, Viki.Api.Server.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
  },
  (boolean)"LocalAffinity": false
}

Each of the object used in the hierachi is builded using the constructor. All the properties are in readonly.

I tryed to serialize and deserialize the result on the WCF part before it's sent and it works.

var serializer = this._system.Serialization.FindSerializerFor(result);
var bytes = serializer.ToBinary(result);
var data = serializer.FromBinary(bytes, result.GetType());

The strange think is that it try to deserialize the object in the WCF part where it is sent and not in the LightHouse where the element should be received and transfert to a agent for processing.

like image 596
Mickael Thumerel Avatar asked May 05 '18 14:05

Mickael Thumerel


People also ask

How to fix system private corelib does not exist in NET Framework?

Serializer adds assemblies next to types you use. System.Private.CoreLib does not exist in .NET Framework and the error is thrown. In order to fix the problem you can use your own SerializationBinder. That’s what actually Newtonsoft.JSON’s author recommends.

Can I serialize objects in one framework and deserialize it in another?

Just a small note for myself: serializing objects in one framework and deserialize it in another can become a real PITA. For example, I serialize an object in .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 anymore.

Do I need netstandard DLL in my App?

Sorry, something went wrong. Right. Netstandard.dll is built into 4.7.1 so you don't need it in your app if you are guaranteed to run on 4.7.1 or higher. That's the designed behavior. Sorry, something went wrong. Executing a .NET Framework 4.6.1 console app that references a .NET Standard 2.0 assembly fails with

How to deserialize JSON generated by NET Core Application?

If this issue happens during deserialization in .NET Framework application and you can't do anything about the JSON you receive, then you can extend DefaultSerializationBinder and use it in JsonSerializerSettings to deserialize JSON generated by .NET Core application:


1 Answers

This is a top result for request "Could not load System.Private.CoreLib" so I post the workaround for ASP.NET Core APIs and .NET clients.

If json serializer type handling set to auto

settings.TypeNameHandling = TypeNameHandling.Auto;

serializer will include type information for polymorphic types. After migration to .NET Core some clients reported exception and the response body contained following type descriptor:

"$type":"System.String[], System.Private.CoreLib"

In the API model property type was defined as IEnumerable<string> which forced serializer to include actual type for an Array. The solution was to replace IEnumerable<string> with string[] or any other concrete type which allowed serializer to omit the type descriptor.

If the above does not work, for instance when you use Dictionary<string, object> you can implement custom SerializationBinder:

public class NetCoreSerializationBinder : DefaultSerializationBinder
{
    private static readonly Regex regex = new Regex(
        @"System\.Private\.CoreLib(, Version=[\d\.]+)?(, Culture=[\w-]+)(, PublicKeyToken=[\w\d]+)?");

    private static readonly ConcurrentDictionary<Type, (string assembly, string type)> cache =
        new ConcurrentDictionary<Type, (string, string)>();

    public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
    {
        base.BindToName(serializedType, out assemblyName, out typeName);

        if (cache.TryGetValue(serializedType, out var name))
        {
            assemblyName = name.assembly;
            typeName = name.type;
        }
        else
        {
        if (assemblyName.AsSpan().Contains("System.Private.CoreLib".AsSpan(), StringComparison.OrdinalIgnoreCase))
            assemblyName = regex.Replace(assemblyName, "mscorlib");

        if (typeName.AsSpan().Contains("System.Private.CoreLib".AsSpan(), StringComparison.OrdinalIgnoreCase))
            typeName = regex.Replace(typeName, "mscorlib");    
            cache.TryAdd(serializedType, (assemblyName, typeName));
        }
    }
}

And register it in JsonSerializerSettings:

settings.SerializationBinder = new NetCoreSerializationBinder();

Note: .AsSpan() for string comparison was added for backwards compatibility with .NET Framework. It doesn't harm, but not required for .NET Core 3.1+, feel free to drop it.

like image 119
Andrii Litvinov Avatar answered Sep 19 '22 06:09

Andrii Litvinov