【问题标题】:The underlying connection was closed: The connection was closed unexpectedly. Data is too big?基础连接已关闭:连接意外关闭。数据太大?
【发布时间】:2014-01-08 19:54:52
【问题描述】:

我有一个服务器/客户端关系,客户端从服务器中提取一个 ArrayList。如果我将服务器设置为始终发送一个空的 ArrayList,那么我不会收到此错误。很明显,问题是我的数据对于连接来说太大了,而且在所有数据都可以通过之前它就关闭了。

我已经研究了这个问题,并添加了这个问题/答案所建议的功能: https://stackoverflow.com/a/285542/3036134许多解决方案都提出了相同的建议。

我相信我实现了一些错误(我认为这很可能是服务行为 MaxItemsInObjectGraph,因为我仍然遇到同样的错误。不幸的是,我无法弄清楚它有什么问题。这是我的代码:

我收到的错误:

CommunicationException was unhandled. The underlying connection was closed: The connection was closed unexpectedly.

我的 WCF 服务代码:

[ServiceContract]
public interface IModelData
{
    [OperationContract]
    ArrayList GetData();
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, MaxItemsInObjectGraph = 2147483647)]
public class ModelDataClient
{
    ChannelFactory<IModelData> HttpFactory;
    IModelData HttpProxy;

    public ModelDataClient()
    {
        HttpFactory = new ChannelFactory<IModelData>(
            new BasicHttpBinding(),
            new EndpointAddress("http://localhost:8000/ModelData"));

        HttpProxy = HttpFactory.CreateChannel();
    }

    public ArrayList GetData()
    {
        return HttpProxy.GetData();
    }
}

[ServiceBehavior(UseSynchronizationContext = false, InstanceContextMode = InstanceContextMode.Single, MaxItemsInObjectGraph = 2147483647)]
public class ModelDataServer : IModelData
{
    public delegate ArrayList GetData();
    public GetData _GetData { get; set; }

    public ModelDataServer()
    {
    }

    public ArrayList GetData()
    {
        return _GetData();
    }
}

我的客户端代码:

public partial class MainForm : Form
{  
    private ModelDataClient Client;

    public MainForm()
    {
        InitializeComponent();

        Client = new ModelDataClient();
    }

    private void Refresh()
    {
        ArrayList dataList = Client.GetData();
        // ********** ERROR POINTS TO LINE ABOVE!!!!!!!!!!!!!!!!!!!!

        // do something with datalist
    }
}   

我的服务器端代码:

public partial class ScraperForm : Form
{
    ServiceHost Host;
    ModelDataServer DataServer;

    ArrayList Data;

    public ScraperForm()
    {
        InitializeComponent();

        #region Start Data Server
        DataServer = new ModelDataServer();
        DataServer._GetData = new ModelDataServer.GetData(this.GetData);

        BasicHttpBinding bhttpb = new BasicHttpBinding();

        bhttpb.MaxBufferSize = 2147483647;
        bhttpb.MaxReceivedMessageSize = 2147483647;
        bhttpb.ReaderQuotas.MaxDepth = 32;
        bhttpb.ReaderQuotas.MaxStringContentLength = 8388608;
        bhttpb.ReaderQuotas.MaxArrayLength = 16384;
        bhttpb.ReaderQuotas.MaxBytesPerRead = 4096;
        bhttpb.ReaderQuotas.MaxNameTableCharCount = 16384;


        Host = new ServiceHost(DataServer, new Uri[]
            {
                new Uri("http://localhost:8000")
            });

        Host.AddServiceEndpoint(typeof(IModelData),
            bhttpb,
            "ModelData");

        Host.Open();

        Data = new ArrayList();
    }

    private void CloseSever()
    {
        Host.Close();
    }

    public void UpdateData() // Run on a timer
    {
        ArrayList Data = new ArrayList()

        // Update Data
    }

    public ArrayList GetData() // This is called by server which is called by client
    {
        return Data;           // no error if I return new ArrayList();
    }
}

编辑:问题是否是由于没有 DataContract/DataMembers 引起的?

更新 我已经使用本教程(以及相关教程)从头开始重建了我的新实现:http://blogs.msdn.com/b/brunoterkaly/archive/2013/10/28/wcf-programming-how-to-write-a-client-app-that-connects-to-a-wcf-service.aspx(对于任何感兴趣的人)。

我没有使用 ArrayList(大量拆箱)和 Typed List(如果与 WCF 一起使用,则以数组形式出现),而是选择使用具有以下格式的字符串传递我的数据: "~" 表示列表中新成员的开始 "," 表示我的自定义数据类型中的一种数据类型的结尾。 所以它可能看起来像 "~NAME,1.29,1,4,123.1~NAME,1.23,3,1,13.2" 等。我建议想要使用列表的人改用它。

我的新实现遇到了一个新问题,可能是相同/相似的问题。请看我的新问题:Object reference not set to an instance of an object - WCF Service and Delegates (WCF Hosted before Delegate is instantiated)

感谢大家的帮助。

【问题讨论】:

  • 我相信服务器和客户端都有限制。
  • 呸!为什么ArrayList?你真的需要一个任意项目的集合吗?
  • @ta.speot.is 是的,我相信上面的代码设置了限制。您是否认为我在此处设置的数据发送过多?我相信这些都设置为最大值
  • 在服务器上设置限制,当然。
  • 我的“数据”是我自己的数据类型列表,称为“RFData”,它由几个双精度数、整数和一个字符串组成。该列表通常包含其中的 10-30 个。我正在使用 arraylist,因为我比自定义数据类型的类型列表更快地读取它。

标签: c# wcf


【解决方案1】:

您的客户端配置为什么?你已经展示了你的服务器端配置,但不要忘记客户端有它自己的配置设置。

查看您的服务器端配置,似乎违规发生在客户端接收数据时。

有关示例,请参阅 here。您也可以通过编程方式执行此操作。

编辑

现在我在 cmets 中看到,您从服务器获取的这个 ArrayList 包含您自己的用户定义类型 RFData。我现在相信这可能是您问题的根源。

数据契约描述了正在交换的数据。客户端和服务器之间使用数据协定对通过网络发送的数据进行序列化和反序列化。在定义要在 WCF 模型中使用的自己的类型时,需要使用数据协定/数据成员。基元以及许多内置 .NET 类型已经具有数据协定。

对于您的 RFData 类型,它将是这样的:

// Apply the DataContract to the type
[DataContract]
public class RFData
{
    // Apply the DataMemberAttribute to the various properties
    [DataMember]
    public double RFDouble { get; set; }
    [DataMember]
    public int RFInt { get; set; }
    [DataMember]
    public string RFString { get; set; }
}

我知道你有几个整数和双精度数,但你明白了要点。 Here 是来自 MSDN 的关于数据合同的非常有用的指南。

【讨论】:

  • 嗨,德里克,感谢您的帮助。我的项目中没有 app.config 文件。还有其他方法可以检索此配置文件吗?
  • @Watson,您应该明确您的客户端/服务器项目类型。 app.config 仅在某些项目中可用。对于其他项目,您应该看到web.configservicereferences.clientconfig。如果您的客户项目是 WinForms 项目,如果尚未在项目中,您可以创建 app.config
  • 感谢您的帮助,德里克,非常感谢。请在我的帖子底部查看我的“更新”。
  • @DerekW 看到上面的评论(忘记打标签了)
猜你喜欢
  • 1970-01-01
  • 2017-06-16
  • 1970-01-01
  • 2013-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-02
  • 1970-01-01
相关资源
最近更新 更多