编辑正如我在评论中提到的,我发现这个问题的原因是Module对象有一个返回OrderInfo对象的引用。默认情况下,DataContractSerializer不支持保留对象引用。我现在已经能够正常工作了。如果有人有兴趣请联系我,我会在这里添加答案。
我不在POCO类中使用datacontract,WCF会自动处理(这可能也是问题。我尝试添加:
[Serializable]
[XmlInclude(typeof(List<Module>))]
但这没有帮助。我无法看到问题是什么,因为我在Module对象中返回一个Pricemodel对象的集合。
public class OrderInfo
{
int _ProductID;
IList<Module> _Modules = new List<Module>();
//IList<MiscProduct> _MiscProduct = new List<MiscProduct>();
public IList<Module> Modules
{
get
{
return new List<Module>(_Modules).AsReadOnly();
}
set
{
_Modules = value;
}
}
}
public class Module
{
string _Name;
int _Sort_Number;
string _Description;
OrderInfo _OrderInfoMaster;
IList<Pricemodel> _Pricemodels = new List<Pricemodel>();
public IList<Pricemodel> Pricemodels
{
get
{
return new List<Pricemodel>(_Pricemodels).AsReadOnly();
}
set
{
_Pricemodels = value;
}
}
}
调用客户端代码是:
using (ProductOrderItems_WCFService.ProductOrderServiceClient client = new ProductOrderItems_WCFService.ProductOrderServiceClient())
{
string s = client.HelloWorld();
Module m = client.GetModule();
List<Module> mods = client.GetModuleList(7);
grdModules.DataSource = mods;
grdModules.DataBind();
OrderInfo oi = client.GetOrderInfo(7);
}
当我从服务请求OrderInfo对象时,它在最后一行失败。以上所有电话都很有效。
答案 0 :(得分:0)
首先是自定义DataContactSerializerOperationBehavior
using System;
using System.ServiceModel.Description;
using System.Runtime.Serialization;
using System.Collections.Generic;
/// <summary>
/// Summary description for ReferencePreservingDataContractSerializerOperationBehavior
/// </summary>
public class ReferencePreservingDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
public ReferencePreservingDataContractSerializerOperationBehavior(OperationDescription operation) : base(operation)
{
}
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes, this.MaxItemsInObjectGraph, this.IgnoreExtensionDataObject, true, this.DataContractSurrogate);
}
public override XmlObjectSerializer CreateSerializer(Type type, System.Xml.XmlDictionaryString name, System.Xml.XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes, this.MaxItemsInObjectGraph, this.IgnoreExtensionDataObject, true, this.DataContractSurrogate);
}
}
接下来是SelfDescribingServiceHost,允许我们使用ReferencePreservingDataContractSerializerOperationBehavior
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace NewWcfService
{
//This class is a custom derivative of ServiceHost
//that can automatically enabled metadata generation
//for any service it hosts.
class SelfDescribingServiceHost : ServiceHost
{
public SelfDescribingServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
}
//Overriding ApplyConfiguration() allows us to
//alter the ServiceDescription prior to opening
//the service host.
protected override void ApplyConfiguration()
{
//First, we call base.ApplyConfiguration()
//to read any configuration that was provided for
//the service we're hosting. After this call,
//this.ServiceDescription describes the service
//as it was configured.
base.ApplyConfiguration();
foreach (ServiceEndpoint endpoint in this.Description.Endpoints)
SetDataContractSerializerBehavior(endpoint.Contract);
//Now that we've populated the ServiceDescription, we can reach into it
//and do interesting things (in this case, we'll add an instance of
//ServiceMetadataBehavior if it's not already there.
ServiceMetadataBehavior mexBehavior = this.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (mexBehavior == null)
{
mexBehavior = new ServiceMetadataBehavior();
this.Description.Behaviors.Add(mexBehavior);
}
else
{
//Metadata behavior has already been configured,
//so we don't have any work to do.
return;
}
//Add a metadata endpoint at each base address
//using the "/mex" addressing convention
foreach (Uri baseAddress in this.BaseAddresses)
{
if (baseAddress.Scheme == Uri.UriSchemeHttp)
{
mexBehavior.HttpGetEnabled = true;
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");
}
else if (baseAddress.Scheme == Uri.UriSchemeHttps)
{
mexBehavior.HttpsGetEnabled = true;
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpsBinding(),
"mex");
}
else if (baseAddress.Scheme == Uri.UriSchemeNetPipe)
{
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexNamedPipeBinding(),
"mex");
}
else if (baseAddress.Scheme == Uri.UriSchemeNetTcp)
{
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexTcpBinding(),
"mex");
}
}
}
private static void SetDataContractSerializerBehavior(ContractDescription contractDescription)
{
foreach (OperationDescription operation in contractDescription.Operations)
{
DataContractSerializerOperationBehavior dcsob = operation.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcsob != null)
{
operation.Behaviors.Remove(dcsob);
}
operation.Behaviors.Add(new ReferencePreservingDataContractSerializerOperationBehavior(operation));
}
}
}
}
然后是ServiceHostFactory:
using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace NewWcfService
{
public class SelfDescribingServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
//All the custom factory does is return a new instance
//of our custom host class. The bulk of the custom logic should
//live in the custom host (as opposed to the factory) for maximum
//reuse value.
return new SelfDescribingServiceHost(serviceType, baseAddresses);
}
}
}
当然Service.svc使用新的HostFactory:
<%@ ServiceHost Language="C#" Debug="true" Service="NewWcfService.Service" Factory="ProTeriaWCF.SelfDescribingServiceHostFactory" CodeBehind="Service.svc.cs" %>
答案 1 :(得分:0)
此错误可能有两个原因;
如果你的返回对象有递归对象,我的意思是你的返回对象和内部对象相互包含,而不是创建序列化问题。您需要在可以决定的级别上剪切递归对象。
值为0的枚举可能会导致此问题。