TransferJsonConverter

на русском

The library is designed to serialize objects to JSON and deserialize from JSON. It includes the implementation of the standard class System.Text.Json.Serialization.JsonConverterFactory and several helper classes. Unlike standard serialization/deserialization This library has the following features.

On serialization

The described possibilities can be used as follows. At the storage level, objects are created that contain, among other things, some inherent in this level properties that should not be available at the model level and on the client, such as primary keys. Neither the model nor the client should know how database works. However, they must be able to uniquely refer to an object.

Example:

There is the following set of types:

    public interface ICatForListing
    {
        string Name { get; }
    }

    public enum Latitude { Center, Left, Right }

    public enum Longitude { Center, Front, Rear }

    public interface IPaw
    {
        Latitude latitude { get; }
        Longitude longitude { get; }
    }

    public interface ICat : ICatForListing
    {
        IList Paws { get; }
    }

    public class StringIntId
    {
        public string StringId { get; set; }
        public int IntId { get; set; }
    }

    public class Paw : IPaw
    {
        [Key]
        public StringIntId Id { get; set; }
        [Key]
        public StringIntId CatId { get; set; }
        public Latitude latitude { get; set; }
        public Longitude longitude { get; set; }
    }

    public class Cat : ICat
    {
        [Key]
        public StringIntId Id { get; set; }
        public IList Paws { get; set; }

        public string Name { get; set; }

    }

And the list:

            List cats = new()
            {
                new Cat
                {
                    Id = new StringIntId { StringId = "Havanas", IntId = 1 },
                    Name = "Murzik",
                    Paws = new List()
                    {
                        new Paw
                        {
                            Id = new StringIntId { StringId = "LeftPaws", IntId = 1 },
                            CatId = new StringIntId { StringId = "Havanas", IntId = 1 },
                            latitude = Latitude.Left,
                            longitude = Longitude.Front
                        },
                        new Paw
                        {
                            Id = new StringIntId { StringId = "LeftPaws", IntId = 2 },
                            CatId = new StringIntId { StringId = "Havanas", IntId = 1 },
                            latitude = Latitude.Left,
                            longitude = Longitude.Rear
                        },
                        new Paw
                        {
                            Id = new StringIntId { StringId = "RightPaws", IntId = 1 },
                            CatId = new StringIntId { StringId = "Havanas", IntId = 1 },
                            latitude = Latitude.Right,
                            longitude = Longitude.Front
                        },
                        new Paw
                        {
                            Id = new StringIntId { StringId = "RightPaws", IntId = 2 },
                            CatId = new StringIntId { StringId = "Havanas", IntId = 1 },
                            latitude = Latitude.Right,
                            longitude = Longitude.Rear
                        },
                    }
                },
                new Cat
                {
                    Id = new StringIntId { StringId = "Havanas", IntId = 2 },
                    Name = "Barsik",
                    Paws = new List()
                    {
                        new Paw
                        {
                            Id = new StringIntId { StringId = "LeftPaws", IntId = 3 },
                            CatId = new StringIntId { StringId = "Havanas", IntId = 1 },
                            latitude = Latitude.Left,
                            longitude = Longitude.Front
                        },
                        new Paw
                        {
                            Id = new StringIntId { StringId = "LeftPaws", IntId = 4 },
                            CatId = new StringIntId { StringId = "Havanas", IntId = 1 },
                            latitude = Latitude.Left,
                            longitude = Longitude.Rear
                        },
                        new Paw
                        {
                            Id = new StringIntId { StringId = "RightPaws", IntId = 3 },
                            CatId = new StringIntId { StringId = "Havanas", IntId = 1 },
                            latitude = Latitude.Right,
                            longitude = Longitude.Front
                        },
                        new Paw
                        {
                            Id = new StringIntId { StringId = "RightPaws", IntId = 4 },
                            CatId = new StringIntId { StringId = "Havanas", IntId = 1 },
                            latitude = Latitude.Right,
                            longitude = Longitude.Rear
                        },
                    }
                },
            };

        

