views:

569

answers:

1

Hi, I 'm having a problem with WCF callbacks that's a proper head-scratcher...

Description of setup:

There's an interface IService that defines a WCF service. My server app implements that service in class ServiceImplementation. The service also has a callback, defined in IServiceCallback and implemented in the client app in class CallbackImplementation.

At some point, the server calls SomeCallbackOperation on the client app (that operation has [OperationContract(IsOneWay = true)], although I don't think it's important in this context).

The client app, as a result of receiving the callback, must do something that requires fresh information from the server. Therefore, I want as part of my callback implementation to call SomeServiceOperation on the server.

That results in an InvalidOperationException, which instructs me to decorate the callback implementation with CallbackBehaviorAttribute and relax the concurrency mode. (I should mention here that the server already operates with ConcurrencyMode.Multiple). The problem is... I do that and it doesn't work:

[CallbackBehavior(
    AutomaticSessionShutdown = true,
    ConcurrencyMode = ConcurrencyMode.Multiple,
    UseSynchronizationContext = false)]
public partial class CallbackImplementation : IServiceCallback {
    // implementation here
}

Which has left me scratching my head. Calls continue to fail with an InvalidOperationException that says:

This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant or Multiple on CallbackBehaviorAttribute.

Question:

What can be going wrong here?

Clarification:

I fully understand what ConcurrencyMode amounts to. I believe that, in principle, SomeCallbackOperation can easily start a new thread pool thread that calls the server to obtain information and then uses it (such a solution would require some thread access sync mechanism for the "uses it" part). That way the problem could be solved without needing to change the ConcurrencyMode.

However, since I am forced to write the thread access sync mechanism anyway, I would prefer it if WCF at least does the ThreadPool.QueueUserWorkItem part for me and I 'm spared the need to have an extra "async operation" method for each SomeCallbackOperation like the one that has me stumped now.

+1  A: 

You say that your client app needs to do something involving another service call in response to the callback from the server for the first call.

Big question is: do you use the same client proxy instance for that second call to the server? If so, I'm pretty sure that would never work - the client proxy is waiting for the completion of its first call and won't do much before that happens.

So: do you issue your second call to the server, in response to the callback from the first call to the server, using the same client proxy? If so: can you try to use a separate, distinct client proxy instance instead? Does that work?

marc_s
Yes, I 'm calling through the same proxy object, so it's entirely possible that the problem lies there.It's not possible to call through another proxy: among other reasons, all clients register on the server, and the server pushes notifications to all of them when appropriate (i.e. in this scenario). My hypothetical "other" proxy would have the same problem I have now with the first one.So in a nutshell, you 're saying that I 'm limited not by the client-side WCF host (which is appeased by ConcurrencyMode.Multiple), but by the proxy object itself, right?
Jon
Yes, I believe, you can make the WCF service be a multithreaded app (if you really want to deal with all that hassle it brings along), but as far as I see, you cannot make the client proxy a multi-threaded piece - not without a lot of manual effort anyway. The client proxy will block on the first call until that call completes or times out - and during that time, it cannot issue another call back to the server, I believe.
marc_s
I agree with Marc that the client will be waiting on the callback to finish so it can complete its first call due to the fact that the callback channel exists as a result of the initial request channel.If the pattern is that you are using a 'response' from the host to then make another call to the host, perhaps utilizing callbacks is not the best option and instead two explicit calls to the host would be better.
MattK
My WCF knowledge isn't really that deep, so I don't quite understand why a call using a proxy object at the server side, which does not require an answer from the client, would result in me not being able to make a call using a proxy object at the client side. I would think that since I 'm using a TCP binding all sorts of duplex communication can be done.Let me clear something up: there aren't two calls to the server from the same client. The SERVER starts calling back clients to push a notification. Each client wants to call the server inside the callback (to get more info), but cannot.
Jon
Here's a good summary I found of what type of behavior to expect based on contract settings:http://www.dasblonde.net/CommentView,guid,febed89b-c0ea-459a-b870-6e643b8cddb2.aspx
MattK