-2

Running a longProcess() method in one of my C# api and while doing that we want to wait for that task to complete. But same time don't want to block the UI. I saw many SO threads, but nothing helps in my case. Below, Method 1 does not block UI and Method 2, blocks/freezes UI. Any thoughts?

public class MyApiManager
{
    private string _x;

    public MyApiManager(string x) 
    {
        _x = x;
    }

    public void DoProcess()
    {
        // Method 1: Does NOT block UI, but does not wait either
        Task task = Task.Factory.StartNew(() =>
        {
            Task longProcess = Task.Factory.StartNew(new Action(longProcess));
        });
        task.Wait();

        // Method 2: BLOCKS UI, also waits
        //var context = TaskScheduler.FromCurrentSynchronizationContext();
        //Task task = Task.Factory.StartNew(() =>
        //{

        //    var token = Task.Factory.CancellationToken;
        //    Task.Factory.StartNew(() =>
        //    {
        //        longProcess();
        //    }, token, TaskCreationOptions.None, context);

        //});
        //task.Wait();

    }

    private void longProcess()
    {
        // simulate long process
        Thread.Sleep(10000);
    }
}
John Saunders
  • 160,644
  • 26
  • 247
  • 397
Sh Ale
  • 79
  • 1
  • 9
  • Can't understand the problem. Isn't the method1 is what you want? – Renatas M. Nov 18 '14 at 15:35
  • I am not sure why I was down voted :( It is an issue that am facing, I can give more information. – Sh Ale Nov 18 '14 at 16:08
  • @Reniuz, like I said -- need both features of running async (method 1) and at the same time does not freeze (method 2). – Sh Ale Nov 18 '14 at 16:10
  • The way you have presented your question is slightly confusing. What I took from what you said is that Method 1 did not block the UI, so it is doing what you want. What is wrong with Method 1? – TheBlindSpring Nov 18 '14 at 17:06
  • @TheBlindSpring, like I said in the title wait and don't block UI. Again, Method 1 does not block, but it does not wait. Method 2, waits but it blocks UI. – Sh Ale Nov 19 '14 at 02:15
  • Unlike forum sites, we don't use "Thanks", or "Any help appreciated", or signatures on [so]. See "[Should 'Hi', 'thanks,' taglines, and salutations be removed from posts?](http://meta.stackexchange.com/questions/2950/should-hi-thanks-taglines-and-salutations-be-removed-from-posts). – John Saunders Nov 19 '14 at 02:23

2 Answers2

3

First off, you need to separate your concerns.

MyApiManager should not know anything about UIs. It manages APIs, and according to the Single Responsibility Principle, that's all it does.

Read Stephen Toub's Should I expose synchronous wrappers for asynchronous methods?

It should be the UI event handler's responsibility to make sure MyApiManager does not block the UI. So, change your event handler to something like this:

public async void ButtonClick_EventHandler(object o, EventArgs args)
{
    //some code

    await Task.Run(() => apiManager.DoProcess());
    //or await Task.Run(apiManager.DoProcess);

    //some more code
}

Both of your approaches are overly complicated, you're wrapping tasks within tasks, within tasks... Simply use await Task.Run, that's all you need.

dcastro
  • 66,540
  • 21
  • 145
  • 155
  • Sure, agreed regarding Single Responsibility Principle. This is not exactly my code, but trying to duplicate as much as possible to provide enough information. Also, this does not hold my process, that's also something am trying to take care. When that button is clicked, control goes to next task, which I want to hold that. – Sh Ale Nov 18 '14 at 16:14
0

In method 2, TaskScheduler.FromCurrentSynchronizationContext() is likely being called from within your UI code. . . so you get the UI scheduler context.

Next, you schedule your task on the UI thread and longProcess() calls sleep, so you are sleeping on the UI thread. As expected, the UI gets blocked.

iheanyi
  • 3,107
  • 2
  • 23
  • 22