Getting IEnumerable <T> semantics using the WCF NetTcpBinding service?
Firstly, this is not a duplicate of IEnumerable <T> as a return type for WCF methods , I understand that the WCF architecture only allows passing specific types that can be added to a message.
Secondly, our installation, however, is not a common service, but it connects a proprietary application package through C # + WCF + NetTcpBinding + Protobuf (only) , so we may have more options for some tricks that require more neutral binding.
Thirdly, this is neither my place nor this question to offer another RPC or messaging infrastructure.
"IEnumerable semantics" for the purposes of this question:
- The returned sequence can be arbitrarily large - therefore, it is not possible to convert the sequence to
Listor similar. - It is not known in advance how many items will be returned.
- Caller can just use
foreachand do with it.
In a local assembly, the C # interface looks like this:
interface IStuffProvider { IEnumerable<Stuff> GetItems(); // may open large file or access database } You cannot map this directly to the WCF service. What can achieve the same might look like this:
[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 IStuffProvider and add to the mix than many usage scenarios will involve using both the service and the client on the same machine, so for the “user code” this will not be “It is very important to know that "network" is involved, user code is simply interested in a simple interface.
One option would, of course, be to have a client-side interface wrapper implementation that provides IStuffProvider and internally redirects and uses IStuffService . However, it seems that it would be very advisable not to support two interfaces, one for user code, one exclusively for WCF exchange, especially since all these applications are tightly connected to each other, so the additional abstraction is simply overhead.
What are the options with WCF?
Please note that after reading on it, Streamed Binding seems like a bad decision, since I would still need a client-side wrapper and the service interface would become more complex if it weren’t for the real gain in my case: I don’t need the maximum efficiency of binary transfer, I would like a good implementation + service efficiency.
In the end I did:
a) The OO IStuffProvider , as described above, with the GetLines() element, as described above.
b) The WCF service interface (and its implementation) implements the access pattern as follows:
[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 the GetLines() function call to the following three functions:
// 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); } } Some time ago, we encountered the same WCF limitation in our project. In short, we are done with
interface IStuffProvider { List<Stuff> GetItems(int page, int pageSize); // may open large file or access database } Yes, this is not the same as IEnumerable<Stuff> GetItems(); Yes, we may encounter problems when some item is added / removed on an already received page. Yes, some server-side settings are required if the server works with elements in terms of IEnumerable<Stuff> . But it is still strongly typed and does not bring much additional logic to the client or server.