如何修复MaxItemsInObjectGraph错误?

时间:2011-06-09 19:32:10

标签: wcf rest

我有一个RESTful WCF服务,我收到以下错误:在对象图中可以序列化或反序列化的最大项数是'65536'。更改对象图或增加MaxItemsInObjectGraph配额。

我以为我已经解决了这个问题,但显然没有。这是我的代码:

我使用的.SVC文件使用这样的自定义工厂:

<%@ ServiceHost Language="C#" Debug="true" Service="myService" Factory="myCustomWebServiceHostFactory" %>

以下是自定义工厂的代码

public class myCustomWebServiceHost : WebServiceHost
{
    public myCustomWebServiceHost()
    {
    }

    public myCustomWebServiceHost(object singletonInstance, params Uri[] baseAddresses)
        : base(singletonInstance, baseAddresses)
    {
    }

    public myCustomWebServiceHost(Type serviceType, params Uri[] baseAddresses)
        : base(serviceType, baseAddresses)
    {
    }

    protected override void OnOpening()
    {
        foreach (var endpoint in Description.Endpoints)
        {
            var binding = endpoint.Binding as WebHttpBinding;
            if (binding != null)
            {
                const int fiveMegaBytes = 5242880;
                binding.MaxReceivedMessageSize = fiveMegaBytes;
                binding.MaxBufferSize = fiveMegaBytes;
                binding.MaxBufferPoolSize = fiveMegaBytes;
            }
        }
        base.OnOpening();
    }
}

class myCustomWebServiceHostFactory : WebServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return new myCustomWebServiceHost(serviceType, baseAddresses);
    }
}

服务:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceContract]
[ServiceBehavior(MaxItemsInObjectGraph = int.MaxValue)]
public class myService
{
...service implementation code goes here
}

客户端:

public class myClient
{
    WebChannelFactory<IMyService> cf;
    IMyService channel;

    public myClient()
    {
        WebHttpBinding _binding = new WebHttpBinding();
        _binding.MaxBufferPoolSize = 5000000;
        _binding.MaxBufferSize = 5000000;
        _binding.MaxReceivedMessageSize = 5000000;
        _binding.TransferMode = TransferMode.Streamed;
        _binding.ReceiveTimeout = new TimeSpan(0, 0, 30);
        _binding.ReaderQuotas.MaxArrayLength = 5000000;
        Uri _uri = new Uri("http://myserviceurl");
        cf = new WebChannelFactory<IMyService>(_binding, _uri);
        channel = cf.CreateChannel();
        foreach (OperationDescription op in cf.Endpoint.Contract.Operations)
        {
            var dataContractBehavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>();
            if (dataContractBehavior != null)
            {
                dataContractBehavior.MaxItemsInObjectGraph = int.MaxValue;
            }
        }
    }
        ...client implementation code goes here
}

更新:我做了一些故障排除。似乎序列化部分在服务器上正常工作。我能够从浏览器进行GET,并以XML格式接收所有数据。所以这很好。它似乎是导致错误的反序列化部分。如果您在myClient的代码中查看上面的内容,您将看到我如何尝试为DataContractSerializer行为设置MaxItemsInObjectGraph属性。我这样做了吗?

4 个答案:

答案 0 :(得分:23)

我想通了!我的客户端代码错了。 我已经创建了我的频道后,我正在设置MaxItemsInObjectGraph 。因此,MaxItemInObjectGraph属性对已创建的通道没有影响。 (这个WCF的东西对我来说太混乱了 - 我通常只是在不知道自己在做什么的情况下复制和粘贴代码)以下是更正后的代码:

        WebHttpBinding _binding = new WebHttpBinding();
        _binding.MaxBufferPoolSize = 5000000;
        _binding.MaxBufferSize = 5000000;
        _binding.MaxReceivedMessageSize = 5000000;
        _binding.TransferMode = TransferMode.Streamed;
        _binding.ReceiveTimeout = new TimeSpan(0, 0, 30);
        _binding.ReaderQuotas.MaxArrayLength = 5000000;
        Uri _uri = new Uri(http://myserviceurl);
        cf = new WebChannelFactory<IMyService>(_binding, _uri);
        foreach (OperationDescription op in cf.Endpoint.Contract.Operations)
        {
            var dataContractBehavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>();
            if (dataContractBehavior != null)
            {
                dataContractBehavior.MaxItemsInObjectGraph = int.MaxValue;
            }
        }
        channel = cf.CreateChannel();

答案 1 :(得分:4)

您需要使用客户端和服务上的行为在dataContractSerializer上设置MaxItemsInObjectGraph。有关示例,请参阅here

答案 2 :(得分:0)

在客户端,实现此目的的另一种方法是创建自定义IEndPointBehavior实现 - 请参阅http://canbilgin.wordpress.com/2010/06/25/how-to-set-maxitemsinobjectgraph-programmatically-for-client/

在使用Windsor WcfFacility

实现客户端时,这尤其有用
public class ReaderQuotaExtension : IEndpointBehavior
{
    #region Implementation of IEndpointBehavior

    public void Validate(ServiceEndpoint endpoint)
    {
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        ModifyDataContractSerializerBehavior(endpoint);
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        ModifyDataContractSerializerBehavior(endpoint);
    }

    #endregion

    private static void ModifyDataContractSerializerBehavior(ServiceEndpoint endpoint)
    {
        foreach (var behavior in endpoint.Contract.Operations.Select(operation => operation.Behaviors.Find<DataContractSerializerOperationBehavior>()))
        {
            behavior.MaxItemsInObjectGraph = 2147483647;
        }
    }

答案 3 :(得分:0)

您将在查询中返回一个通用列表或大小超过65536的数组。使用select top 60000或不添加超过60k的元素将解决您的问题。