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

Replace Newtonsoft with System.Text.Json #364

Closed
kristof12345 opened this issue Dec 29, 2021 · 10 comments · Fixed by #401
Closed

Replace Newtonsoft with System.Text.Json #364

kristof12345 opened this issue Dec 29, 2021 · 10 comments · Fixed by #401

Comments

@kristof12345
Copy link

Hi!

Please update to .net 6 and replace Newtonsoft with System.Text.Json.

Thanks.

@abatishchev
Copy link
Member

abatishchev commented Dec 29, 2021

Hi! It's actually 2-issues-in-1.

I might be able to come to the upgrade to .NET 6 soon as it's trivial. On other hand, since it's trivial, please don't hesitate to contribute yourself. You can use #315 as a reference

The latter is little less trivial, see #76. Meanwhile it's already possible to substitute the serialization engine by reimplementing IJsonSerializer. Again, it's trivial and if you could contribute that would be awesome.

@abatishchev
Copy link
Member

By looking at the list of supported target frameworks by the latest version, I see it supports net472 and netstandard2.0 so we potentially can drop Json.Net, keeps it only in net35 and net40.

@abatishchev
Copy link
Member

@kristof12345 the former is done, please try version 8.8.1.

For the latter, please consider contributing. I'd happy to help to get it reviewed and published in a timely manner.

@abatishchev

This comment was marked as duplicate.

@abatishchev
Copy link
Member

@kristof12345 friendly ping on support System.Text.Json, that would be an awesome addition to the library

@abatishchev abatishchev changed the title Update to .net 6 and replace Newtonsoft with System.Text.Json Replace Newtonsoft with System.Text.Json Apr 8, 2022
@hartmark
Copy link
Contributor

hartmark commented Jun 3, 2022

What's missing/not working in the code added in the PR?

@hartmark
Copy link
Contributor

hartmark commented Jun 3, 2022

I made a quick look at the code and realized that the easiest way of solving this is to create two separate nugets that implements IJsonSerializer and then remove all code regarding serializing in the base nugget.

JwtNet.Json.Newtonsoft:

using System;
using JWT;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;

namespace Tests.ApiTests;

public class MyJsonSerializerNewtonsoft : IJsonSerializer
{
    public string Serialize(object obj)
    {
        return JsonConvert
            .SerializeObject(
                obj,
                new JsonSerializerSettings()
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver(),
                    Converters = { new StringEnumConverter() }
                });
    }

    public object Deserialize(Type type, string json)
    {
        return JsonConvert
            .DeserializeObject(
                json, type,
                new JsonSerializerSettings
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver(),
                    Converters = { new StringEnumConverter() }
                });
    }
}

JwtNet.Json.System.Text:

using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using JWT;

namespace Tests.ApiTests;

public class MyJsonSystemText : IJsonSerializer
{
    public string Serialize(object obj)
    {
        
        var jsonOptions = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
        };
        jsonOptions.Converters.Add(new JsonStringEnumConverter());
        
        return JsonSerializer.Serialize(obj, jsonOptions);
    }

    public object Deserialize(Type type, string json)
    {
        var jsonOptions = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
        };
        jsonOptions.Converters.Add(new JsonStringEnumConverter());
        
        return JsonSerializer.Deserialize(json, type, jsonOptions);
    }
}

Plus we need some way to configure the serlialization options.

@abatishchev
Copy link
Member

abatishchev commented Jun 4, 2022

the easiest way of solving this is to create two separate nugets

Yes, exactly. I outlined this idea in #76. Hope one day I and/or someone else would do that.

I ried in #389 something different but it didn't work.

@hartmark
Copy link
Contributor

hartmark commented Jun 4, 2022

What didn't work? I got it compiling with this small changes to your branch.

See this PR #401

However the asserts seems to be off as it complains about not matching types.

When running the test:
Decode_To_Dictionary_Should_Return_Dictionary_When_Algorithm_Is_Symmetric

I get this error:

Expected token to contain value "Jesus" at key "FirstName", but found Jesus.
   at FluentAssertions.Execution.LateBoundTestFramework.Throw(String message)
   at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message)
   at FluentAssertions.Execution.DefaultAssertionStrategy.HandleFailure(String message)
   at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
   at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
   at FluentAssertions.Execution.AssertionScope.FailWith(String message, Object[] args)
   at FluentAssertions.Collections.GenericDictionaryAssertions`2.Contain(TKey key, TValue value, String because, Object[] becauseArgs)
   at JWT.Tests.Builder.JwtBuilderDecodeTests.Decode_To_Dictionary_Should_Return_Dictionary_When_Algorithm_Is_Symmetric() in /home/markus/code/jwt/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs:line 313

Note it's complaining it cannot compare "Jesus" with Jesus, when debugging it looks like this:
image

It seems to be boxed to a JsonElement and not a proper string

@hartmark
Copy link
Contributor

hartmark commented Jun 4, 2022

It seems Newtonsoft.Json does some guessing about what the type of the underlying object is and System.Text.Json does the safe way to not assume anything.

So the fix is to add a custom deserializer like this:
https://josef.codes/custom-dictionary-string-object-jsonconverter-for-system-text-json/

I'm going on vacation now and will be away until Tuesday so do a gently poke to me if you don't get it up and running.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
3 participants