循环引用和WCF

时间:2011-02-11 09:51:48

标签: .net wcf entity-framework entity ado.net-entity-data-model

我使用POCO Generator生成了我的POCO实体,我的数据库中有超过150个表。 我在包括客户端在内的所有应用层共享POCO实体。我在我的上下文中禁用了LazyLoading和ProxyCreation。我在数据访问和业务层之上使用WCF。

现在,当我将poco实体返回给我的客户端时,我收到错误消息“底层连接已关闭”我启用了WCF跟踪并找到了确切的错误: < / em> 包含周期,如果禁用参考跟踪,则无法序列化

我看了MSDN并发现在DataContract方法中设置IsReference = true的解决方案,但我没有使用DataContracts来装饰我的POCO类,我认为也不需要它。如果我用DataContract属性

装饰一个类,我不会将它称为POCO

然后,我找到了解决方案,例如在我的ServiceContracts上应用自定义属性[CyclicReferenceAware]。这确实有效,但我想把这个问题提交给社区,看看其他人如何管理这个问题以及为什么微软没有提供内置支持在序列化POCO类时确定循环引用

3 个答案:

答案 0 :(得分:7)

您已经提到了这种方法,但我使用了这个属性

public class ReferencePreservingDataContractFormatAttribute : Attribute, IOperationBehavior
    {
        #region IOperationBehavior Members
        public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
        {
        }

        public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
        {
            IOperationBehavior innerBehavior = new ReferencePreservingDataContractSerializerOperationBehavior(description);
            innerBehavior.ApplyClientBehavior(description, proxy);
        }

        public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
        {
            IOperationBehavior innerBehavior = new ReferencePreservingDataContractSerializerOperationBehavior(description);
            innerBehavior.ApplyDispatchBehavior(description, dispatch);
        }


        public void Validate(OperationDescription description)
        {
        }
    #endregion
}

} ......以及对服务的操作的参考,如此;

[OperationContract]
[ReferencePreservingDataContractFormat]
IList<SomeObject> Search(string searchString);

仅供参考 - 我希望在到期时给予信任,但没有记录我最初看到上述方法的地方。

编辑:

我相信代码的来源是来自blog post

答案 1 :(得分:0)

我遇到了同样的问题并通过将导航属性从DataContract中排除回父级来解决它

[DataContract]
public partial class Parent
{
        [Key]
        [DataMember]
        public virtual int ParentId { get; set; }

        [DataMember]
        public virtual string ParentName { get; set; }

        [DataMember]
        public virtual Child Child { get; set; }

}

[DataContract]
public partial class Child
{
        [Key]
        [DataMember]
        public virtual int ChildId { get; set; }

        [DataMember]
        public virtual string ChildName { get; set; }

        public virtual List<Parent> Parents {get; set;}
}

答案 2 :(得分:0)

在从WCF服务返回之前,我使用以下调用来展平EntityFramwork POCO实体。它将根据maxLevel值剪切圆形子对象。

    /// <summary>
    ///  Flattern one custom POCO entity.
    ///  Work for resolve the circular reference issues in Entity Framework Code First POCO entity.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entity"></param>
    /// <param name="maxLevel"></param>
    /// <param name="currLevel"></param>
    /// <returns></returns>
    public static T EntityFlatten<T>(this T entity, int maxLevel = 1, int currLevel = 1) where T : class
    {
        if (entity != null)
        {
            var myType = entity.GetType();
            var myAssembly = myType.Assembly;
            var props = myType.GetProperties();

            if (props != null)
            {
                // Walk through all properties defined in the POCO entity.
                foreach (var prop in props)
                {
                    Type typeOfProp = prop.PropertyType;

                    //
                    // If the type is from my assembly == custom type
                    // include it, but flatten its properties.
                    // It is one custom POCO entity.
                    //
                    if (typeOfProp.Assembly == myAssembly)
                    {
                        if (currLevel < maxLevel)
                        {
                            prop.SetValue(entity, EntityFlatten(prop.GetValue(entity, null), maxLevel, currLevel+1));
                        }
                        else
                        {
                            prop.SetValue(entity, null);
                        }
                    }
                    else
                    {
                        //It should be POCO collection property
                        if (typeOfProp.Namespace == "System.Collections.Generic")
                        {
                            if (currLevel < maxLevel)
                            {
                                var originalList = prop.GetValue(entity, null) as IList;

                                if (originalList != null && originalList.Count>0)
                                {
                                    for (int i=0; i<originalList.Count;i++)
                                    {
                                        var item = originalList[i].EntityFlatten(maxLevel, currLevel);
                                        originalList[i] = item;
                                        i++;
                                    }
                                    prop.SetValue(entity, originalList);
                                }
                            }
                            else
                            {
                                prop.SetValue(entity, null);
                            }
                        }
                    }
                }
            }

            return entity;
        }
        else
            return null;
    }

    /// <summary>
    ///  Flatten the POCO entities collection. 
    ///  Work for resolve the circular reference issues in Entity Framework Code First POCO entity.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <param name="maxLevel"></param>
    /// <param name="currentLevel"></param>
    /// <returns></returns>
    public static IList<T> EntitiesFlatten<T>(this IList<T> entities, int maxLevel = 1, int currentLevel = 1) where T : class
    {
        if (entities != null)
        {
            var list = entities as IList<T>;

            for (int i = 0; i < list.Count; i++)
            {
                T entity = list[i];

                entity = entity.EntityFlatten<T>(maxLevel, currentLevel);
            }

            return list;
        }
        else
            return null;
    }