222

Summary: I would like to call an asynchronous method in a constructor. Is this possible?

Details: I have a method called getwritings() that parses JSON data. Everything works fine if I just call getwritings() in an async method and put await to left of it. However , when I create a LongListView in my page and try to populate it I'm finding that getWritings() is surprisingly returning null and the LongListView is empty.

To address this problem, I tried changing the return type of getWritings() to Task<List<Writing>> and then retrieving the result in the constructor via getWritings().Result. However, doing that ends up blocking the UI thread.

public partial class Page2 : PhoneApplicationPage
{
    List<Writing> writings;

    public Page2()
    {
        InitializeComponent();
        getWritings();
    }

    private async void getWritings()
    {
        string jsonData = await JsonDataManager.GetJsonAsync("1");
        JObject obj = JObject.Parse(jsonData);
        JArray array = (JArray)obj["posts"];

        for (int i = 0; i < array.Count; i++)
        {
            Writing writing = new Writing();
            writing.content = JsonDataManager.JsonParse(array, i, "content");
            writing.date = JsonDataManager.JsonParse(array, i, "date");
            writing.image = JsonDataManager.JsonParse(array, i, "url");
            writing.summary = JsonDataManager.JsonParse(array, i, "excerpt");
            writing.title = JsonDataManager.JsonParse(array, i, "title");

            writings.Add(writing);
        }

        myLongList.ItemsSource = writings;
    }
}
DavidRR
  • 15,000
  • 17
  • 89
  • 169
Kaan Baris Bayrak
  • 2,613
  • 3
  • 13
  • 20
  • Why do you want to do it in the Constructor? – csharpwinphonexaml Apr 13 '14 at 20:51
  • 6
    i have to call in somewhere otherwise how can i put my data in it any suggestion ? – Kaan Baris Bayrak Apr 13 '14 at 20:54
  • 3
    i would do in the override async void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { //here } – csharpwinphonexaml Apr 13 '14 at 20:55
  • 1
    Why do you need to access the result? Just call getWRitings() or whatever async method and _don't await it_. It won't be done when the constructor ends, but that's ok. Don't use its value there, instead - use its value in another method and call that. – Benjamin Gruenbaum Apr 13 '14 at 21:16
  • thank you this is exactly what i am doing right now and its done :) – Kaan Baris Bayrak Apr 13 '14 at 21:21
  • @KBB I edited your very good question to hopefully make it even more useful to others. In doing so, I made some assumptions about your intent. So, if something doesn't look quite right now, please let me know. Of course, you can certainly edit further or even roll back my changes. – DavidRR May 26 '16 at 12:40
  • @BenjaminGruenbaum In [Async OOP 2: Constructors](http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html) in the concluding section *What NOT To Do,"* [Stephen Cleary](http://stackoverflow.com/users/263693/stephen-cleary) argues that simply not awaiting an asynchronous method in a constructor is *not* a good idea. – DavidRR May 26 '16 at 13:01
  • @DavidRR that's cute, but I disagree with it, there are several cases where you want to perform an asynchronous action but not wait for it. Some cases include: sending analytics, actions where you want to perform I/O and wait for it later (think ` – Benjamin Gruenbaum May 26 '16 at 13:38
  • @BenjaminGruenbaum There is enough substance in your comment that I believe merits turning it into an answer. – DavidRR May 26 '16 at 13:54

13 Answers13

142

The best solution is to acknowledge the asynchronous nature of the download and design for it.

In other words, decide what your application should look like while the data is downloading. Have the page constructor set up that view, and start the download. When the download completes update the page to display the data.

