【问题标题】:Getting IEnumerable<T> semantics with a NetTcpBinding WCF service?使用 NetTcpBinding WCF 服务获取 IEnumerable<T> 语义?
【发布时间】:2014-11-17 21:34:50
【问题描述】:

首先,这不是IEnumerable<T> as return type for WCF methods 的重复,我想我理解WCF 架构只允许传输可以填充到消息中的具体类型。

其次,我们的设置不是通用服务,而是通过C# + WCF + NetTcpBinding + Protobuf(仅限) 连接一系列专有应用程序所以我们可能有更多的空间来使用一些需要更具约束力的中立的技巧。

第三,提出不同的 RPC 或消息传递框架既不是我的职责,也不是这个问题。


“IEnumerable 语义”,就这个问题而言,是:

  • 返回的序列可以任意大 - 因此无法将序列转换为 List 或类似的。
  • 提前知道有多少物品会被退回
  • 来电者只需使用foreach 即可。

在本地程序集中,C# 接口看​​起来像这样:

interface IStuffProvider {
  IEnumerable<Stuff> GetItems(); // may open large file or access database
}

您不能将其直接映射到 WCF 服务。可能达到相同效果的东西可能如下所示:

[ServiceContract(SessionMode = SessionMode.Required)]
interface IStuffService {
  [OperationContract]
  void Reset(); // may open large file or access database
  [OperationContract]
  List<Stuff> GetNext(); // return next batch of items (empty list if no more available)
}

当然,使用IStuffService 将比IStuffProvider 更容易出错,并且与许多使用场景在同一台机器上同时使用服务和客户端相比,它更容易出错,因此对于“用户代码”它会意识到涉及“网络”并不重要,用户代码只对简单的界面感兴趣。

一种选择当然是有一个客户端接口包装器实现,它公开IStuffProvider 并在内部转发并使用IStuffService。 然而,似乎确实希望不必必须维护两个接口,一个用于用户代码,一个仅用于 WCF 通信,尤其是因为这些应用程序无论如何都是紧密耦合的,所以额外的抽象似乎只是开销。

WCF 有哪些选择?


请注意,在阅读之后,Streamed Binding 似乎是一个糟糕的解决方案,因为我仍然需要在客户端有一个包装器,并且服务接口会变得更加复杂而没有真正的收益就我而言:我不需要最大的二进制传输效率,我想要好的实现+维护效率。

【问题讨论】:

  • 也许你可以使用WCF提供的Streaming functionality? (不过,我有一段时间没有使用 WCF,所以我不确定它是否合适......)
  • @AasmundEldhuset - 当然值得一读。不过似乎有很多附加条件。
  • WCF 往往是这样的,不是吗? ;-)
  • 任意大 => 流式绑定。不费吹灰之力。
  • @Lucas - 到目前为止我还没有掌握的是流式绑定是否可以应用于任意类型,或者它是否仅适用于bytes ...可能已经是对此的答案这里...

标签: c# wcf protobuf-net nettcpbinding remoteobject


【解决方案1】:

前段时间,我们在项目中遇到了同样的 WCF“限制”。简而言之,我们最终得到了

interface IStuffProvider {
  List<Stuff> GetItems(int page, int pageSize); // may open large file or access database
}

是的,它与IEnumerable&lt;Stuff&gt; GetItems(); 不一样,是的,当在已经收到的页面上添加/删除某些项目时,我们会遇到麻烦。是的,如果服务器根据IEnumerable&lt;Stuff&gt; 处理项目,则需要进行一些服务器端调整。但它仍然是严格类型化的,并没有在客户端或服务端带来太多额外的逻辑。

【讨论】:

  • "请注意,这不是问题的答案,而是一些共同的想法。" - 那么这不应该作为评论发布吗?
  • 这没有提供问题的答案。要批评或要求作者澄清,请在其帖子下方发表评论。
  • @ie。 - 虽然我认为这不适合我的问题,但详细说明了您如何处理数据的初始加载(如果有人首先请求页面5 怎么办?如果多次请求相同的数据怎么办? ) 等。它可以成为一个很好的“替代”答案。至少它看起来技术含量低且易于维护(如果不使用的话)。
  • @TJ 好吧,正如我所写的,我们在项目中面临同样的限制,并且(无论多么悲伤)这是我们案例的答案。因此(并且仅因此)我写了这个作为答案。无论如何,我很高兴看到“真实”的答案。是的,这既不是批评也不是要求,对于这两个我总是使用 cmets ;)
  • @MartinBa 是的,这种方法远非完美,但它是我们解决“顺序”访问问题的方法,它能够在我们想要的时候中断而无需获得其余部分。
【解决方案2】:

我最后做的是有:

a) OO 接口 IStuffProvider 同上,GetLines() 成员同上。

b) WCF 服务接口(及其实现)实现如下访问模式:

    [OperationContract]
    ReadToken StartReadingLines(...);

    [OperationContract]
    // return next batch of items (empty list if no more available)
    List<Stuff> ReadNextLines(ReadToken readToken);

    [OperationContract]
    void FinishReadingLines(ReadToken readToken);

c) 客户端通过实现IStuffProvider代理类访问服务,并将对GetLines()函数的调用映射到上述三个函数:

    // implementation in the proxy class:
    public IEnumerable<Stuff> GetLines()
    {
        var readToken = _dataService.StartReadingLines(...);
        try {
            for (List<Stuff> lines = _dataService.ReadNextLines(readToken); lines.Count > 0; lines = _dataService.ReadNextLines(readToken)) {
                foreach (var line in lines) {
                    yield return line;
                }
            }
        } finally {
            _dataService.FinishReadingLines(readToken);
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-20
    • 1970-01-01
    相关资源
    最近更新 更多