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

System.Text.Json Breaking change when serializing an array with a custom converter #45833

Closed
kblok opened this issue Dec 9, 2020 · 2 comments
Assignees

Comments

@kblok
Copy link

kblok commented Dec 9, 2020

Description

JsonSerializer.Serialize fails to serialize an array of elements using a JsonConverter that serializes the interface of that element.
This piece of code works on netcore3.1, but it fails on net5.0.
Workarounds will be appreciated.

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace ConverterTests
{
    class Program
    {
        static void Main(string[] args)
        {
            var itemToSerialize = new MainClass
            {
                Items = new[]
                {
                    new ToSerialize{Title = "T1"},
                    new ToSerialize{Title = "T2"},
                }
            };

            var options = new JsonSerializerOptions();
            options.Converters.Add(new Converter());
            Console.WriteLine(JsonSerializer.Serialize(itemToSerialize, options));
            Console.ReadLine();
        }
    }

    public interface IToSerializable
    {
        public string Title { get; set; }
    }
    public class ToSerialize : IToSerializable
    {
        public string Title { get; set; }
    }

    public class MainClass
    {
        public ToSerialize[] Items { get; set; }
    }

    public class Converter : JsonConverter<IToSerializable>
    {
        public override bool CanConvert(Type type) => typeof(IToSerializable).IsAssignableFrom(type);

        public override IToSerializable Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }

        public override void Write(Utf8JsonWriter writer, IToSerializable value, JsonSerializerOptions options)
        {
            writer.WriteString("foo", value.Title);
        }
    }
}
@pablopioli
Copy link

Related to
#45189

Since this is by design, until the situation changes in Net 6 my workaround would be to use Newtonsoft.Json

@eiriktsarpalis
Copy link
Member

Even though this particular example did not fail in .NET Core 3.1, this is by design behavior. Related to #46522.

In order to support multiple types (including type hierarchies) with a single converter implementation, you would need to use a converter factory instead:

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

namespace ConverterTests
{
    class Program
    {
        static void Main(string[] args)
        {
            ToSerialize[] values = new[] { new ToSerialize { Title = "T1" } };

            var options = new JsonSerializerOptions();
            options.Converters.Add(new ConverterFactory());
            Console.WriteLine(JsonSerializer.Serialize(values, options));
        }
    }

    public interface IToSerializable
    {
        public string Title { get; set; }
    }

    public class ToSerialize : IToSerializable
    {
        public string Title { get; set; }
    }

    public class ConverterFactory : JsonConverterFactory
    {
        public override bool CanConvert(Type typeToConvert) => typeof(IToSerializable).IsAssignableFrom(typeToConvert);

        public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
        {
            return (JsonConverter)Activator.CreateInstance(typeof(Converter<>).MakeGenericType(typeToConvert))!;
        }
    }

    public class Converter<ToSerializable> : JsonConverter<ToSerializable> where ToSerializable : IToSerializable
    {
        public override ToSerializable Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }

        public override void Write(Utf8JsonWriter writer, ToSerializable value, JsonSerializerOptions options)
        {
            writer.WriteString("foo", value.Title);
        }
    }
}

@eiriktsarpalis eiriktsarpalis added customer assistance and removed untriaged New issue has not been triaged by the area owner labels Jul 23, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Aug 22, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants