Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cross Platform Primitive Types with Generics #1972

Closed
danebou opened this issue Jan 31, 2019 · 19 comments
Closed

Cross Platform Primitive Types with Generics #1972

danebou opened this issue Jan 31, 2019 · 19 comments

Comments

@danebou
Copy link

danebou commented Jan 31, 2019

Source/destination types

public class TestClass<T>
{
    public int A { get; set; }
    public T B { get; set; }
}

Source/destination JSON

With UWP/.NetCore:

{
    "$type": "AppTest.MainPage+TestClass`1[[System.Int32, System.Private.CoreLib]], AppTest",
    "A": 1,
    "B": 2
}

With .NET Framework

{
    "$type": "AppTest.MainPage+TestClass`1[[System.Int32, mscorlib]], AppTest",
    "A": 1,
    "B": 2
}

Expected behavior

Successful deserialization. Or the suggested fix of serializing primitives without the assembly name:

{
    "$type": "AppTest.MainPage+TestClass`1[[System.Int32]], AppTest",
    "A": 1,
    "B": 2
}

Actual behavior

Runtime Exception:

Newtonsoft.Json.JsonSerializationException: 'Error resolving type specified in JSON 'ConsoleApp3.Program+TestClass`1[[System.Int32, mscorlib]], ConsoleApp3'. Path '$type', line 1, position 81.'

Steps to reproduce

  1. Serialize class with TypeNameHandling (Tested with TypeNameHandling.Objects)
 string serialized = JsonConvert.SerializeObject(a, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Objects});
  1. Deserialize json file on a different .Net system
    a. That is, .NETFramework if UWP/.NETCore, and vice versa.
object deserialized = JsonConvert.DeserializeObject(serialized, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Objects });
@danebou
Copy link
Author

danebou commented Jan 31, 2019

Similar issue: #1378

However, it would be nice if at least the primitive types are supported by default. (Type.IsPrimitive?)

@Dunge
Copy link

Dunge commented Nov 17, 2020

Stumbling on this issue porting my projects from NetFramework to Net5.

I'm surprised this is not a more high profile issue since this is probably happening to many people since the existence of NetCore. Any project using json serialization for messages between micro-services using different framework will encounter this on basic primitive types. #1378 offers a workaround, but it's not perfect, and also requires old NetFramework services to be updated to support the inverse (netcore to netframework).

Since the issue haven't moved since 2019, should I assume it's not in the plan to offer a transparent fix officially?

@sungam3r
Copy link

This repo is (almost) dead. Use System.Text.Json instead. It makes no sense for MS to improve this serializer.

@Dunge
Copy link

Dunge commented Nov 17, 2020

As much as System.Text.Json is a nice initiative and faster and easier to use for basic projects, it is still missing many features so the switch can't be done "as is" for many project. Notably polymorphic deserialization (TypeNameHandling) as mentioned in this issue. Or PopulateObject(), or some other custom converters that needs to be implemented differently.

@sungam3r
Copy link

sungam3r commented Nov 18, 2020

Yes, there is no parity in features yet. But at least with the appearance of net5 there are more green checkmarks in the second column - https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to?pivots=dotnet-5-0#table-of-differences-between-newtonsoftjson-and-systemtextjson

See also dotnet/runtime#41313

@danebou
Copy link
Author

danebou commented Nov 23, 2020

Yeah this issue is definitely going to be seen more and more when porting apps to .NET 5.

I'll share our temporary but not ideal solution was removing all instances of , System.Private.CoreLib and , mscorlib in the serialized text. If you want you could even check for levels of [[ ]] brackets.

@danebou
Copy link
Author

danebou commented Nov 23, 2020

I don't know what the status of JSON.net is, but I'd imagine it stay around as System.Text.Json gains more functionality, probably years. But feels weird talking about whenever or not JSON.net will stay around in this issue thread. Might want to at least support this feature as people make the transition, since this would be the biggest obstacle I can think of.

@danebou
Copy link
Author

danebou commented Nov 23, 2020

@Dunge This issue occurred when serializing on .NET 5 and then deserializing on .NET Framework 4 right? Want to make sure this fully fixes the issue

@JamesNK
Copy link
Owner

JamesNK commented Nov 23, 2020

The value in $type is written and read by ISerializationBinder. You could write your own one to resolve these name values.

Alternatively you could wrap the default one (DefaultSerializationBinder) and do something hacky like a string replace on the type name. For example, replace mscorlib with System.Private.CoreLib.

@SimonCropp
Copy link

potential workaround?

    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
    {
        if (args.Name == "System.Private.CoreLib")
        {
            return typeof(int).Assembly;
        }

        return null;
    };

@Dunge
Copy link

Dunge commented Nov 26, 2020

@danebou Yes. Somehow, .NET Framework4 serialized strings with mscorlib can deserialize without issue in a .NET5 project, but not the inverse.

@SimonCropp This seems to be working for me. In any case, it's much simpler and cleaner than @arthurvaverko-kaltura workaround in #1378.

In my situation, the System.Private.CoreLib string would not appear on primitive (int, string). It would appear in generics as the issue mention, but also on types like List when TypeNameHandling = TypeNameHandling.All is specified.

@SimonCropp
Copy link

@Dunge yeah we confirmed and rolled out the AssemblyResolve workaround

@danebou
Copy link
Author

danebou commented Dec 4, 2020

That's a far better solution. I'll close out my PR.

@SimonCropp
Copy link

@danebou i didnt consider my suggestion a "fix", just a workaround. My preference would be that this scenario was supported OOTB

@danebou
Copy link
Author

danebou commented Dec 8, 2020

Ah gotcha. Yeah, I'm in favor of OOTB too. It at least seems like a cleaner solution. However, it might bring unexpected behavior to the user, if say they relied on that assembly check to determine the platform (very bad implementation, but still).

@JamesNK Regardless of the implementation, is this something you feel like should be handled with JSON.net, or left up to the user to apply a workaround? I think the decision on that would either close out this issue, or allow us to get a PR up.

@JamesNK
Copy link
Owner

JamesNK commented Dec 8, 2020

I'm not sure. I'm hesitant to hardcode behavior on assembly names. If it isn't automatically supported, at the very least the workaround should be added to the documentation.

@SimonCropp
Copy link

@JamesNK is previously worked ootb, should it instead be considered a bug in dotnet?

@danebou
Copy link
Author

danebou commented Dec 9, 2020

An alternative solution is to leave the assembly name off when serializing primitives. I don't know which option that would fit into

@danebou
Copy link
Author

danebou commented Jun 30, 2021

I'll close out this issue. The workaround SimonCropp suggested is great.

@danebou danebou closed this as completed Jun 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants