0

I am trying to implement the asynchronous pattern in my WCF service. The BeginMethod is called, but the corresponding EndMethod is never called. Debugging the server, putting breakpoints in various places I noticed that callback that is passed to the BeginMethod never returns. I suspect that this is the reason why the EndMethod is never called.

Server code is structured as follows:

IAsyncResult BeginMethod([params], AsyncCallback callback, object asyncState)
{
    var task = Task<MyReturnType>.Factory.StartNew(()=>
    {
        //Do work here
        return value;
    });

    return task.ContinueWith(r=>
        {
            callback(task);
            return r;
        });
} 

MyReturnType EndMethod(IAsyncResult asyncResult)
{
    return ((Task<MyReturnType>)asyncResult).Result;
}

My breakpoint in EndMethod is never reached, and the line callback(task); never returns.

Jesse
  • 915
  • 1
  • 11
  • 20
  • After you've added the service reference, what code are you using to call this endpoint? – Scott Perham Sep 14 '16 at 21:20
  • Well I coded my client code on my own as we didn't want to expose our wsdl. Basically I create a subclass of ClientBase as Well as a subclass of ChannelBase which is used in the overriden `CreateChanel` method. The Channel class implements the Begin, and end methods by calling `BeginInvoke("", args, callback, state)'` and `EndInvoke("", , asynResult)` respectively. – Jesse Sep 14 '16 at 21:29
  • It's actually the callers responsibility to call `EndXXX`, are you explicitly doing this? The `BeginXXX` method will call the synchronous version but you should still need to call `End` to get the return value. – Scott Perham Sep 14 '16 at 21:35
  • Yes, I am calling the `BeginXXX` and `EndXXX`. currently I'm doing it back to back, though I was going to refactor after to make the client asynchronous as well. Do you think this could be what's causing my problem? do I need to wait for the call to finish before calling `EndXXX`? – Jesse Sep 14 '16 at 21:39
  • No that wasn't it, and after thinking about it, that wouldn't make sense anyway. – Jesse Sep 14 '16 at 21:46
  • @ScottPerham, thanks for the help, you got me thinking about what was actually happening here, which ultimately helped me realize the problem. – Jesse Sep 15 '16 at 02:56
  • For the record. WCF calls `EndXXX` automatically, I believe, though have not verified, that it happens as part of the callback that it passes to your start method. Basically the callback was throwing an exception before invoking the end method because the state object was missing, – Jesse Sep 17 '16 at 18:01

1 Answers1

0

The problem was that the callback expects that the IAsyncResult in the case an instance of Task<string> to contain the state object that was passed into the BeginMethod, honestly this should have been obvious, but I was missing it. Different overloads of StarNew and ContinueWith did the trick. Posting my solution in order to save some head scratching for somebody.

IAsyncResult BeginMethod([params], AsyncCallback callback, object asyncState)
{
    var task = Task<MyReturnType>.Factory.StartNew((s)=>
    {
        //Do work here
        return value;
    }, state);

    return task.ContinueWith((t, s)=>
    {
        callback(t);
        return t.Result;
    });
} 

MyReturnType EndMethod(IAsyncResult asyncResult)
{
     return ((Task<MyReturnType>)asyncResult).Result;
}
Jesse
  • 915
  • 1
  • 11
  • 20