locked
Marshall ContinueWith to UI Thread RRS feed

  • Question

  • I am trying to implement an asynchronous call to a webapi method and update my UI thread in a winforms application.  We are using the DevExpress controls in the winforms app, which are able to marshall the response back to the ui thread for basic controls such as dropdown lists.  However when implementing a grid it is returning an exception that it cant update the datasource of the grid due to the cross threading issues.

    Here is my code to call the web api from the client...

    protected void Get<T>(OnCompleteCallback<T> onCompleteEvent)
    {
        GetAsync<T>(httpClient, 
            addressSuffix, 
            onCompleteEvent,    
            TaskScheduler.FromCurrentSynchronizationContext());
    }
    
    private async void GetAsync<T>(HttpClient client, string url, OnCompleteCallback<T> onComplete, TaskScheduler taskScheduler)
    {
        try
        {
            // Get a reference to the current thread.
            loggingService.Write(LOG_TITLE,
                String.Format("GetAsync requesting data from {0}", url), 
                Constants.LogCategory.Trace);
    
            await client.GetAsync(url).ContinueWith((task) =>
            {
                 HttpResponseMessage response = task.Result;
    
                 loggingService.Write(LOG_TITLE, 
                     String.Format("GetAsync returned data from {0}", url), 
                     Constants.LogCategory.Trace);
    
                 response.Content.ReadAsAsync<T>().ContinueWith((taskResult) =>
                 {
                     loggingService.Write(LOG_TITLE, 
                     String.Format("GetAsync read data from {0}", url), 
                     Constants.LogCategory.Trace);
    
                     onComplete(new OnCompleteEventArgs<T>(taskResult.Result));
    
                 }, taskScheduler);
    
             }, taskScheduler);
         }
         catch (Exception e)
         {
             onComplete(new OnCompleteEventArgs<T>(e));
         }
    }

    oncomplete is a callback which needs to be made on the UI thread.  Taskscheduler is being set from the currentsyncronizationcontext.  However the thread being logged at each logging statement is different.

    Thanks to whomever can answer this question.

    Wednesday, March 13, 2013 4:04 PM

Answers

  • Since you're already using the new async support, you don't need to make it this complicated:

    private async void GetAsync<T>(HttpClient client, string url, OnCompleteCallback<T> onComplete)
    {
        try
        {
            // Get a reference to the current thread.
            loggingService.Write(LOG_TITLE,
                String.Format("GetAsync requesting data from {0}", url), 
                Constants.LogCategory.Trace);
    
            HttpResponseMessage response = await client.GetAsync(url);
    
            loggingService.Write(LOG_TITLE, 
            String.Format("GetAsync returned data from {0}", url), 
                     Constants.LogCategory.Trace);
    
            var result = await response.Content.ReadAsAsync<T>();
    
    
            loggingService.Write(LOG_TITLE, 
                     String.Format("GetAsync read data from {0}", url), 
                     Constants.LogCategory.Trace);
    
            onComplete(new OnCompleteEventArgs<T>(result);
         }
         catch (Exception e)
         {
             onComplete(new OnCompleteEventArgs<T>(e));
         }
    }

    await already pushes things back into the current synchronization context for you...


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Wednesday, March 13, 2013 4:42 PM
    Moderator

All replies

  • Since you're already using the new async support, you don't need to make it this complicated:

    private async void GetAsync<T>(HttpClient client, string url, OnCompleteCallback<T> onComplete)
    {
        try
        {
            // Get a reference to the current thread.
            loggingService.Write(LOG_TITLE,
                String.Format("GetAsync requesting data from {0}", url), 
                Constants.LogCategory.Trace);
    
            HttpResponseMessage response = await client.GetAsync(url);
    
            loggingService.Write(LOG_TITLE, 
            String.Format("GetAsync returned data from {0}", url), 
                     Constants.LogCategory.Trace);
    
            var result = await response.Content.ReadAsAsync<T>();
    
    
            loggingService.Write(LOG_TITLE, 
                     String.Format("GetAsync read data from {0}", url), 
                     Constants.LogCategory.Trace);
    
            onComplete(new OnCompleteEventArgs<T>(result);
         }
         catch (Exception e)
         {
             onComplete(new OnCompleteEventArgs<T>(e));
         }
    }

    await already pushes things back into the current synchronization context for you...


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Wednesday, March 13, 2013 4:42 PM
    Moderator
  • Reed...You are my hero!  I was there all along...but was clearly over-complicating the whole thing.

    THANKS!

    Wednesday, March 13, 2013 5:09 PM