Complex Object won't return when using 'include' syntax in WCF with Entity Version 6

守給你的承諾、 提交于 2019-12-12 20:17:46

问题


Okay so this one has got me stumped as I just see that my client basically disconnects and terminates when returning an object with 'include'. However it works fine without that across a WCF SERVICE. The problem is that I really want those connected objects set up through navigation.

Basically the code is a complex object return:

public teCIF getCif(int aCifId)
        {
            using (CIFContainer context = GetCifContext())
            {
                var thing = context.teCIFs
                    .Include("Product_TYPE")
                    .FirstOrDefault(i => i.CIF_ID == aCifId);

                return thing;
            }
        }

Now the weird thing is that this will work JUST FINE when I comment out the include statement. It is like the complex type being sent over the WCF service does not like the include statement and just says: "nope, not going to do that".

For reference my Complex Object I have already hacked at quite a bit as it is a T4 generated object from a database (abbreviated):

[Serializable]
    public partial class teCIF
    {
        public int CIF_ID { get; set; }
        public string CUSTOMER_NAME { get; set; }
        public string SITE_NAME { get; set; }
        [System.Xml.Serialization.XmlIgnore]
        public int PRODUCT_TYPE_ID { get; set; }

        public virtual tlPRODUCT_TYPE Product_TYPE { get; set; }
    }

Update for linking copmplex item:

[Serializable]
public partial class tlPRODUCT_TYPE
{
    public tlPRODUCT_TYPE()
    {
        this.teCIFs = new HashSet<teCIF>();
    }

    [System.Xml.Serialization.XmlIgnore]
    public int PRODUCT_TYPE_ID { get; set; }
    public string VALUE { get; set; }

    [System.Xml.Serialization.XmlIgnore]
    public virtual ICollection<teCIF> teCIFs { get; set; }
}

I have tried removing attributes but have not yet messed with the 'data member' type that WCF likes. I just don't get why this does not work as I have sworn I have done this in the past Entity Version 4 with complex types with navigation properties related to other complex types.


回答1:


Okay so I actually got help from a friend but figured that this could come up for others so I should answer the question as it may help someone else. I had to add a custom attribute that I make a class for that determines cyclic references. Basically the pointers to the navigation were somehow getting lost when using WCF, but were fine when not hooked up to a service. This is not good as I want my service to be hosting the methods using WCF, not just client calls directly using Entity V6.

    [ServiceContract]
    public interface ICifService
    {

        [OperationContract]
        [CyclicReferencesAware(true)]
        teCIF getCif(int aCifId);
    }

The implementation class works like this:

    using System;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    using System.Runtime.Serialization;
    using System.Xml;
    using System.Collections.Generic;

    [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Method)]
    public class CyclicReferencesAwareAttribute : Attribute, IContractBehavior, IOperationBehavior
    {
        private readonly bool _on = true;

        public CyclicReferencesAwareAttribute(bool on)
        {
            _on = on;
        }

        public bool On
        {
            get { return _on; }
        }

        #region IOperationBehavior Members

        void IOperationBehavior.AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        void IOperationBehavior.ApplyClientBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation)
        {
            CyclicReferencesAwareContractBehavior.ReplaceDataContractSerializerOperationBehavior(operationDescription, On);
        }

        void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
        {
            CyclicReferencesAwareContractBehavior.ReplaceDataContractSerializerOperationBehavior(operationDescription, On);
        }

        void IOperationBehavior.Validate(OperationDescription operationDescription)
        {
        }

        #endregion

        #region IContractBehavior Members

        void IContractBehavior.AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        void IContractBehavior.ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            CyclicReferencesAwareContractBehavior.ReplaceDataContractSerializerOperationBehaviors(contractDescription, On);
        }

        void IContractBehavior.ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
        {
            CyclicReferencesAwareContractBehavior.ReplaceDataContractSerializerOperationBehaviors(contractDescription, On);
        }

        void IContractBehavior.Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        {
        }

        #endregion
    }

    public class CyclicReferencesAwareContractBehavior : IContractBehavior
    {
        private const int MaxItemsInObjectGraph = 2147483647;
        private const bool IgnoreExtensionDataObject = false;

        private bool _on;

        public CyclicReferencesAwareContractBehavior(bool on)
        {
            _on = on;
        }

        #region IContractBehavior Members

        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            ReplaceDataContractSerializerOperationBehaviors(contractDescription, _on);
        }

        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
        {
            ReplaceDataContractSerializerOperationBehaviors(contractDescription, _on);
        }

        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        {
        }

        internal static void ReplaceDataContractSerializerOperationBehaviors(ContractDescription contractDescription, bool on)
        {
            foreach (var operation in contractDescription.Operations)
            {
                ReplaceDataContractSerializerOperationBehavior(operation, on);
            }
        }

        internal static void ReplaceDataContractSerializerOperationBehavior(OperationDescription operation, bool on)
        {
            if (operation.Behaviors.Remove(typeof(DataContractSerializerOperationBehavior)) || operation.Behaviors.Remove(typeof(ApplyCyclicDataContractSerializerOperationBehavior)))
            {
                operation.Behaviors.Add(new ApplyCyclicDataContractSerializerOperationBehavior(operation, MaxItemsInObjectGraph, IgnoreExtensionDataObject, on));
            }
        }
        #endregion
    }

    internal class ApplyCyclicDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
    {
        private readonly int _maxItemsInObjectGraph;
        private readonly bool _ignoreExtensionDataObject;
        private readonly bool _preserveObjectReferences;

        public ApplyCyclicDataContractSerializerOperationBehavior(OperationDescription operationDescription, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool preserveObjectReferences)
            : base(operationDescription)
        {
            _maxItemsInObjectGraph = maxItemsInObjectGraph;
            _ignoreExtensionDataObject = ignoreExtensionDataObject;
            _preserveObjectReferences = preserveObjectReferences;
        }

        public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
        {
            return new DataContractSerializer(type, name, ns, knownTypes, _maxItemsInObjectGraph, _ignoreExtensionDataObject, _preserveObjectReferences, null /*dataContractSurrogate*/);
        }

        public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
        {
            return new DataContractSerializer(type, name, ns, knownTypes, _maxItemsInObjectGraph, _ignoreExtensionDataObject, _preserveObjectReferences, null /*dataContractSurrogate*/);
        }
    }

Once I applied this attribute to any Operation in my interface for my service, it worked fine for any complex type.



来源:https://stackoverflow.com/questions/24922962/complex-object-wont-return-when-using-include-syntax-in-wcf-with-entity-versi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!