Since this morning, I have to load/stress test a WCF service and concurrency access (within an app console to be simple), but the WCF service is totally opaque to me. I can't edit it or view the source code.
What I've tried so far :
So, in the Main() program, I am calling a method to initialize some services :
private static void Init()
{
_serviceCommunicationMock = Mock.Of<ITrackingCommunicationService>();
Mock.Get(_serviceCommunicationMock).Setup(x => x.GetIdentityCardAsync(It.IsAny<string>())).ReturnsAsync(() =>
{
new TrackingWcfCommunicationOptions
{
EndPointAddress = "http://172.16.0.2/IIT/[COMPANY].Tracking/TrackingService"
};
string jsonContent = System.IO.File.ReadAllText(GetRandomFile());
return jsonContent.Parse();
});
_serviceValidationMock = Mock.Of<IIdentityCardValidation>();
Mock.Get(_serviceValidationMock).Setup(x => x.VerifyProductIdentityCard(It.IsAny<IdentityCard>())).Returns(
new [COMPANY].Tracking.Core.Business.Model.ResultValidation()
{
IsValid = true,
ErrorMessages = new List<string>()
});
_trackingManager = new TrackingManager(_serviceCommunicationMock, _serviceValidationMock);
}
After this, I'm calling an other method to try to stress tests my WCF as following :
private async static void DoSomething()
{
var taskList = new List<Task<IdentityCard>>();
for (int iterator = 0; iterator < 1; iterator++)
{
async Task<IdentityCard> func()
{
var response = await _trackingManager.GetIdentityCardAsync("Vhdn3UpJsDp6ue6LQWy5gZ");
return response;
}
taskList.Add(func());
}
await Task.WhenAll(taskList);
foreach (var task in taskList)
{
Console.WriteLine(task.Result);
}
}
But the problem is in the Init() method, it already returns a random file but I excepted to call the _trackingManager.GetIdentityCardAsync([GUID]). But it simple impossible as I'm a beginner in Moq AND in WCF.
Could someone help me ?
I am runnning a public front facing api that hardly scale for now. This API is built upon Asp.Net web API 2 (.Net 4.7.2). This
The problem that I have is that from this entry point the service have to make multiple calls to others internal services exposing their Rest interface.
We have made some optimisation :
to make all those call asynchronous (async/await).
All the services (public facing one as well as internal) are load balanced and we have put in place 4 servers with hight memory ram/cpu (64 gb, 8cpu each)
But when we have sudden burst of load , or when we make some stress tests we see that we have a pain to scale up : the response time start to increase and we could not achieve more than 150 req/s
and average of response is 2.5 sec while all the time seem to been spend in the network latency wainting each internal service to respond....
So I was thinking if it was possible to buffer a bunch of requests and make a batch call to the internal apis to get the details to combine and then answer the callers.
My idea would be to have a special kind of static httpClient with an async method that would bufferize the calls and will make a request when either there is a special count of calls bufferized or when
a limit of few ms have elapsed : that way when we are under load our API could make few network calls and be more responsive...
I know that somes are also using a mom/bus for that like Kafka for example , but it seems to me that going this way will only let us have eaven more paralell calls to handle but no real gain
on the speed.. (I may be wrong on that)
To illustrate what I have in mind :
Do you think that this could be done using Reactive (for observe either the delay spent, or the count of messages bufferized)/TPL Dataflow (in order to fill a block and then make a batch call) ?
I have this idea in mind but I do not know if it is a good idea, and how to make it work...
UPDATE :
Find here the usefull sample code provided by Theodor Zoulias :
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
static class Program
{
public static async Task Main()
{
var execution = new BatchExecution<int, int>(async (int[] inputs) =>
{
Print($"Processing [{String.Join(", ", inputs)}]");
await Task.Yield() ;
return inputs.Select(x => x * 10).ToArray();
}, batchSize: 3);
Task[] workers = Enumerable.Range(1, 10).Select(id => Task.Run(async () =>
{
//await Task.Delay(id * 50);
Print($"Before InvokeAsync({id})");
var result = await execution.InvokeAsync(id);
Print($"After await InvokeAsync({id}), result is {result}");
})).ToArray();
await Task.WhenAll(workers);
}
static void Print(string line)
{
Console.WriteLine($#"{DateTime.Now:HH:mm:ss.fff} [{Thread.CurrentThread
.ManagedThreadId}] > {line}");
}
public class BatchExecution<TInput, TOutput>
{
private class AsyncOperation : TaskCompletionSource<TOutput>
{
public AsyncOperation() :
base(TaskCreationOptions.RunContinuationsAsynchronously)
{ }
public TInput Input { get; init; }
}
private readonly BatchBlock<AsyncOperation> _batchBlock;
private readonly ActionBlock<AsyncOperation[]> _actionBlock;
public BatchExecution(
Func<TInput[], Task<TOutput[]>> batchAction,
int batchSize,
int maximumConcurrency = DataflowBlockOptions.Unbounded)
{
_batchBlock = new BatchBlock<AsyncOperation>(batchSize);
_actionBlock = new ActionBlock<AsyncOperation[]>(async operations =>
{
try
{
TInput[] inputs = operations.Select(x => x.Input).ToArray();
TOutput[] results = await batchAction(inputs);
if (results.Length != inputs.Length)
throw new InvalidOperationException("Results count mismatch.");
for (int i = 0; i < operations.Length; i++)
operations[i].SetResult(results[i]);
}
catch (OperationCanceledException oce)
{
Array.ForEach(operations, x => x.TrySetCanceled(oce.CancellationToken));
}
catch (Exception ex)
{
Array.ForEach(operations, x => x.TrySetException(ex));
}
}, new() { MaxDegreeOfParallelism = maximumConcurrency });
_batchBlock.LinkTo(_actionBlock, new() { PropagateCompletion = true });
}
public Task<TOutput> InvokeAsync(TInput input)
{
var operation = new AsyncOperation() { Input = input };
bool accepted = _batchBlock.Post(operation);
if (!accepted) throw new InvalidOperationException(
"The component has been marked as complete.");
return operation.Task;
}
public void Complete() => _batchBlock.Complete();
public Task Completion => _actionBlock.Completion;
}
}
I need some feedback/advice on the way I am doing that : is that possible to do what I am after with Reactive/TPL and a httpClient or is there a better way to do it ?
Here is a BatchExecution class, that accepts individual requests, and invokes a batch operation when the number of stored requests reaches a specified number (batchSize). The results of the batch operation are propagated to the associated individual requests:
public class BatchExecution<TInput, TOutput>
{
private class AsyncOperation : TaskCompletionSource<TOutput>
{
public AsyncOperation() :
base(TaskCreationOptions.RunContinuationsAsynchronously) { }
public TInput Input { get; init; }
}
private readonly BatchBlock<AsyncOperation> _batchBlock;
private readonly ActionBlock<AsyncOperation[]> _actionBlock;
public BatchExecution(
Func<TInput[], Task<TOutput[]>> batchAction,
int batchSize,
int maximumConcurrency = DataflowBlockOptions.Unbounded)
{
_batchBlock = new BatchBlock<AsyncOperation>(batchSize);
_actionBlock = new ActionBlock<AsyncOperation[]>(async operations =>
{
try
{
TInput[] inputs = operations.Select(x => x.Input).ToArray();
TOutput[] results = await batchAction(inputs);
if (results.Length != inputs.Length)
throw new InvalidOperationException("Results count mismatch.");
for (int i = 0; i < operations.Length; i++)
operations[i].SetResult(results[i]);
}
catch (OperationCanceledException oce)
{
Array.ForEach(operations, x => x.TrySetCanceled(oce.CancellationToken));
}
catch (Exception ex)
{
Array.ForEach(operations, x => x.TrySetException(ex));
}
}, new() { MaxDegreeOfParallelism = maximumConcurrency });
_batchBlock.LinkTo(_actionBlock, new() { PropagateCompletion = true });
}
public Task<TOutput> InvokeAsync(TInput input)
{
var operation = new AsyncOperation() { Input = input };
bool accepted = _batchBlock.Post(operation);
if (!accepted) throw new InvalidOperationException(
"The component has been marked as complete.");
return operation.Task;
}
public void Complete() => _batchBlock.Complete();
public Task Completion => _actionBlock.Completion;
}
Usage example. Let's assume the existence of this internal service API:
Task<string[]> GetCityNamesAsync(int[] ids);
The BatchExecution could then be initialized and used like this:
var batchExecution = new BatchExecution<int, string>(async (int[] ids) =>
{
return await GetCityNamesAsync(ids);
}, batchSize: 10);
//...
string cityName = await batchExecution.InvokeAsync(13);
You could consider customizing the class by replacing the standard BatchBlock<AsyncOperation> with a custom time-aware BatchBlock, like the one found in this question.
I’m looking for ideas on how to implement a certain bit of functionality for a program.
Basically, I have a main program/thread that makes an asynchronous call to a library (that I also have control over) to do some processing. However, from that call, I need the library to make a callback to the main thread every so often to get more data. How could I do this?
So pass a callback for the library to use. For example:
public class Program
{
static public void Main()
{
var library = new Library();
library.Callback = GetMoreData;
var task = Task.Run( () => library.Foo() );
Console.WriteLine("Other thread is running.");
task.Wait();
}
static string GetMoreData()
{
return "More data";
}
}
class Library
{
public Func<string> Callback { get; set; }
public async Task Foo()
{
for (int i=0; i<10; i++)
{
var moreData = Callback();
Console.WriteLine("Library received this data: {0}", moreData);
await Task.Delay(500);
}
}
}
Example on DotNetFiddle
Seeking some input on a behaviour I'm noticing in my code below. This is my first attempt at async/await using Xamarin Forms and I have perused hundreds of posts, blogs and articles on the subject including the writings from Stephen Cleary on async from constructors and best practices to avoid locking. Although I am using a MVVM framework I assume my issue is more generic than that so I'll ignore it for the moment here.
If I am still missing something or there are ways to improve what I'm trying to do ... happy to listen and learn.
At a high level the logic is as follows:
Application starts and initialises
During initialisation verify database exist and if not - create the SQLite DB. Currently I force this every time to simulate a new application and pre-populate it with some sample data for development purposes
After initialisation completed load results set and display
This works most of the time but I have noticed 2 infrequent occurrences due to the async handling of the database initialisation and pre-populating:
Occasionally not all sample records created are displayed once the app started up - I assume this is because the pre-population phase has not completed when the results are loaded
Occasionally I get an error that one of the tables have not been created - I assume this is because the database initialisation has not completed when the results are loaded
The code - simplified to show the flow during initialisation and startup:
----------- VIEW / PAGE MODEL ----------------
public class MyListItemsPageModel
{
private ObservableRangeCollection<MyListItem> _myListItems;
private Command loadItemsCommand;
public MyListItemsPageModel()
{
_myListItems = new ObservableRangeCollection<MyListItem>();
}
public override void Init(object initData)
{
if (LoadItemsCommand.CanExecute(null))
LoadItemsCommand.Execute(null);
}
public Command LoadItemsCommand
{
get
{
return loadItemsCommand ?? (loadItemsCommand = new Command(async () => await ExecuteLoadItemsAsyncCommand(), () => { return !IsBusy; }));
}
}
public ObservableRangeCollection<MyListItem> MyListItems {
get { return _myListItems ?? (_myListItems = new ObservableRangeCollection<MyListItem>()); }
private set {
_myListItems = value;
}
}
private async Task ExecuteLoadItemsAsyncCommand() {
if (IsBusy)
return;
IsBusy = true;
loadItemsCommand.ChangeCanExecute();
var _results = await MySpecificDBServiceClass.LoadAllItemsAsync;
MyListItems = new ObservableRangeCollection<MyListItem>(_results.OrderBy(x => x.ItemName).ToList());
IsBusy = false;
loadItemsCommand.ChangeCanExecute();
}
}
----------- DB Service Class ----------------
// THERE IS A SPECIFIC SERVICE LAYER BETWEEN THIS CLASS AND THE PAGE VIEW MODEL HANDLING THE CASTING OF TO THE SPECIFIC DATA TYPE
// public class MySpecificDBServiceClass : MyGenericDBServiceClass
public class MyGenericDBServiceClass<T>: IDataAccessService<T> where T : class, IDataModel, new()
{
public SQLiteAsyncConnection _connection = FreshIOC.Container.Resolve<ISQLiteFactory>().CreateConnection();
internal static readonly AsyncLock Mutex = new AsyncLock();
public DataServiceBase()
{
// removed this from the constructor
//if (_connection != null)
//{
// IsInitialized = DatabaseManager.CreateTableAsync(_connection);
//}
}
public Task<bool> IsInitialized { get; private set; }
public virtual async Task<List<T>> LoadAllItemsAsync()
{
// Temporary async/await initialisation code. This will be moved to the start up as per Stephen's suggestion
await DBInitialiser();
var itemList = new List<T>();
using (await Mutex.LockAsync().ConfigureAwait(false))
{
itemList = await _connection.Table<T>().ToListAsync().ConfigureAwait(false);
}
return itemList;
}
}
----------- DB Manager Class ----------------
public class DatabaseManager
{
static double CURRENT_DATABASE_VERSION = 0.0;
static readonly AsyncLock Mutex = new AsyncLock();
private static bool IsDBInitialised = false;
private DatabaseManager() { }
public static async Task<bool> CreateTableAsync(SQLiteAsyncConnection CurrentConnection)
{
if (CurrentConnection == null || IsDBInitialised)
return IsDBInitialised;
await ProcessDBScripts(CurrentConnection);
return IsDBInitialised;
}
private static async Task ProcessDBScripts(SQLiteAsyncConnection CurrentConnection)
{
using (await Mutex.LockAsync().ConfigureAwait(false))
{
var _tasks = new List<Task>();
if (CURRENT_DATABASE_VERSION <= 0.1) // Dev DB - recreate everytime
{
_tasks.Add(CurrentConnection.DropTableAsync<Table1>());
_tasks.Add(CurrentConnection.DropTableAsync<Table2>());
await Task.WhenAll(_tasks).ConfigureAwait(false);
}
_tasks.Clear();
_tasks.Add(CurrentConnection.CreateTableAsync<Table1>());
_tasks.Add(CurrentConnection.CreateTableAsync<Table2>());
await Task.WhenAll(_tasks).ConfigureAwait(false);
_tasks.Clear();
_tasks.Add(UpgradeDBIfRequired(CurrentConnection));
await Task.WhenAll(_tasks).ConfigureAwait(false);
}
IsDBInitialised = true;
}
private static async Task UpgradeDBIfRequired(SQLiteAsyncConnection _connection)
{
await CreateSampleData();
return;
// ... rest of code not relevant at the moment
}
private static async Task CreateSampleData()
{
IDataAccessService<MyListItem> _dataService = FreshIOC.Container.Resolve<IDataAccessService<MyListItem>>();
ObservableRangeCollection<MyListItem> _items = new ObservableRangeCollection<MyListItem>(); ;
_items.Add(new MyListItem() { ItemName = "Test 1", ItemCount = 14 });
_items.Add(new MyListItem() { ItemName = "Test 2", ItemCount = 9 });
_items.Add(new MyListItem() { ItemName = "Test 3", ItemCount = 5 });
await _dataService.SaveAllItemsAsync(_items).ConfigureAwait(false);
_items = null;
_dataService = null;
IDataAccessService<Sample> _dataService2 = FreshIOC.Container.Resolve<IDataAccessService<AnotherSampleTable>>();
ObservableRangeCollection<Sample> _sampleList = new ObservableRangeCollection<Sample>(); ;
_sampleList.Add(new GuestGroup() { SampleName = "ABC" });
_sampleList.Add(new GuestGroup() { SampleName = "DEF" });
await _dataService2.SaveAllItemsAsync(_sampleList).ConfigureAwait(false);
_sampleList = null;
_dataService2 = null;
}
}
In your DataServiceBase constructor, you're calling DatabaseManager.CreateTableAsync() but not awaiting it, so by the time your constructor exits, that method has not yet completed running, and given that it does very little before awaiting, it's probably barely started at that point. As you can't effectively use await in a constructor, you need to remodel things so you do that initialisation at some other point; e.g. perhaps lazily when needed.
Then you also want to not use .Result/.Wait() whenever possible, especially as you're in an async method anyway (e.g. ProcessDBScripts()), so instead of doing
var _test = CurrentConnection.DropTableAsync<MyListItem>().Result;
rather do
var _test = await CurrentConnection.DropTableAsync<MyListItem>();
You also don't need to use Task.Run() for methods that return Task types anyway. So instead of
_tasks.Add(Task.Run(() => CurrentConnection.CreateTableAsync<MyListItem>().ConfigureAwait(false)));
_tasks.Add(Task.Run(() => CurrentConnection.CreateTableAsync<AnotherSampleTable>().ConfigureAwait(false)));
just do
_tasks.Add(CurrentConnection.CreateTableAsync<MyListItem>()));
_tasks.Add(CurrentConnection.CreateTableAsync<AnotherSampleTable>()));
sellotape has correctly diagnosed the code problem: the constructor is starting an asynchronous method but nothing is (a)waiting for it to complete. A simple fix would be to add await IsInitialized; to the beginning of LoadAllItemsAsync.
However, there's also a design problem:
After initialisation completed load results set and display
That's not possible on Xamarin, or any other modern UI platform. You must load your UI immediately and synchronously. What you should do is immediately display a splash/loading page and start the asynchronous initialization work. Then, when the async init is completed, update your VM/UI with your "real" page. If you just have LoadAllItemsAsync await IsInitialized, then your app will sit there for some time showing the user zero data before it "fills in".
You may find my NotifyTask<T> type (available on NuGet) useful here if you want to show a splash/spinner instead of zero data.
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;
}
}
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).
You can also do just like this:
Task.Run(() => this.FunctionAsync()).Wait();
Note: Be careful about thread blocking!
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.
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
}
}
Basically 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 no one could "accidentally" 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;
}
}
Instead of doing
var page = new Page2();
you would be using:
var page = await Page2.Create();
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.
My preferred approach:
// caution: fire and forget
Task.Run(async () => await someAsyncFunc());
Try to replace this:
myLongList.ItemsSource = writings;
with this
Dispatcher.BeginInvoke(() => myLongList.ItemsSource = writings);
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.
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;
}
}
}
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://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/consuming-the-task-based-asynchronous-pattern
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
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;
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
}
}
The answer is simple, If you are developing an UWP app, then add the async function to the Page_Loaded method of the page.
if you want it to wait task to be done you can improve madlars codes like below. (I tried on .net core 3.1 it worked )
var taskVar = Task.Run(async () => await someAsyncFunc());
taskVar.Wait();
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);
}