0

I'm trying to properly start a returned Task on a background thread so as not to block the UI thread.

The blocking call is done in another class as such:

var tcs = new TaskCompletionSource<T>();
request.BeginGetResponse(() => DoSomethingSlowThenCompleteTCS(tcs));
return tcs.Task;

I assumed I could simply start the task as such (or a million other variations I've tried:

CallThatReturnsTask()
    .ContinueWith(
        x =>
            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                new System.Action(() =>
                {
                    // Some continuation stuff that needs to be on the dispatcher
                }
))).Start();

base.OnActivate(); // Call that needs to run immediately

However I've found that I needed to wrap the returning task in a Task.Run() in order to not block the UI thread. I'm almost 100% certain that doing this defeats the purpose of returning the Task in the first place, but it's the only way I've gotten it working.

Task.Run(() =>
    {
        CallThatReturnsTask()
            .ContinueWith(
                x =>
                    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                        new System.Action(() =>
                        {
                            // Some continuation stuff that needs to be on the dispatcher
                        }
        )));
});

base.OnActivate(); // Call that needs to run immediately

What's the correct way to go about this?

Thanks in advance.

-------------------- Edit 1 --------------------

Is this better? It still seems as if I'm wrapping a task within a task instead of just executing the first task on the correct thread.

Task.Run(() => {
    var result = CallThatReturnsTask().Result;

    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new System.Action(() =>
        {
            // Dispatcher stuff
        }
    ));
});
  • May be a duplicate of http://stackoverflow.com/questions/661561/how-to-update-the-gui-from-another-thread-in-c?rq=1 – Erik Philips Dec 01 '16 at 17:29
  • I don't think you are supposed to `Start` the `TaskCompletionSource` task. The [examples](https://msdn.microsoft.com/en-us/library/dd449174(v=vs.110).aspx#Examples) and related [questions](http://stackoverflow.com/questions/15316613/real-life-scenarios-for-using-taskcompletionsourcet) do not start it. The MSDN example creates a different task to run, similar to how you did `Task.Run(() => ...`. – Quantic Dec 01 '16 at 17:41
  • Note that in most cases (i.e. for true `async` methods) task you get as result is already started and you can't really impact where it started... You may influence choice of thread where it completes with `.ConfigureAwait(false)` for example, but that does not seem to be the question... – Alexei Levenkov Dec 01 '16 at 17:41
  • @Quantic Yeah I tried without Start() as well and the behaviour seems to be the same. The MSDN example uses Task.Result to block and await the result of the task. I don't want to block. The related questions are pretty much spot on what I want but they use await to wait for the result of the task. I've also tried this but my UI is still blocked for whatever reason. – Alexander Hartvig Nielsen Dec 01 '16 at 19:20
  • @AlexeiLevenkov That is actually the case here as far as I can tell. I use the [BeginGetResponse](https://msdn.microsoft.com/en-us/library/system.net.webrequest.begingetresponse(v=vs.110).aspx) method to start an asynchronous web request whose callback completes the TCS. Then I return the task of the TCS. I don't think this task needs to be started? Perhaps I should wrap a Task.Result call in a Task.Run() instead of the current approach? That still seems like I'm wrapping a task inside a task, which seems wrong. – Alexander Hartvig Nielsen Dec 01 '16 at 19:26
  • @AlexeiLevenkov I've added an edit with the above 'solution'. Seems more elegant but still not the proper way? – Alexander Hartvig Nielsen Dec 01 '16 at 19:35
  • I don't know - I don't consider myself to be expert on lower level Task operations. You really can't use `async`? Would be so much easier to read... – Alexei Levenkov Dec 01 '16 at 20:04
  • @AlexeiLevenkov I'm not set on using any specific 'technology', be it Tasks or async. I just haven't been able to implement it and have it work correctly with async/await. I've tried awaiting the Task returned by CallThatReturnsTask(), but that seems to block my UI for some reason (I'd expect it to work) – Alexander Hartvig Nielsen Dec 01 '16 at 20:48
  • @AlexanderHartvigNielsen I strongly suspect that "CallThatReturnsTask" is completely synchronous and hence block the UI. I'd recommend investigate first (i.e. replace `CallThatReturnsTask` with true async mocked version like `Task.Delay(10000);return WhateverResultYouExpect;` and get it working with `async`/`await`) and if you still have problem - ask new one with clear information you discover. – Alexei Levenkov Dec 02 '16 at 15:40
  • Last version of the code looks reasonable and matches exactly what you think you need. – Alexei Levenkov Dec 02 '16 at 15:42
  • @AlexeiLevenkov You may be right, I'll investigate. Thanks for all your help. – Alexander Hartvig Nielsen Dec 04 '16 at 12:15

0 Answers0