Question

Initially I had a LINQ query (say EF or any other) with expected deffered execution:

class Provider : IProvider
{
    public IEnumerable<Any> GetSome()
    {
         yield return new Any(); // LINQ query
    }
}

But now such a provider moved into a WCF service (and IoC):

unityContainer.RegisterType<IProvider>(
    new PerResolveLifetimeManager(),
    new InjectionFactory(c => new ChannelFactory<T>("IService").CreateChannel()));

Is it possible to preserve deferred execution over WCF call?

Was it helpful?

Solution

This is answer is actually an answer to your last comment to Ladislav Mrnka. You say:

Okay, I see, so there are no "free donuts" possible. In LINQ to Any we have such behavior but a necessity to cross the service boundaries, i.e. data to be (de)serialized, breaks it, right?

While it doesn't come for free, it is still possible!

On the server side, you would have to provide a method to initialize the request and a method to get the results, one by one.

On the client side - specifically on one of its low level infrastructure classes - you can wrap it in an enumerator and finally, your "business" classes can use that enumerator just like any other.

We already discussed that it will introduce additional overhead in the means of the request-response needed for each item. This will introduce latency and increase the network load.

A sample of this approach using a pseudo RESTful API could look like this:

Server side:

  • POST http://server/api/search-specification:
    The body contains the parameters needed for your search, e.g. start date and end date
    The response will be an URI identifying the search-specification.
  • GET http://server/api/search-specification/1/next-result:
    The response will be the next item.

The controller for this looks something like this:

public Response PostSearchSpecification(SearchSpecification spec)
{
    int id = _searches.Max(x => x.Key) + 1; // Make thread-safe
    _searches[id] = _provider.GetSome().GetEnumerator();
    return ...;
}

public Item GetNextResult(int searchSpecId)
{
    if(_searches[searchSpecId].MoveNext())
        return _searches.Current;
    else
        return null; // or return a HTTP status code that tells the
                     // client that there are no more items.
}

I am calling it a pseudo RESTful API, because it certainly looks like one, but it needs to internally keep state for each specification to enable the deferred execution. Additionally GET http://server/api/search-specification/1/next-result is not idempotent.
But I think it demonstrates what I mean :)

The client side would encapsulate it somehow like this:

class Search
{
    public IEnumerable<Item> Start(params)
    {
        var client = new HttpClient(...);
        var resultsUri = client.Post(new SearchSpecification(params)).Response;
        Item item = client.Get<Item>(resultsUri);
        while(item != null)
        {
            yield return item;
            item = client.Get<Item>(resultsUri);
        }
    }
}

And you would use it like this:

var search = new Search();

foreach(var item in search.Start(...))
    // ...

Just a raw sketch on how you could implement something like this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top