【问题标题】:Can a WCF service support both Buffered and Streamed transfer modes?WCF 服务能否同时支持缓冲和流传输模式?
【发布时间】:2013-08-13 22:36:12
【问题描述】:

请注意,这个问题是我尚未解决的当前问题的一个分支:

Need help resolving an error when WCF service returns DataTable: OutOfMemoryException

我有一个现有的 WCF 服务,其端点配置为 TransferMode.Buffered 和一个客户端应用程序,其连接要求相同。

OperationContracts 是既定的方法,除了非常小的方法外,我无法轻易修改。例如,我们有一个接受 SQL 查询 String 并返回从 SQL 执行派生的 DataTable 的方法。

我们在使用这种方法处理非常大的表时遇到了问题。大意味着内存占用。

我正在考虑实现TransferMode.Streamed(或类似的),但我似乎无法掌握如何仅针对某些方法执行此操作。

我的 WCF 服务启动,创建了唯一的端点,该端点是 Buffered。所以这让我们想要假设它是全有或全无。如果我改为Streaming,那么我将不得不对我所有的OperationContract 方法进行大规模返工。

有一些 SO 问题与这个主题有关,但不是直接的,也没有任何真正能把我带到我需要去的地方的答案。

是我遗漏了什么,还是可以让它工作?

我需要修复的方法:(如果想了解连接,请参考引用的问题……代码很多)

WCF 服务代码:

[OperationContract]
DataTable readDataTable(out DbError dbError, String queryString, Boolean SchemaOnly);

public DataTable readDataTable(out DbError dbError, String queryString, Boolean SchemaOnly)
{
    DataTable dt = new DataTable("ReturnTable");
    dbError = new DbError();
    if (!String.IsNullOrEmpty(queryString))
    {
        try
        {
            command.CommandText = queryString.Replace(new String[] { "{{", "}}", ";;" }, new String[] { "{", "}", ";" });
            SqlDataReader reader = command.ExecuteReader(SchemaOnly ? CommandBehavior.SchemaOnly : CommandBehavior.Default);
            dt.Load(reader);
            reader.Close();
        }
        catch (Exception ex)
        {
            dbError.HasError = true;
            dbError.Error = ex.Message + "\n\n" + queryString;
        }
    }
    return dt;
}

使用它的客户端代码:

public DataTable readDataTable(String queryString, Boolean SchemaOnly)
{
    DbError dbError;
    DataTable dt = svcCon.readDataTable(out dbError, queryString, SchemaOnly);
    if (dbError.HasError)
    {
        if (_showErrors)
        ErrorHandler.Show(dbError.Error);
    }
    return dt;
}

【问题讨论】:

    标签: c# wcf .net-3.5


    【解决方案1】:

    这是一个大问题。我明白这个问题。简短的回答是,您不能在同一个端点操作合约中同时拥有流式传输和缓冲。当然,您可以从同一个 Web 服务运行 1 多个单独的端点,每个端点都有不同的端口,例如一些使用缓冲,一些使用流。

    而且,您可以将主机设置为流式传输其响应,而客户端(使用相同的端点)可以将其上传请求缓冲到主机(反之亦然);这不是问题。但是无法缓冲和流式传输来自同一主机端点的响应。

    我们在从 SQL 缓冲下载到客户端时遇到了同样的问题。有一段时间,我们使用流媒体进行下载,主要是为了解决客户端设备超时问题,但发现流媒体也是内存密集型的。我们发现,流媒体作为一种技术也更难使用。所以我们已经从流式传输回到缓冲,但是我们使用交互式“分块”方法来下载 > 100mb。例如,当需要交付 1 GB 的包时,主机将以 100mb 的块发送文件,客户端软件将其组装为单个文件。

    我希望这会有所帮助。

    【讨论】:

    • 布莱恩,感谢您的回复。你正在为我验证我以为我已经知道的事情。你的情况似乎很好地反映了我目前的困境。您能详细介绍一下这种分块方法吗?您使用什么机制来交付块?您可以从我的示例代码中看到客户端需要DataTable 并且服务器会提供。我怎样才能交付这样一个分块的东西? List<DataRow> 的块还是什么?循环?提前致谢。
    • 顺便说一句,我一直在尝试在另一个端口上使用第二个端点运行,但收效甚微。在内部某处,我的ServiceHost 不断被处理,我的 SQLConnection 死了。但我想如果我能解决机械问题,我就能成功。
    • 唐,根据您的评论,我认为我们的要求和您的要求有些不同。我们通过客户端设备用于数据复制的 basicHttpService 文件交付。我们不提供对象或像 DataTable 这样的复杂数据结构。无论如何,分块的工作方式如下:客户端联系我们的 WCF 主机并请求我们存储在 SQL 服务器上的文件。如果文件小于 100 mb,我们只需缓冲整个文件并在响应中将其发送给客户端。
    • 但是如果二进制文件>100mb,它就会被分块。假设客户端请求一个 1gb 的文件。当查询在 SQL 上运行时,我们要做的第一件事是获取二进制文件的 DataLength()。因为大小很大,我们将只检索前 100mb,使用 SQL substring() 函数来获取该部分。当我们在第一个响应中返回 100mb 时,我们还发送了一个名为“ChunkCounter”的变量,该变量将设置为 1,因为这是第一个块。然后客户端再次调用主机,交出 ChunkCounter 值。
    • 这一次,Web 服务将获取 1gb 二进制文件的第二部分 100mb 块,返回字节和 chunkcounter=2 ... 以此类推,直到获取最后一个块。此时,我返回 999 作为块计数器值,它告诉客户端块已完成。
    猜你喜欢
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多