views:

246

answers:

1

Hello. Today I have a WCF question, though it probably pertains to other Networking models in .NET as well.

I have a WCF service that exposes a Send(Message) OperationContract, which is OneWay = true. Now this service has a callback channel to return Messages to the client.

Anyway I am trying (successfully) to call this Send method from my Client asynchronously. On a DuplexSessionChannel I am calling BeginSend(Message, OnSendComplete, null) and I have an OnSendComplete(IAsyncResult) method that calls EndSend(asyncResult) on the DuplexSessionChannel.

The service has a CallbackContract and uses the same BeginSend()/EndSend() pattern for sending back to the client, which is called on the callBack channel I get with OperationContext.Current.GetCallbackChannel.

The client on its DuplexSessionChannel calls BeginReceive()/EndReceive() when receiving messages back from the Services callback channel.

Even though things are working, I dont understand what the End<Operation>() methods actually do and this is what I need to have explained to me.

I ask because I am getting an occasional exception in a call to EndSend() on the Service (sending back to the client) complaining that a collection has been modified (I know what this exception means, but not why it is happening or where exactly...). I am using PollingDuplexHttpBinding with a Silverlight client.

I am not a WCF expert, but don't hold back on the details, I need the knowledge. I have seen these sort of Begin/End patterns before around other async operations during my career thus far but never really understood what was going on.

Thanks in advance.

+1  A: 

It sounds like your question is just about the Begin/End APM (async programming model). Briefly, the APM takes a sync method like

R Foo(A a);  // R is some result type, A is some argument type

and breaks it into async BeginFoo and EndFoo methods. The main advantage happens when the operation is doing some truly asynchronous system operation (e.g. talking to the network) that may be long-running (at least compared to other functions; e.g. talking to the network may take hundreds of milliseconds or more). This pattern gives you a way to tell the system to start the operation, and then call you back when the result of the operation is ready. The advantage to the pattern is you don't have to have a managed thread blocked while this call is pending (which means e.g. that you can have thousands of pending network reads/writes without needing thousands of threads, hurray, threads are expensive).

So given that, 'BeginFoo' is how you say 'start the method with these arguments', and then when you get called back (as notification that the result is ready), 'EndFoo' is how you get the result. In the general case, if 'Foo' might throw a particular exception, then this exception might come out of either the 'Begin' call or the 'End' call and you have to be prepared to handle it in both places.

In the case of something like Send() (which maybe returns void? I forget) it's a little annoying/weird because since it's one-way you kinda just want to 'fire-and-forget'. But exceptions can still happen (e.g. I tried to send but someone unplugged my network cable), and so this may yield exceptions... and given the Begin/End APM, such an exception might come out of the EndSend call. In effect, the exception is a kind of 'result' of calling Send, and so you calling EndSend provides a way for the system to throw an exception at you to say something went wrong after you called BeginSend.

Brian
In WCF the IDuplexSessionChannel.BeginSend and EndSend has the following signature:IAsyncResult BeginSend(Message, AsyncCallback, object)void EndSend(IAsyncResult);I call EndSend from inside the callback method that is called by the AsyncCallback delegate passed to BeginSend. Given that EndSend() returns void, I still don't understand what it is for. The "result" as I see it comes from BeginSends AsyncCallback. I also dont understand why BeginSend returns IAsyncResult, when it is also returned asynchronously by the BeginSend AsyncCallback.
MrLane
Reading Brians post again a few months after i posted this question things are MUCH more clear with this pattern. The programming WCF book by Juval Lowery explains this well as well. I still dont know the cause of the exception, but it has been eliminated as I no longer call EndSend(), as I realise there is no results being returned from it anyway. I don't know if this is good practice (perhaps I could be missing exception details), but the book seems to suggest it can be omitted, and since removing things have been much better.
MrLane