Thu, Jun 10 2010 12:25 PM Marc Jacobi

The context of anonymous methods/lambda's is lost on async proxy calls in SL3 (Updated)

EDIT: This issue was caused by using cached singletons for each proxy (see comments). So the context of anonymous method works correctly, it just appeared it didn't because multiple event handler (lambda's) were registered to the same proxy instance.

We're building an SL3 application that gets its data from a WCF (Ria) Service. The application uses a standard generated proxy (SlSvcUtil.exe) and all calls are done using the familiar async pattern: call a begin method and wait for the completed event. In our SL3 application we have some layers on top of this Proxy:

1) The ServiceAgent - manages the service proxy and transparently recreates it when it is in a Faulted state. It subscribes to the completed event on the proxy and promotes this to the caller (repositories).
2) The Repositories - exposes centralized and cached data access divided bij functional area / domain.
3) The Model (per module) - Each module in the app implements the MVVM pattern and its model accesses the repositories and maps the data from service contracts to module-specific view entities.

Because all data fetching is async we use an eventing mechanism (similar to INotifyPropertyChanged and INotifyCollectionChanged) to communicate'the 'completed' event from the proxy upward through the application.

It was in the implementation of the repositories that I first discovered that something was wrong with the context in which our 'completed' events were raised. Our implementation looked something like this (pseudo code):

public DataEntity GetDataEntity(Guid Id)
{
    DataEntity retVal = new DataEntity();

    using(var proxy = _serviceAgent.GetProxy<RequestDataContract, ResponseDataContract>())
    {
        proxy.RegisterCompletedHandler( (response) =>
            {
                retVal.Property1 = Response.Property1;
                retVal.Property2 = Response.Property2;
                retVal.Property3 = Response.Property3;
            });
        proxy.BeginRequest(new Request(id));
    }
    return retVal;
}

Initially this method returns an empty object that gets mapped to an empty ViewEntity and bound to the UI. When the proxy reports the service call is completed the 'CompletedHandler' is called implemented by the lambda and provides access to the response of the service call. Now the empty DataEntity is filled and these changes are propegated to the ViewEntity (think INotifyPropertyChanged) and in turn the Viewentity notifies its changes to the UI (also INotifyPropertyChanged). This works, no problem.

Untill you place another call to the same repository method while the first is still 'running'. Then the 'context' the lambda needs to fill the retVal is lost and 'overwritten' by the second call. So it may be very well that the result of the first call is written to the retVal of the second call. You can imagine the strange behavior you'll get in your app (and how long it takes to figure out what the problem is ;-).

The solution that I've found is to use the userState that the proxy allows you to sent with a method call. The pseudo code will look something like this:

public DataEntity GetDataEntity(Guid Id)
{
    DataEntity retVal = new DataEntity();

    using(var proxy = _serviceAgent.GetProxy<RequestDataContract, ResponseDataContract>())
    {
        proxy.RegisterCompletedHandler( (response, userState) =>
            {
                DataEntity de = (DataEntity)userState;
                de.Property1 = Response.Property1;
                de.Property2 = Response.Property2;
                de.Property3 = Response.Property3;
            });
        proxy.BeginRequest(new Request(id), retVal);
    }
    return retVal;
}

Now the correct retVal is passed as userState allong with the service call to the proxy and the completed (event) handler will now have access to it when it is called and will be able to set the property values.

I was very suprised that this occurred in my code and it may very well be that I'm doing things wrong, but I don't see it. Any suggestions are welcome.

Hope it helps.

Filed under: , , , ,

# re: The context of anonymous methods/lambda's is lost on async proxy calls in SL3

Thursday, June 10, 2010 2:13 PM by Rogier

Hey Marc,

Is your proxy being cached by your ServiceAgent? In other words: is "_serviceAgent.GetProxy()" returning the same instance?

This would explain the behaviour you're looking at, because you are then registering 2 eventhandlers to the same proxy, which both get called when either of the two async-calls finish.

Just a thought...

grtz,

Rogier.

# re: The context of anonymous methods/lambda's is lost on async proxy calls in SL3

Friday, June 11, 2010 7:10 AM by Marc Jacobi

Hi Rogier,

Thanks for the suggestion. I checked the code real quick and these instances are indeed cached! Thanx!

When I think of it now, it all seems so simple ;-) I will report back with my findings.

# re: The context of anonymous methods/lambda's is lost on async proxy calls in SL3 (Updated)

Tuesday, June 15, 2010 8:18 AM by Marc Jacobi

Just reporting back that indeed it was a state issue with the proxy I returned from GetProxy<RequestT, ResponseT>(). I decided to leave this as is and remove all call-specific state from the proxies.

I have changed the code to a scenario where all state that is related to a service operation call is passed using a new object ServiceOperationContext. You create an instance passing it callback handlers for completion. The instance is passed to BeginRequest() of the proxy and travels as userState with the underlying service proxy call.

I've tested the solution and it surface some additional problem in the code, but once they were resolved, everything works fine.

Thanx Rogier, I owe you one! ;-)

Leave a Comment

(required) 
(required) 
(optional)
(required) 
Please add 5 and 7 and type the answer here: