caliburn.micro serialization issue when implementing PropertyChangedBase
Asked Answered
D

1

6

I'm developing a client/server data driven application using caliburn.micro for frontend and Asp.net WebApi 2 for backend.

public class Person
{
    public int Id {get;set;}
    public string FirstName{get;set;}
    ...
}

The application contains a class called "Person". A "Person" object is serialized (JSON) and moved back and forth from client to server using simple REST protocal. The solution works fine without any problem.

Problem:

I have set a parent class "PropertyChangedBase" for "Person" in order to implement NotifyOfPropertyChanged().

public class Person : PropertyChangedBase
{
    public int Id {get;set;}

    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            _firstName = value;
            NotifyOfPropertyChange(() => FirstName);
        }
    }
    ...
}

But this time the properties of class "Person" has NULL values at receiving end.

I guess there is a problem with serialization / deserialization. This is only happens when implementing PropertyChangedBase.

Can anyone help me to overcome this issue?

Donothingism answered 22/3, 2015 at 22:32 Comment(2)
Which JSON serializer are you using?Dimitri
I'm using HttpClient PostAsJsonAsync . var response = await client.PostAsJsonAsync("api/person", person);Donothingism
D
9

You need to add the [DataContract] attribute to your Person class and the [DataMember] attribute to every property and field you wish to serialize:

[DataContract]
public class Person : PropertyChangedBase
{
    [DataMember]
    public int Id { get; set; }

    private string _firstName;

    [DataMember]
    public string FirstName { get; set; }
}

You need to do this because the caliburn.micro base class PropertyChangedBase has the [DataContract] attribute:

namespace Caliburn.Micro {
    [DataContract]
    public class PropertyChangedBase : INotifyPropertyChangedEx
    {
    }
}

But why should this be necessary? In theory, the presence of the DataContractAttribute applied to the base class should not affect your derived Person class, because DataContractAttribute sets AttributeUsageAttribute.Inherited = false:

[AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Struct|AttributeTargets.Enum, Inherited = false, 
AllowMultiple = false)]
public sealed class DataContractAttribute : Attribute

However, HttpClientExtensions.PostAsJsonAsync uses the default instance of JsonMediaTypeFormatter, which by default uses the Json.NET library to perform serialization. And Json.NET does not respect the Inherited = false attribute of DataContractAttribute, as is explained here

[Json.NET] detects the DataContractAttribute on the base class and assumes opt-in serialization.

(For confirmation see Question about inheritance behavior of DataContract #872 which confirms this behavior of Json.NET continues to be as intended.)

So you need to add those attributes after all.

Alternatively, if you do not want to have to apply data contract attributes all over your derived classes, you could switch to DataContractJsonSerializer following the instructions here: JSON and XML Serialization in ASP.NET Web API:

If you prefer, you can configure the JsonMediaTypeFormatter class to use the DataContractJsonSerializer instead of Json.NET. To do so, set the UseDataContractJsonSerializer property to true:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.UseDataContractJsonSerializer = true;
Dimitri answered 23/3, 2015 at 5:38 Comment(1)
Excellent. I have added the attributes Datacontract & DataMember. It working as expected. Thanks a lot !!!Donothingism

© 2022 - 2024 — McMap. All rights reserved.