Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

caliburn.micro serialization issue when implementing PropertyChangedBase

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?

like image 267
Rahul Avatar asked Mar 22 '15 22:03

Rahul


1 Answers

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;
like image 156
dbc Avatar answered Nov 16 '22 00:11

dbc