caliburn.micro 实现 PropertyChangedBase 时出现序列化问题

caliburn.micro serialization issue when implementing PropertyChangedBase

我正在开发一个 client/server 数据驱动的应用程序,前端使用 caliburn.micro,后端使用 Asp.net WebApi 2。

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

该应用程序包含一个名为 "Person" 的 class。 "Person" 对象被序列化 (JSON) 并使用简单的 REST 协议在客户端和服务器之间来回移动。该解决方案工作正常,没有任何问题。

问题:

我已经为 "Person" 设置了父级 class "PropertyChangedBase" 以实现 NotifyOfPropertyChanged()。

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

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

但是这次 class "Person" 的属性在接收端有 NULL 值。

我猜序列化/反序列化有问题。 这仅在实施 PropertyChangedBase 时发生。

谁能帮我解决这个问题?

您需要将 [DataContract] attribute to your Person class and the [DataMember] 属性添加到每个 属性 和您希望序列化的字段:

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

    private string _firstName;

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

您需要这样做,因为 caliburn.micro base class PropertyChangedBase 具有 [DataContract] 属性:

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

但为什么这是必要的?理论上,存在 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

但是,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.

(有关确认,请参阅 Question about inheritance behavior of DataContract #872,它确认 Json.NET 的这种行为继续按预期进行。)

所以你毕竟需要添加那些属性。

或者,如果您不想在所有派生的 类 中应用数据协定属性,您可以按照此处的说明切换到 DataContractJsonSerializerJSON 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;