locked
Async Pattern with WCF Client (Silverlight 5) RRS feed

  • Question

  • Silverlight 5 brought us the Async pattern. It seems as though this has been implemented in Silverlight to some extent. Theoretically, we should now be able to make WCF service calls using the async pattern. But, I've never been able to get it to work. I'm determined to figure this one out...

    This came up the other day so I tried implementing the client code here:

    http://10rem.net/blog/2012/05/22/using-async-and-await-in-silverlight-5-and-net-4-in-visual-studio-11-with-the-async-targeting-pack

    But, I get errors.

    Our WCF service has a method called GetRecord. It takes the record type, the record's PK, and a transaction id. So, I modified the method from this website, and I get this (it's inside an existing auto-generated WCF proxy class):

            public Task<object> GetRecord<T>(object pk, string transactionId)
            {
                var tcs = new TaskCompletionSource<object>();
    
                GetRecordCompleted += (s, e) =>
                {
                    if (e.Error != null)
                        tcs.TrySetException(e.Error);
                    else if (e.Cancelled)
                        tcs.TrySetCanceled();
                    else
                        tcs.TrySetResult(e.Result);
                };
    
                GetRecordAsync<T>(pk, transactionId);
    
                return tcs.Task;
            }

    This method compiles fine. But, when I got to call it like this:

    var result = await proxy.GetRecord<StatusDef>(1, null);

    I get two compilation errors:

    The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.

    and

    Task<object>' does not contain a definition for 'GetAwaiter' and no extension method 'GetAwaiter' accepting a first argument of type 'Task<object>' could be found (are you missing a using directive or an assembly reference?)

    OK. So I'll guess I'll follow the advice and change the method and add the "async" modifer:

            public async Task<object> GetRecord<T>(object pk, string transactionId)
            {
                var tcs = new TaskCompletionSource<object>();
    
                GetRecordCompleted += (s, e) =>
                {
                    if (e.Error != null)
                        tcs.TrySetException(e.Error);
                    else if (e.Cancelled)
                        tcs.TrySetCanceled();
                    else
                        tcs.TrySetResult(e.Result);
                };
    
                GetRecordAsync<T>(pk, transactionId);
    
                return tcs.Task;
            }

    Now, I get a warning on this method:

    This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

    And, the same compilation errors come up. What am I supposed to do?

    Wednesday, October 14, 2015 10:14 PM

All replies

  • Oh, and I thought about changing the return type, and implementing GetAwaiter on that, but I can't get it to compile. Here's the doco on GetAwaiter, but it looks like there is no doco for Silverlight.

    https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.getawaiter%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

    This is the signature:

    public TaskAwaiter GetAwaiter()

    But, TaskAwaiter is conspicuously missing from System.Threading.Tasks in mscorlib on the Silverlight platform.

    So what gives? Is it possible to use the async pattern to call WCF in Silverlight?


    Wednesday, October 14, 2015 10:21 PM
  • I tried yet another approach. This code works in that it executes the WCF method using the normal WCF proxy. I know this because I can catch the entry point on the server side. But, it doesn't wait for the task to complete before continuing on the client side (which is what I'm trying to achieve).

                var proxy = (IGeneralUtilityService)Globals.TheWCFProxyFactory.GetManualServiceClient<IGeneralUtilityServiceClient>();
                var asyncResult = proxy.BeginGetRecord("Adapt.Model.TaskManagement.StatusDef", 1, null, null, null);
                var task = Task.Factory.FromAsync(asyncResult, proxy.EndGetRecord);

    So, the obvious thing to do would be this right?

                var proxy = (IGeneralUtilityService)Globals.TheWCFProxyFactory.GetManualServiceClient<IGeneralUtilityServiceClient>();
                var asyncResult = proxy.BeginGetRecord("Adapt.Model.TaskManagement.StatusDef", 1, null, null, null);
                var task = Task.Factory.FromAsync(asyncResult, proxy.EndGetRecord);
                task.Wait();
    But, this just locks the Silverlight app up on the Wait() call completely. It never executes the WCF call. I know this because on the server side, the "GetRecord" method is never hit. What am I doing wrong? Which approach is the one that works in Silverlight?

    Thursday, October 15, 2015 12:50 AM
  • We tried async with SL5.

    It's not properly implemented. Shonky is the word springs to mind.

    Don't use it.

    We use callbacks instead.


    Hope that helps.

    Technet articles: WPF: MVVM Step 1; All my Technet Articles

    Thursday, October 15, 2015 8:47 AM
    Moderator
  • Andy, yes, I believe you are correct. I just wanted to hear it from the horse's mouth.

    Microsoft, is this true?

    Is the async pattern only half implemented in Silverlight, and therefore useless with WCF?

    A yes, or no would be good.

    Thursday, October 15, 2015 9:37 PM
  • Bump
    Sunday, October 18, 2015 10:21 PM
  • Microsoft, please pick a word:

    Silverlight [does/doesn't] support the async pattern for WCF clients.

    Tuesday, October 20, 2015 12:16 AM
  • Hi MelbourneDeveloper,

    In my opinion, we often use the callback for WCF clients in Silverlight application. I also have a try with Async pattern, but it doesn't work. Please refer to following blog, which introduce Silverlight Async. It also use the callback in Silverlight.

    http://blogs.msdn.com/b/thecrmguys/archive/2012/08/28/silverlight-async-with-visual-studio-2012.aspx

    Best Regards,
    Weiwei

    Wednesday, October 21, 2015 5:07 AM
    Moderator
  • I don't really understand this. On one hand you say:

    "I also have a try with Async pattern, but it doesn't work"

    On the other hand, the article you've linked to says

    "the new async features in .NET 4.5 combined with the Async Targeting Pack provide Silverlight developers with the tools to transform their asynchronous code back to readable, maintainable methods, by removing the need to litter business logic with callbacks and UI dispatching code."

    Is it possible to get a more definitive answer? I just don't want to give up prematurely.

    Wednesday, October 21, 2015 10:14 PM
  • It's not premature to give up.

    It doesn't work.


    Hope that helps.

    Technet articles: WPF: MVVM Step 1; All my Technet Articles

    Thursday, October 22, 2015 8:06 AM
    Moderator
  • OK Andy, I'm willing to take that as an authoritative answer. However, would you mind detailing what you did to investigate this? This is for posterity so that other inquiring mind like my own are satisfied that at least someone has gone to a reasonable degree of effort to prove that this does not work.
    Thursday, October 22, 2015 9:35 PM
  • It's been a while so I'm afraid I don't have any code to show you.

    Just the lingering memory of frustration.

    The best I could do was unreliable.

    I think they were only with calls which were very very quick.

    So my impression is that it could well be that the waiting for the return isn't long enough of maybe just doesn't happen.

    Any sort of unreliable is no good to me, so since then we just don't use async in Silverlight.


    Hope that helps.

    Technet articles: WPF: MVVM Step 1; All my Technet Articles

    Sunday, October 25, 2015 12:29 PM
    Moderator
  • Well, it sounds like you've had the same experience as me.

    I'm still not entirely convinced that it's not possible to use the pattern at all. But, I lean toward thinking that it is.

    I'll leave the thread open for a while, and if I hear nothing, I'll close it on an ambiguous note.

    Sunday, October 25, 2015 9:14 PM