Let's send the list to the client, passing only the properties from the ICatForListing interface.

        TransferJsonConverterFactory serializer = new TransferJsonConverterFactory(null)
            .AddTransient<ICatForListing, Cat>()
            ;
        JsonSerializerOptions options = new();
        options.Converters.Add(serializer);
        string json = JsonSerializer.Serialize<List<ICat>>(cats, options);

Get JSON: [{"Id":{"StringId":"Havanas","IntId":1},"Name":"Murzik"},{"Id":{"StringId":"Havanas","IntId":2},"Name":"Barsik"}].

Let's send a single cat to the client, passing properties from the ICat interface.

        TransferJsonConverterFactory serializer = new TransferJsonConverterFactory(null)
            .AddTransient<ICat, Cat>()
            .AddTransient<IPaw, Paw>()
            ;
        JsonSerializerOptions options = new();
        options.Converters.Add(serializer);
        string json = JsonSerializer.Serialize<ICat>(cats[0], options);

Get JSON:

{"Id":{"StringId":"Havanas","IntId":1},"Name":"Murzik",
"Paws":[{"Id":{"StringId":"LeftPaws","IntId":1},"CatId":{StringId":"Havanas","IntId":1},"Latitude":"Left","Longitude":"Front"},
{"Id":{"StringId":"LeftPaws","IntId":2},"CatId":{"StringId":"Havanas","IntId":1},"Latitude":"Left","Longitude":"Rear"},
{"Id":{"StringId":"RightPaws","IntId":3},"CatId":{"StringId":"Havanas","IntId":1},"Latitude":"Right","Longitude":"Front"},
{"Id":{"StringId":"RightPaws","IntId":4},"CatId":{"StringId":"Havanas","IntId":1},"Latitude":"Right","Longitude":"Rear"}]}
.

When deserializing

Example:

Let's get the JSON list from the previous example on the client. Load it into an existing ObservableCollection<ICatForListing> cats;

            TransferJsonConverterFactory serializer = new TransferJsonConverterFactory(null)
                .AddTransient<ICatForListing, Cat>()
                ;
            JsonSerializerOptions options = new();
            options.Converters.Add(serializer);
            serializer.Target = cats;
            JsonSerializer.Deserialize<RewritableListStub<ICatForListing>>(jsonString, options);
        

Here we have overwritten the contents of the collection by applying the RewritableListStub<ICat> stub. We could also add new objects to the collection by applying the AppendableListStub<ICat> stub. This may be required if a large amount of data is being loaded in multiple chunks:

            ...
            JsonSerializer.Deserialize<AppendableListStub<ICat>>(jsonString, options);
        

After that we will have in the collection ObservableCollection<ICatForListing> cats; elements of type ICatForListing and the client is nothing does not know how the database works.

Let's get on the client JSON one cat of the previous example. Let's say we have a property:

        public ICat SelectedCat 
        {
            get
            {
                return _selectedCat;
            }
            set
            {
                _selectedCat = value;
                OnPropertyChanged();
            }
        }
        

We can create a new object and assign it to this property:

            TransferJsonConverterFactory serializer = new TransferJsonConverterFactory(null)
                .AddTransient<ICat, Cat>()
                .AddTransient<IPaw, Paw>()
                ;
            JsonSerializerOptions options = new();
            options.Converters.Add(serializer);
            SelectedCat = JsonSerializer.Deserialize<ICat>(jsonString, options);
        

Or we can use the old object and load new property values into it. In this case, you need to manually notify the UI about the property change:

            TransferJsonConverterFactory serializer = new TransferJsonConverterFactory(null)
                .AddTransient<ICat, Cat>()
                .AddTransient<IPaw, Paw>()
                ;
            JsonSerializerOptions options = new();
            options.Converters.Add(serializer);
            serializer.Target = SelectedCat;
            JsonSerializer.Deserialize<ICat>(jsonString, options);
            OnPropertyChanged(nameof(SelectedCat));
        

In both cases, we have a reference to an object of type ICat, which knows nothing about the database.

In the case of a request to the server, serialization occurs in the same way as described in On serialization. If you want to get data about one cat or delete it, serialize it into a short form ICatForListing, if you want to apply changes - serialize to full form ICat. In this case, JSON will be transmitted with the keys.