I have a blog post on asynchronous constructors that you may find useful. Also, some MSDN articles; one on asynchronous data-binding (if you're using MVVM) and another on asynchronous best practices (i.e., you should avoid async void).

Stephen Cleary
  • 376,315
  • 69
  • 600
  • 728
  • 12
    Too bad this answer applies specifically for UI code. I'm writing a Windows service that needs the constructor to load some things into memory, with the data coming from some async methods elsewhere. – Ellesedil Nov 26 '14 at 15:45
  • 5
    @Ellesedil: This answer refers to MVVM specifically because this question was asking about MVVM specifically. My [blog post](http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html) is applicable to Win32 services, and you could ask your own question if you wish. – Stephen Cleary Nov 26 '14 at 15:48
  • @Ellesedil I have the same problem as yours, I convert the async to sync and load it to memory... How do you solve this problem? – Bargitta Apr 20 '16 at 03:11
  • 1
    @Matus: First, explore redesigning the type so that it doesn't need asynchronous data at construction time. If that is untenable, then you can [inject an asynchronous factory](http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html). – Stephen Cleary Nov 02 '18 at 17:25
102

You can also do just like this:

Task.Run(() => this.FunctionAsync()).Wait();

Note: Be careful about thread blocking!

Peter Stegnar
  • 11,661
  • 12
  • 58
  • 77
  • 22
    how is that different from `FunctionAsync().Wait()` – Chris Marisic May 21 '15 at 20:03
  • 11
    You should be really careful, because it's not only blocking the thread, but can cause a deadlock (see here e.g.: http://stackoverflow.com/questions/15021304/an-async-await-example-that-causes-a-deadlock). Especially easy to get a deadlock in winforms – Ilya Chernomordik Oct 29 '15 at 09:55
  • 7
    @IlyaChernomordik While it is blocking the thread where the constructor is run, the `this.FunctionAsync()` call is executed in a different thread and upon completion the constructor is resumed. This pattern should actually work, while a direct `this.FunctionAsync().Wait()` would indeed deadlock. The gotcha: do not depend on specific thread affinity inside `FunctionAsync`, because its executing thread can be anything. – grek40 Dec 04 '15 at 07:05
  • 2
    Great for test setup – NeedHack Nov 23 '16 at 11:27
  • 2
    I don't know how to thank you , i have very bad problem and i solved it by your solution that was great – E-housma Mardini Oct 31 '17 at 09:42
  • I have to say that I've tried all the solutions in this thread and this is the only one that worked. I have no idea why .ConfigureAwait(true/false).GetAwaiter().GetResult() or simply .Wait() would work differently from Task.Run(async () => await myAsyncMethod()).Wait(), but they did. – Siderite Zackwehdex Sep 21 '18 at 15:40
  • To add more context, I was executing an async method in the constructor of a web API controller, so there was no way to use different methods of instantiating the controller. The execution had to end before executing the API method called. – Siderite Zackwehdex Sep 21 '18 at 15:41
  • Don't ever call .Wait() or .Result as this is going to lock your app. – Abdullah Tahan Jan 01 '20 at 14:52
  • @ChrisMarisic - if your going to use Wait(), why have it asyncronous? – Sam Oct 13 '20 at 01:07
  • @Sam there's no such thing as an asynchronous constructor, if you don't wait the code likely won't execute at all, or the outcome is indeterminant given the context is exited already. – Chris Marisic Oct 26 '20 at 15:20
74

I'd like to share a pattern that I've been using to solve these kinds of problems. It works rather well I think. Of course, it only works if you have control over what calls the constructor. Example below

public class MyClass
{
    public static async Task<MyClass> Create()
    {
        var myClass = new MyClass();
        await myClass.Initialize();
        return myClass;
    }

    private MyClass()
    {

    }

    private async Task Initialize()
    {
        await Task.Delay(1000); // Do whatever asynchronous work you need to do
    }
}

Basicly what we do is we make the constructor private and make our own public static async method that is responsible for creating an instance of MyClass. By making the constructor private and keeping the static method within the same class we have made sure that noone could "accidently" create an instance of this class without calling the proper initialization methods. All the logic around the creation of the object is still contained within the class (just within a static method).

var myClass1 = new MyClass() // Cannot be done, the constructor is private
var myClass2 = MyClass.Create() // Returns a Task that promises an instance of MyClass once it's finished
var myClass3 = await MyClass.Create() // asynchronously creates and initializes an instance of MyClass

Implemented on the current scenario it would look something like:

public partial class Page2 : PhoneApplicationPage
{
    public static async Task<Page2> Create()
    {
        var page = new Page2();
        await page.getWritings();
        return page;
    }

    List<Writing> writings;

    private Page2()
    {
        InitializeComponent();
    }

    private async Task getWritings()
    {
        string jsonData = await JsonDataManager.GetJsonAsync("1");
        JObject obj = JObject.Parse(jsonData);
        JArray array = (JArray)obj["posts"];

        for (int i = 0; i < array.Count; i++)
        {
            Writing writing = new Writing();
            writing.content = JsonDataManager.JsonParse(array, i, "content");
            writing.date = JsonDataManager.JsonParse(array, i, "date");
            writing.image = JsonDataManager.JsonParse(array, i, "url");
            writing.summary = JsonDataManager.JsonParse(array, i, "excerpt");
            writing.title = JsonDataManager.JsonParse(array, i, "title");

            writings.Add(writing);
        }

        myLongList.ItemsSource = writings;
    }
}

And instead of doing

var page = new Page2();

You would be doing

var page = await Page2.Create();
Shazi
  • 1,138
  • 8
  • 19
  • 2
    This approach uses a [factory pattern](http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html). See another well-received similar answer [here](http://stackoverflow.com/a/12520574/1497596). – DavidRR May 26 '16 at 12:52
  • 2
    How can I use this with dependency injection (constructor injection)? – Sean Stayns Jun 26 '17 at 22:06
  • 2
    Pass the dependencies through the static create – Void May 05 '18 at 11:31
  • Yes, but I need the use this async Create() in the Load() method of my Ninject ApplicationModule. This is because this object is consumed by another object during the injection. There is no way to make an async call in the Application Module. – David Price May 05 '19 at 23:02
  • I just don't get it no matter how long I stare at this. How does this let you call async code from a constructor? – Sam Oct 13 '20 at 02:24
  • It doesn't. It provides an alternate solution to the problem – Shazi Oct 13 '20 at 11:16
7

A quick way to execute some time-consuming operation in any constructor is by creating an action and run them asynchronously.

new Action( async() => await InitializeThingsAsync())();

Running this piece of code will neither block your UI nor leave you with any loose threads. And if you need to update any UI (considering you are not using MVVM approach), you can use the Dispatcher to do so as many have suggested.

A Note: This option only provides you a way to start an execution of a method from the constructor if you don't have any init or onload or navigated overrides. Most likely this will keep on running even after the construction has been completed. Hence the result of this method call may NOT be available in the constructor itself.

Anup Sharma
  • 1,754
  • 16
  • 29
5

Try to replace this:

myLongList.ItemsSource = writings;

with this

Dispatcher.BeginInvoke(() => myLongList.ItemsSource = writings);
csharpwinphonexaml
  • 3,563
  • 10
  • 28
  • 60
4

My preferred approach:

// caution: fire and forget
Task.Run(async () => await someAsyncFunc());
mdlars
  • 827
  • 10
  • 16
  • This does not ensure that the data will be available when you'll want to use them, because the `Task` that creates them is fired-and-forgotten. And in case of an exception the data will never become available. – Theodor Zoulias Oct 30 '19 at 05:33
  • @TheodorZoulias - Correct, however the question reads as follows: "I would like to call an asynchronous method in a constructor. Is this possible?" It's possible to perform, but also make sense to know of the pitfalls. Regardless I don't see this exact implementation in any of the other examples on this thread. Also fire-and-forget may be a valid approach depending on scenario, and I'd argue that "data will never become available" could be resolved with exception handling. I've mostly seen this pattern used with MVVM and Desktop/Mobile where you can use two-way data binding to refresh. – mdlars Oct 30 '19 at 06:16
  • 1
    You have a point. Nevertheless, you should at least make it more prominent that you are initiating a fire-and-forget task. Nowadays it seems that the preferred way to do it is to assign it to a discard: `_ = Task.Run(async...` – Theodor Zoulias Oct 30 '19 at 06:22
  • 1
    @Theodor Zoulias - Thanks for this comment. My compiler was suggesting I refactor to this discard operator earlier today on something and I had no idea what it was talking about. Working on something else right now where this helped and all the sudden clicked. Thanks. – Sam Sep 16 '20 at 21:37
3

To put it simply, referring to Stephen Cleary https://stackoverflow.com/a/23051370/267000

your page on creation should create tasks in constructor and you should declare those tasks as class members or put it in your task pool.

Your data are fetched during these tasks, but these tasks should awaited in the code i.e. on some UI manipulations, i.e. Ok Click etc.

I developped such apps in WP, we had a whole bunch of tasks created on start.

Community
  • 1
  • 1
Dmitry Dyachkov
  • 1,371
  • 2
  • 14
  • 38
1

You could try AsyncMVVM.

Page2.xaml:

<PhoneApplicationPage x:Class="Page2"
                      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <ListView ItemsSource="{Binding Writings}" />
</PhoneApplicationPage>

Page2.xaml.cs:

public partial class Page2
{
    InitializeComponent();
    DataContext = new ViewModel2();
}

ViewModel2.cs:

public class ViewModel2: AsyncBindableBase
{
    public IEnumerable<Writing> Writings
    {
        get { return Property.Get(GetWritingsAsync); }
    }

    private async Task<IEnumerable<Writing>> GetWritingsAsync()
    {
        string jsonData = await JsonDataManager.GetJsonAsync("1");
        JObject obj = JObject.Parse(jsonData);
        JArray array = (JArray)obj["posts"];

        for (int i = 0; i < array.Count; i++)
        {
            Writing writing = new Writing();
            writing.content = JsonDataManager.JsonParse(array, i, "content");
            writing.date = JsonDataManager.JsonParse(array, i, "date");
            writing.image = JsonDataManager.JsonParse(array, i, "url");
            writing.summary = JsonDataManager.JsonParse(array, i, "excerpt");
            writing.title = JsonDataManager.JsonParse(array, i, "title");
            yield return writing;
        }
    }
}
Dmitry Shechtman
  • 5,898
  • 4
  • 23
  • 25
1

Don't ever call .Wait() or .Result as this is going to lock your app. Don't spin up a new Task either, just call the ContinueWith

public class myClass
{
  public myClass
  {
    GetMessageAsync.ContinueWith(GetResultAsync);
  }

  async Task<string> GetMessageAsync()
  {
    return await Service.GetMessageFromAPI(); 
  }
private async Task GetResultAsync(Task<string> resultTask)
{
    if (resultTask.IsFaulted)
{
      Log(resultTask.Exception); 
}
eles
{
 //do what ever you need from the result
}
}
}

https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/consuming-the-task-based-asynchronous-pattern

Abdullah Tahan
  • 1,474
  • 12
  • 21
0

A little late to the party, but I think many are struggling with this...

I've been searching for this as well. And to get your method/action running async without waiting or blocking the thread, you'll need to queue it via the SynchronizationContext, so I came up with this solution:

I've made a helper-class for it.

public static class ASyncHelper
{

    public static void RunAsync(Func<Task> func)
    {
        var context = SynchronizationContext.Current;

        // you don't want to run it on a threadpool. So if it is null, 
        // you're not on a UI thread.
        if (context == null)
            throw new NotSupportedException(
                "The current thread doesn't have a SynchronizationContext");

        // post an Action as async and await the function in it.
        context.Post(new SendOrPostCallback(async state => await func()), null);
    }

    public static void RunAsync<T>(Func<T, Task> func, T argument)
    {
        var context = SynchronizationContext.Current;

        // you don't want to run it on a threadpool. So if it is null, 
        // you're not on a UI thread.
        if (context == null)
            throw new NotSupportedException(
                "The current thread doesn't have a SynchronizationContext");

        // post an Action as async and await the function in it.
        context.Post(new SendOrPostCallback(async state => await func((T)state)), argument);
    }
}

Usage/Example:

public partial class Form1 : Form
{

    private async Task Initialize()
    {
        // replace code here...
        await Task.Delay(1000);
    }

    private async Task Run(string myString)
    {

        // replace code here...
        await Task.Delay(1000);
    }

    public Form1()
    {
        InitializeComponent();

        // you don't have to await nothing.. (the thread must be running)
        ASyncHelper.RunAsync(Initialize);
        ASyncHelper.RunAsync(Run, "test");

        // In your case
        ASyncHelper.RunAsync(getWritings);
    }
}

This works for Windows.Forms and WPF

Jeroen van Langen
  • 18,289
  • 3
  • 33
  • 50
0

In order to use async within the constructor and ensure the data is available when you instantiate the class, you can use this simple pattern:

class FooClass : IFooAsync
{        
    FooClass 
    {
        this.FooAsync = InitFooTask();
    }

    public Task FooAsync { get; }

    private async Task InitFooTask()
    {
        await Task.Delay(5000);
    }
}

The interface:

public interface IFooAsync
{
    Task FooAsync { get; }
}

The usage:

FooClass foo = new FooClass();    
if (foo is IFooAsync)
    await foo.FooAsync;
Shahar Shokrani
  • 4,735
  • 5
  • 31
  • 55
0

Brian Lagunas has shown a solution that I really like. More info his youtube video

Solution:

Add a TaskExtensions method

  public static class TaskExtensions
{
    public static async void Await(this Task task, Action completedCallback = null ,Action<Exception> errorCallBack = null )
    {
        try
        {
            await task;
            completedCallback?.Invoke();
        }
        catch (Exception e)
        {
            errorCallBack?.Invoke(e);
        }
    }
}

Usage:

  public class MyClass
{

    public MyClass()
    {
        DoSomething().Await();
       // DoSomething().Await(Completed, HandleError);
    }

    async Task DoSomething()
    {
        await Task.Delay(3000);
        //Some works here
        //throw new Exception("Thrown in task");
    }

    private void Completed()
    {
        //some thing;
    }

    private void HandleError(Exception ex)
    {
        //handle error
    }

}
Visual Sharp
  • 928
  • 4
  • 15
  • async void methods are only allowed for EventHandlers. Await() with no parameters won't wait, but will do something called fire and forget, where you just start the async process and don't wait for it. At least await task.ConfigureAwait(false) should be called to have save calls in different SynchronisationContexts. – Redwolf Sep 12 '20 at 11:59
  • Well, I thought this was the best hope for me. I'll just have to whimp out. I simply cannot make an async EF Add/Insert from my constuctor in a base controller class. To many hours and days and days and hours at this point. Have to bail and make it synchronous. – Sam Oct 13 '20 at 02:59
  • Actually I am still getting my error but I am using this structure. I think it is helpful to see what is going on. The exception handler is catching my error. – Sam Oct 13 '20 at 03:36
  • @Sam Make the constructor private. Then create a public static async Task Create() method. – Redwolf Oct 26 '20 at 15:24
-2

You could put the async calls in a separate method and call that method in the constructor. Although, this may lead to a situation where some variable values not being available at the time you expect them.

 public NewTravelPageVM(){
   GetVenues();              
 }

 async void  GetVenues(){
   var locator = CrossGeolocator.Current;
   var position = await locator.GetPositionAsync();
   Venues = await Venue.GetVenues(position.Latitude, position.Longitude);
 }
kyun
  • 7,487
  • 4
  • 21
  • 44