Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
238 views
in Technique[技术] by (71.8m points)

c# - 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...