简体   繁体   English

获得IEnumerable <T> 使用NetTcpBinding WCF服务的语义?

[英]Getting IEnumerable<T> semantics with a NetTcpBinding WCF service?

First, this is not a duplicate of IEnumerable<T> as return type for WCF methods , I think I understand that the WCF architecture only allows concrete types to be transferred that can be stuffed into a message. 首先,这不是 IEnumerable <T>的副本作为WCF方法的返回类型 ,我想我明白WCF架构只允许传输可以填充到消息中的具体类型。

Second, our setup however is not a general service but connecting up a bundle of proprietary apps via C# + WCF + NetTcpBinding + Protobuf (only) so we may have more room for some tricks that something that needs to be more binding neutral. 其次,我们的设置不是一般服务,而是通过C#+ WCF + NetTcpBinding + Protobuf (仅)连接一组专有应用程序,因此我们可能有更多空间来处理某些需要更具约束力中性的技巧。

Third, it is neither my place nor this question's to propose a different RPC or messaging framework. 第三,提出不同的RPC或消息传递框架既不是我的地方,也不是这个问题。


"IEnumerable semantics", for the purpose of this question, are: 出于这个问题的目的,“IEnumerable语义”是:

  • The returned sequence can be arbitrarily large -- it is therefore not possible to convert the sequence to a List or similar. 返回的顺序可以任意大-因此它是不可能的序列转换成List或相似。
  • It is not known in advance how many items will be returned 事先知道将返还多少物品
  • Caller can just use foreach and be done with it. 来电者可以使用foreach并完成它。

In a local assembly, a C# interface my look like this: 在本地程序集中,C#接口看起来像这样:

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

You can't map that directly to a WCF service. 您无法将其直接映射到WCF服务。 Something that might achieve the same could look like: 可能达到相同效果的东西可能如下:

[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)
}

Of course, using IStuffService will be more error prone than a IStuffProvider and add in to the mix than many usage scenarios would involve using both service and client on the same machine, so for "user code" it wouldn't be super important to be aware that "the network" is involved, the user code is just interested in a simple interface. 当然,使用IStuffServiceIStuffProvider更容易出错并加入混合比许多使用场景涉及在同一台机器上同时使用服务和客户端,因此对于“用户代码”来说,它不是非常重要的。意识到涉及“网络”,用户代码只对简单的界面感兴趣。

One option would be of course to have a client side interface wrapper implementation, that exposes IStuffProvider and internally forwards to and uses IStuffService . 一个选项当然是具有客户端接口包装器实现,它公开IStuffProvider并在内部转发并使用IStuffService However, it seems it would really be desirable to not have to maintain two interfaces, one for user code, one solely for the WCF communication, especially as these applications are all tightly coupled anyway, so the additional abstraction just seems overhead. 然而,现在看来,这真的会希望不必维护两个接口,一个用于用户代码,一个纯粹为WCF通信,特别是因为这些应用程序都是严格反正耦合的,因此额外的抽象似乎只是开销。

What are the options we have here with WCF? 我们在这里使用WCF有哪些选择?


Note that after reading up on it, the Streamed Binding seems a poor solution, as I would still need a wrapper on the client side and the service interface would get more complex for no real gain in my case: I don't need maximum binary transfer efficiency, I would like good implementation + maintenance efficiency. 请注意,在阅读之后, Streamed Binding似乎是一个糟糕的解决方案,因为我仍然需要客户端的包装器,并且服务接口会变得更加复杂,在我的情况下没有真正的好处:我不需要最大的二进制转移效率,我想好的实施+维护效率。

Some time ago we faced the same WCF "restriction" in our project. 前段时间我们在项目中遇到了相同的WCF“限制”。 To be short, we ended up with 简而言之,我们最终得到了

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

Yes, it is not the same as IEnumerable<Stuff> GetItems(); 是的,它与IEnumerable<Stuff> GetItems(); Yes, we can get in troubles when some item added/removed on already received page. 是的,我们可以在已经收到的页面上添加/删除某些项目时遇到麻烦。 Yes, it is required some server-side tweaks, if server works with items in terms of IEnumerable<Stuff> . 是的,如果服务器使用IEnumerable<Stuff>方面的项目,则需要进行一些服务器端调整。 But it is still strictly typed and does not bring much additional logic in the client or the server. 但它仍然是严格类型的,并没有在客户端或服务器中带来太多额外的逻辑。

What I did in the end is have: 我到底做了什么:

a) The OO interface IStuffProvider as above with the GetLines() member as above. a)如上所述的OO 接口 IStuffProvider与上面的GetLines()成员。

b) The WCF service interface (and it's implementation) implements an access pattern like this: 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) The client accesses the service through a proxy class that implements IStuffProvider and maps a call to the GetLines() function to the above three functions: 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);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM