Ошибка сериализации DataContractJsonSerializer: рассмотрите возможность использования DataContractResolver или добавьте в список любые типы, неизвестные статически

Я расширяю объект, который сериализуется с помощью System.Runtime.Serialization.Json.DataContractJsonSerializer, двумя дополнительными свойствами, которые являются строками (а не сложными типами) по наследству. Используемая версия .NET — .NET 4.
Механизм сериализации отлично работает для базового объекта, но не работает для объекта с двумя дополнительными свойствами, что кажется мне очень странным.
Я использую атрибуты [DataContract] как для базового, так и для унаследованного объекта и все свойства в обоих из них имеют атрибуты [DataMember] с именами.
Оба объекта являются внутренними, но я не понимаю, как это может повлиять на сериализацию дочернего объекта.
Во время отладки я наблюдал, как базовый объект переходит к try заблокировать и сериализовать, а потомок разорвется на строке serializer.WriteObject(ms, sourceObject);
Добавление атрибута известного типа [KnownType(typeof(OnTheMoveBusinessComponentJavaScriptInitObject))] к унаследованному объекту приводит к той же ошибке в том же месте.
Почему я не могу заменить базовый объект унаследованным?

Дочерний объект:

namespace OnTheMoveLibrary.DataControls
{
    [DataContract]
    [KnownType(typeof(OnTheMoveBusinessComponentJavaScriptInitObject))]
    internal class OnTheMoveTreeBusinessComponentJavaScriptInitObject : OnTheMoveBusinessComponentJavaScriptInitObject
    {
        [DataMember(Name = "MasterRecordId")]
        public string MasterRecordId { get; set; }

        [DataMember(Name = "ParentRecordId")]
        public string ParentRecordId { get; set; }
    }
}

Базовый объект:

namespace OnTheMoveLibrary.DataControls
{
    [DataContract]
    internal class OnTheMoveBusinessComponentJavaScriptInitObject : OnTheMoveValidatable
    {
        public OnTheMoveBusinessComponentJavaScriptInitObject()
        {
            this.SqlStatementObject = new OnTheMoveSelectStatement();
            this.PreDefaults = new PreDefaultsObject();
            this.ParentAssociations = new List<ParentAssociation>();
            this.CalculatedFields = new List<OnTheMoveCalculatedField>();
            this.BusinessComponentEvents = new List<BusinessComponentEvent>();
        }

        [DataMember(Name = "sqlStatementObject")]
        public IOnTheMoveSelectStatement SqlStatementObject { get; set; }

        [DataMember(Name = "calculatedFields")]
        public List<OnTheMoveCalculatedField> CalculatedFields { get; set; }

        [DataMember(Name = "knockoutContextName")]
        public string KnockoutContextName { get; set; }

        [DataMember(Name = "observable")]
        public bool Observable { get; set; }

        [DataMember(Name = "integrationObjectNameForNewRecords")]
        public string IntegrationObjectNameForNewRecords { get; set; }

        [DataMember(Name = "singleRecordNewFlag")]
        public bool SingleRecordNewFlag { get; set; }

        [DataMember(Name = "recordIndex")]
        public int? RecordIndex { get; set; }

        [DataMember(Name = "primaryTableName")]
        public string PrimaryTableName { get; set; }

        /// <summary>
        /// The index within the query string of the "RecordId" parameter to use as a parent to insert new records, defaulting to 0
        /// For example, if we have a recordid of "A123,B123" in the querystring, and set ParentQSRecordIdIndex=1, then B123 is used as the parent object when saving
        /// </summary>
        [DataMember(Name = "parentRecordIdQueryStringIndex")]
        public int? ParentRecordIdQueryStringIndex { get; set; }

        [DataMember(Name = "parentAssociations")]
        public List<ParentAssociation> ParentAssociations { get; set; }

        [DataMember(Name = "applyBindings")]
        public bool ApplyBindings { get; set; }

        [DataMember(Name = "PreDefaults")]
        public PreDefaultsObject PreDefaults { get; set; }

        /// <summary>
        /// Gets or sets a list of <see cref="BusinessComponentEvent">BusinessComponentEvents</see>.
        /// </summary>
        [DataMember(Name = "businessComponentEvents")]
        public List<BusinessComponentEvent> BusinessComponentEvents { get; set; }

        [DataMember(Name = "automaticLeadingWildcards")]
        public bool? AutomaticLeadingWildcards { get; set; }

        [DataMember(Name = "automaticTrailingWildcards")]
        public bool? AutomaticTrailingWildcards { get; set; }

        [DataMember(Name = "enableAggregateFields")]
        public bool? EnableAggregateFields { get; set; }

        public override void ValidateProperties()
        {
            this.ValidateProperty("SqlStatementObject", this.SqlStatementObject != null ? this.SqlStatementObject.ToString() : null);
            this.SqlStatementObject.ValidateProperties();
        }
    }
}

Механизм сериализации:

public static string ObjectToJson<TValue>(TValue sourceObject)
    {
        string result = null;
        Type type = typeof(TValue);

        if (type == typeof(object))
        {
            return CallObjectToJsonWithSpecificType(sourceObject);
        }

        Type[] knownTypes = new[] { typeof(OnTheMoveSelectStatement), typeof(OnTheMoveCustomSelectStatement) };
        var serializer = new DataContractJsonSerializer(type, knownTypes);
        var ms = new MemoryStream();
        try
        {
            serializer.WriteObject(ms, sourceObject);
            result = Encoding.UTF8.GetString(ms.ToArray());
        }
        finally
        {
            ms.Close();
        }

        return result;
    }

person Matas Vaitkevicius    schedule 27.06.2014    source источник


Ответы (1)


Сам разобрался.

Вместо того, чтобы добавлять тип базового класса в атрибут к классу, который наследует

[DataContract]
[KnownType(typeof(OnTheMoveBusinessComponentJavaScriptInitObject))]
internal class OnTheMoveTreeBusinessComponentJavaScriptInitObject : OnTheMoveBusinessComponentJavaScriptInitObject

нужно сделать наоборот - добавить к базовому классу атрибут с типом дочернего класса (что ломает весь объектно-ориентированный дизайн, поскольку базовый класс никогда не должен знать, кто от него наследуется).

[DataContract]
[KnownType(typeof(OnTheMoveTreeBusinessComponentJavaScriptInitObject))]
internal class OnTheMoveBusinessComponentJavaScriptInitObject : OnTheMoveValidatable
person Matas Vaitkevicius    schedule 27.06.2014