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.
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.
Third, it is neither my place nor this question's to propose a different RPC or messaging framework.
"IEnumerable semantics", for the purpose of this question, are:
- The returned sequence can be arbitrarily large -- it is therefore not possible to convert the sequence to a
List
or similar. - It is not known in advance how many items will be returned
- Caller can just use
foreach
and be done with it.
In a local assembly, a C# interface my look like this:
interface IStuffProvider {
IEnumerable<Stuff> GetItems(); // may open large file or access database
}
You can't map that directly to a WCF service. 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.
One option would be of course to have a client side interface wrapper implementation, that exposes IStuffProvider
and internally forwards to and uses 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.
What are the options we have here with 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.
What I did in the end is have:
a) The OO interface
IStuffProvider
as above with theGetLines()
member as above.b) The WCF service interface (and it's implementation) implements an access pattern like this:
c) The client accesses the service through a proxy class that implements
IStuffProvider
and maps a call to theGetLines()
function to the above three functions: