#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);
}
}
}