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

Each parameter in constructor 'Void .ctor(System.Guid, System.String, System.String, System.String, System.String)' on type 'xxxxxxx' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. The match can be case-insensitive. #43563

Closed
logcorner opened this issue Oct 18, 2020 · 5 comments

Comments

@logcorner
Copy link

Hi,
I'm facing an issue when using System.Text.Json. Fields are not correctly Serialized and Deserialized.
and sometimes , I have the er error :
Each parameter in constructor 'Void .ctor(System.Guid, System.String, System.String, System.String, System.String)' on type 'xxxxxxx' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. The match can be case-insensitive.

Here is the code :

 class Program
    {
        static void Main(string[] args)
        {
            var @event = (Event)new SpeechCreatedEvent(Guid.NewGuid(), "title", "event.com", "descriptuion", "type");
            string serializedEvent = JsonSerializer.Serialize(@event);

            var type = @event.GetType().AssemblyQualifiedName;
            var result = (Event)JsonSerializer.Deserialize(serializedEvent, Type.GetType(type));
            Console.WriteLine("Hello World!", result);
        }
    }

namespace ConsoleApp1.Domain
{
    public class SpeechCreatedEvent : Event
    {
        public string Title { get; }
        public string Url { get; }
        public string Description { get; }
        public string Type { get; }

        private SpeechCreatedEvent()
        {

        }
        public SpeechCreatedEvent(Guid id, string title, string url,
            string description, string type)
        {
            AggregateId = id;
            Title = title;
            Url = url;
            Description = description;
            Type = type;
        }
    }

    public abstract class Event : IDomainEvent
    {
        public Guid AggregateId { get; protected set; }

        public Guid EventId => Guid.NewGuid();
        public long AggregateVersion { get; private set; }
        public DateTime OcurrendOn => DateTime.UtcNow;

        public void BuildVersion(long aggregateVersion)
        {
            AggregateVersion = aggregateVersion;
        }
    }

    public interface IDomainEvent
    {
        Guid EventId { get; }
        long AggregateVersion { get; }

        void BuildVersion(long aggregateVersion);
    }
}

the serialization / deserialization works fine using newtonsoft as follows

JsonSerializerSettings settings = new JsonSerializerSettings
             { ContractResolver = new PrivateSetterContractResolver() };
             return (Event)JsonConvert.DeserializeObject(serializedEvent, Type.GetType(eventType), settings);
 private class PrivateSetterContractResolver : DefaultContractResolver
        {
            protected override JsonProperty CreateProperty(
                MemberInfo member,
                MemberSerialization memberSerialization)
            {
                var prop = base.CreateProperty(member, memberSerialization);
                if (!prop.Writable)
                {
                    var property = member as PropertyInfo;
                    if (property != null)
                    {
                        var hasPrivateSetter = property.GetSetMethod(true) != null;
                        prop.Writable = hasPrivateSetter;
                    }
                }
                return prop;
            }
        }

dotnetcore/Home#42

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Oct 18, 2020
@Dotnet-GitSync-Bot
Copy link
Collaborator

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@huoyaoyuan
Copy link
Member

System.Text.Json doesn't support things like contract resolver.
Your class is not simple. In this case you should use [JsonIgnore] and [JsonConstructor] properly.

@logcorner
Copy link
Author

logcorner commented Oct 18, 2020

@huoyaoyuan this classes are on domain layer and I do not want to use json properties on.

NB : it works fine with newtonsoft.json and I would like to move to System.Text.Json.
If System.Text.Json does not support this at this moment, so I have to rollback and continue unsing newtonsoft.json
Regards

@huoyaoyuan
Copy link
Member

it works fine with newtonsoft.json and I would like to move to System.Text.Json

System.Text.Json isn't a drop-in replacement of Newtonsoft.Json, although it's designed with the latter in mind.
It's expected that you cannot migrate certain workloads.

@layomia
Copy link
Contributor

layomia commented Oct 21, 2020

I believe the exception message is pretty clear on what needs to be done here. To make deserialization work as expected, you need to rename the id parameter of the parameterized SpeechCreatedEvent ctor to aggregateId (or some other match case-insensitive match) so that it can bind with the AggregateId property. The reason for this restriction is to ensure that data is always roundtrippable, i.e. we are deserializing only data that could have been the output of serializing a given object. This should be documented, cc @tdykstra.

public SpeechCreatedEvent(Guid aggregateId, string title, string url,
            string description, string type)
{
    AggregateId = aggregateId;
    Title = title;
    Url = url;
    Description = description;
    Type = type;
}

A contract-resolver-like feature isn't implemented in System.Text.Json. I believe this will be considered as part of #34456. Since the parameterless ctor on SpeechCreatedEvent is non-public (meaning the parameterized ctor is the only ctor that JsonSerializer could choose for deserialization), then a contract resolver isn't necessary in this scenario. I believe contract resolver is being discussed because "decorating" the deserialization ctor with [JsonConstructor] is not desired (but as previously mentioned, is not even necessary).

@layomia layomia closed this as completed Oct 21, 2020
@layomia layomia removed the untriaged New issue has not been triaged by the area owner label Oct 21, 2020
@layomia layomia added this to the 6.0.0 milestone Oct 21, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 7, 2020
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