Исключение StackOverflowException в WCF с DataContractSerializer и IsReference=true

#wcf #stack-overflow

#wcf #переполнение стека

Вопрос:

Мы разрабатываем приложение с использованием EF4 POCO и WCF 4.0. Мы используем DataContractSerializer и добавили IsReference=true .

Отложенная загрузка отключена, и приложение работало нормально, но теперь мы видим некоторые экземпляры одного из объектов StackOverflowException . Раньше у нас были циклические ссылки, и никаких проблем.

Есть какие-либо подсказки о том, как действовать дальше?

Комментарии:

1. Вы можете подтвердить, что объект, который вызывает это переполнение стека, имеет соответствующий IsReference атрибут? т.Е. Вы где-то не пропустили некоторые атрибуты?

2. Спасибо за предложение, я собираюсь написать средство проверки графа объектов, чтобы сообщить мне, какие классы в графе объектов не имеют атрибута.

3. Выполнил тест.. Ни у каких пользовательских классов не было никаких проблем… Я опубликую тестовый код.

4. Насколько велик ваш объектный граф?

5. Кажется, что граф объектов больше, чем я ожидал. Это не оправдывает исключение stackoveflowexception, но, похоже, мы можем избежать проблемы, избегая таких больших графов объектов.

Ответ №1:

код для проверки проблем, связанных с атрибутом DataContract:

 public class ObjectGraphValidator
{
    List<object> _knownObjects = new List<object>();
    Dictionary<Type, int> _encounteredCount = new Dictionary<Type, int>();
    List<Type> _nonReferenceTypes = new List<Type>();

    public void ValidateObjectGraph(object obj)
    {
        Type type = obj.GetType();
        if (_encounteredCount.ContainsKey(type))
            _encounteredCount[type]  ;
        else
        {
            _encounteredCount.Add(type, 1);
            if (type.IsValueType)
                _nonReferenceTypes.Add(type);
            DataContractAttribute att = Attribute.GetCustomAttribute(type, typeof(DataContractAttribute)) as DataContractAttribute;
            if (att == null || !att.IsReference)
                _nonReferenceTypes.Add(type);
        }

        if (obj.GetType().IsValueType)
            return;
        if (_knownObjects.Contains(obj))
            return;
        _knownObjects.Add(obj);
        if (obj is IEnumerable)
            foreach (object obj2 in (obj as IEnumerable))
                ValidateObjectGraph(obj2);
        foreach (PropertyInfo property in type.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic))
            if (property.GetIndexParameters().Count() == 0)
            {
                object value = property.GetValue(obj, null);
                if (value == null)
                    continue;
                ValidateObjectGraph(value);
            }
    }
}