SQLite-Net-PCL Deadlock issue - c#

I am using SQLite-PCL with Xamarin.Android for data storage. I am using it asynchronously, and am experiencing a deadlock issue because of this.
The implementation is contained in a DataHandler class:
Constructor
public DataHandler(string path)
{
_db = new SQLiteAsyncConnection(path);
Initialize().Wait();
}
Initialize Function
private async Task Initialize()
{
using (await Lock())
{
await _db.CreateTableAsync<Person>();
await _db.CreateTableAsync<Animal>();
}
}
And lastly, that Lock() function is an implementation of the answer at the question here: https://stackoverflow.com/a/44127898/3808312
When the object is constructed, Initialize().Wait() is called and deadlocks on the first call to CreateTableAsync() and unfortunately, I can't really debug into the library without touching the disassembly of it. Am I using async pattern wrong or something? And yes, I do know that Wait() is synchronous. That was just to keep the same format as the other methods in the class.

For issues like this, a frequent pattern is to create the affected class using an async factory method.
public class DataHandler {
//...other code
private DataHandler() {
}
private async Task InitializeAsync(string path) {
_db = new SQLiteAsyncConnection(path);
using (await Lock()) {
await _db.CreateTableAsync<Person>();
await _db.CreateTableAsync<Animal>();
}
}
public static async Task<DataHandler> CreateDataHandler(string path) {
var handler = new DataHandler();
await handler.InitializeAsync(path);
return handler;
}
//...other code
}
and then use it in a manner that allows async calls.
var handler = await DataHandler.CreateDataHandler("<path here>");
Like in the OnAppearing virtual method where you can subscribe to the Appearing event of the page/view
protected override void OnAppearing() {
this.Appearing += Page_Appearing;
}
and call your async code on an actual even handler
private async void Page_Appearing(object sender, EventArgs e) {
//...call async code here
var handler = await DataHandler.CreateDataHandler("<path here>");
//..do what you need to do with the handler.
//unsubscribing from the event
this.Appearing -= Page_Appearing;
}

Related

EditContext OnFieldChanged reporting wrong return type

I have the 3 methods below in a razor file
protected override async Task OnInitializedAsync()
{
EditContext = new EditContext(_projectModel);
EditContext.OnFieldChanged += EditContext_OnFieldChanged;
}
private async Task EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
{
await SetOkDisabledStatus();
}
This method is an async method and I have to await it anywhere it is been called
private async Task SetOkDisabledStatus()
{
if (EditContext.Validate())
{
OkayDisabled = null;
await JsRuntime.InvokeVoidAsync("Animate");
}
else
{
OkayDisabled = "disabled";
}
}
I am using the EditContext for validation in a Blazor server application.
I have been getting the error message on this line below in the OnInitializedAsync() method and not sure how to proceed with it.
EditContext.OnFieldChanged += EditContext_OnFieldChanged;
Error Message:
Task MyProject.EditContext_OnFieldChanged(object, FieldChangedEventArgs)'
has the wrong return type.
Expected a method with void EditContext_OnFieldChanged(object?, FieldChangedEventArgs e)
Please note that I am using sonarqube to check all my code.
You can assign an async lambda to the event handler, like this:
EditContext.OnFieldChanged +=
async (sender,args) => await EditContext_OnFieldChanged(sender,args);
But, you should be aware that the EditContext/Form will not await your task. Anything you do in that async task will be out of sync with the editcontext.
You should probably include a cancellation token in your async code as well, so that multiple changes to a field do not fire multiple validation tasks at the same time.
Async validation is hard - make sure you test every possible scenario.
Generated Blazor eventhandlers (like #onclick="...") are flexible about return type and parameters but EditContext.OnFieldChanged is not, it has a fixed delegate type.
Make the following change:
//private async Task EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
private async void EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
{
await SetOkDisabledStatus();
StateHasChanged(); // make sure OkayDisabled takes effect
}
On another note, you can probably make OkayDisabled a boolean and use disabled="#OkayDisabled" where you need it.
Blazor makes the disabled attribute disappear when you assign it with false.
Alternative: keep the validation synchronous. That might prevent some problems as #Mister Magoo points out. And then let only the Animation run async.
private void EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
{
SetOkDisabledStatus();
}
private void SetOkDisabledStatus()
{
if (EditContext.Validate())
{
OkayDisabled = null;
_ = JsRuntime.InvokeVoidAsync("Animate"); // no await, on purpose
}
else
{
OkayDisabled = "disabled";
}
}
StateHasChanged() should not be needed in this scenario.

How to run code on the main thread after async

I have code that will only run on the main thread, but before that code can run, I need to initialize an object. Is there anyway I can force async code to run sync? The functions after the awaits are API calls, and therefore I cannot modify those directly.
public partial class MainWindow : Window
{
private MustBeInit mbi;
public MainWindow() {
InitializeComponent();
// async code that initializes mbi
InitMbi();
// mbi must be done at this point
SomeCodeThatUsesMbi();
}
public async void InitMbi() {
mbi = new MustBeInit();
await mbi.DoSomethingAsync();
await mbi.DoSomethingElseAsync();
// is there any way i can run these two methods as not await and
// run them synchronous?
}
public void SomeCodeThatUsesMbi() {
DoSomethingWithMbi(mbi); // mbi cannot be null here
}
}
You can't use the await in constructors, but you can put the whole thing into an async event handler subscribed to the Loaded event of the Window:
public MainWindow()
{
this.Loaded += async (s, e) =>
{
await InitMbi();
// mbi must be done at this point
SomeCodeThatUsesMbi();
};
InitializeComponent();
}
And don't forget to change the return value of your InitMbi() to Task:
public async Task InitMbi()
// is there any way i can run these two methods as not await and
// run them synchronous?
Yes, just remove the await before the method call like:
public async void InitMbi() {
mbi = new MustBeInit();
mbi.DoSomethingAsync();
mbi.DoSomethingElseAsync();
// is there any way i can run these two methods as not await and
// run them synchronous?
}
But be aware of the fact that this will block your main thread!

What is the right way to call a Task from MainPage

If await can be used only by async methods, how can I call a task from MainPage()?
My code sample:
public MainPage()
{
InitializeComponent();
label.Text=await Task.Run(TaskTest); //this doesn't work
}
private async Task<string> TaskTest()
{
try
{
using (WebClient client = new WebClient())
{
return await client.DownloadStringTaskAsync("https://www.example.com/return.php");
//also tried w/ no success:
//return client.DownloadStringTaskAsync("https://www.example.com/return.php").Result;
}
}
catch (Exception)
{
throw;
}
}
Avoid async void fire-and-forget methods.
Event handlers however are the only exception to that rule.
Reference Async/Await - Best Practices in Asynchronous Programming
In this case, since you want to await the task then create and event and handler that would facilitate the desired behavior
public MainPage() {
InitializeComponent();
Downloading += OnDownloading; //subscribe to event
Downloading(this, EventArgs.Empty); //raise event to be handled
}
private event EventHandler Downloading = delegate { };
private async void OnDownloading(object sender, EventArgs args) {
//Downloading -= OnDownloading; //unsubscribe (optional)
label.Text = await TaskTest(); //this works
}
private async Task<string> TaskTest() {
try {
using (WebClient client = new WebClient()) {
return await client.DownloadStringTaskAsync("https://www.example.com/return.php");
}
} catch (Exception) {
throw;
}
}
You cannot make the Main() method asynchronous and thus, you can use the await keyword in the body of the Main() function.
A simple workaround that you can implement by editing your current code is making your function TaskTest() return void so you don't have to await it's call.
Example:
public MainPage()
{
InitializeComponent();
TaskTest();
}
private async void TaskTest()
{
try
{
using (WebClient client = new WebClient())
{
label.Text = await client.DownloadStringTaskAsync("https://www.example.com/return.php");
}
}
catch (Exception)
{
throw;
}
}
Edit
In case you have to wait for the return value of an asynchronous call without using await, you could go ahead and use a while to check whether the Task has completed or not.
Task<string> accessTokenTask = Task.Run<string>(() => MethodToGetToken());
// wait until operation is done.
while(!accessTokenTask.IsCompleted)
{
accessTokenTask.Wait():
}
// once the task completes, the runtime will step out of the while loop
// and you can access your Token in the Result
string token = accessTokenTask.Result;
Hope this answers your question.
You probably shouldn't call your Task from MainPage. I started with the Visual Studio blank page and tried to do the same thing. I found an answer suggested to use await Navigation.PushModalAsync(NewPage);, and then call the task there Task.Run(async () => { await method(); }).Wait();. It worked, but not the best way to do it.
This article on CodeProject is great to help beginners to add MVVM to the blank page project. You just need to bind the ViewModel to the MainPage, and then call your Task from the ViewModel instead.
public MainPage()
{
InitializeComponent();
this.BindingContext = new MainPageViewModel(this);
}

AsyncEx DeferralManager for awaiting event handlers

I have a similar problem stated in this thread and according to Stephen Cleary's comment, WinRT's solution is to use deferrals. The solution indicated in the thread also works for me but I wanted to try out using deferrals since it might be or become the standard way of handling this kind of situation.
So I read his blog about it and tried to apply it to my code, but I can't seem to get it to work. What's happening is that event subscription is still not being awaited. I also couldn't find any full sample program that I can run and analyze. So I tried creating a sample console program to demonstrate the problem that I was seeing.
First I have the event handler delegate and event arguments definitions:
public delegate void CancelEventHandlerAsync(object sender, CancelEventArgsAsync e);
public class CancelEventArgsAsync : CancelEventArgs
{
private readonly DeferralManager _deferrals = new DeferralManager();
public IDisposable GetDeferral()
{
return this._deferrals.GetDeferral();
}
public Task WaitForDefferalsAsync()
{
return this._deferrals.SignalAndWaitAsync();
}
}
Then the child module definition that is the event sender:
public class ChildModule1
{
public event CancelEventHandlerAsync ChildModuleLaunching;
public async Task Launch()
{
var cancelEventArgs = new CancelEventArgsAsync();
this.ChildModuleLaunching(this, cancelEventArgs);
cancelEventArgs.WaitForDefferalsAsync();
if (cancelEventArgs.Cancel)
{
return;
}
Console.WriteLine("Child module 1 launched."); // This should not be executed.
}
}
Then the parent class that subscribes to the child module event:
public class Parent
{
private ChildModule1 child1 = new ChildModule1();
public Parent()
{
this.child1.ChildModuleLaunching += this.OnChildModule1Launching;
}
public async Task Process()
{
await this.child1.Launch();
}
private async void OnChildModule1Launching(object sender, CancelEventArgsAsync e)
{
var deferral = e.GetDeferral();
await Task.Delay(2500); // Simulate processing of an awaitable task.
e.Cancel = true;
deferral.Dispose();
}
}
Finally, the console app entry point:
static void Main(string[] args)
{
var parent = new Parent();
parent.Process().Wait();
Console.ReadKey();
}
You need to await the WaitForDefferalsAsync call:
await cancelEventArgs.WaitForDefferalsAsync();

Is it possible to have async methods as callbacks to eventhandlers in c#?

My design is illustrated by below example. Having a while true loop doing something and notifying by an event that it has done something to all subscribers. My application should not continue its execution before its done notifying all subscribers, where this works as long as someone do not put a async void on the callback.
If someone put a async void on the callback to await some task, then my loop can continue before the callback is completed. What other designs can I do to avoid this situation.
Its 3th party plugins that register themeself and subscribe to the event, so I have no control over if they put a async void. Understandable I cant do Task callbacks for the EventHandler, so what alternatives do I have with .net 4.5.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
public class Test
{
public event EventHandler Event;
public void DoneSomething()
{
if (Event != null)
Event(this,EventArgs.Empty);
}
}
class Program
{
static void Main(string[] args)
{
var test = new Test();
test.Event += test_Event;
test.Event +=test_Event2;
while(true)
{
test.DoneSomething();
Thread.Sleep(1000);
}
}
private static void test_Event2(object sender, EventArgs e)
{
Console.WriteLine("delegate 2");
}
static async void test_Event(object sender, EventArgs e)
{
Console.WriteLine("Del1gate 1");
await Task.Delay(5000);
Console.WriteLine("5000 ms later");
}
}
}
If someone put a async void on the callback to await some task, then my loop can continue before the callback is completed. What other designs can I do to avoid this situation.
There is really no way to avoid this. Even if you were to somehow "know" that the subscriber wasn't implemented via async/await, you still couldn't guarantee that the caller didn't build some form of asynchronous "operation" in place.
For example, a completely normal void method could put all of its work into a Task.Run call.
My application should not continue its execution before its done notifying all subscribers
Your current version does follow this contract. You're notifying the subscribers synchronously - if a subscriber does something asynchronously in response to that notification, that is something outside of your control.
Understandable I cant do Task callbacks for the EventHandler, so what alternatives do I have with .net 4.5.
Note that this is actually possible. For example, you can rewrite your above as:
public class Program
{
public static void Main()
{
var test = new Test();
test.Event += test_Event;
test.Event +=test_Event2;
test.DoneSomethingAsync().Wait();
}
}
public delegate Task CustomEvent(object sender, EventArgs e);
private static Task test_Event2(object sender, EventArgs e)
{
Console.WriteLine("delegate 2");
return Task.FromResult(false);
}
static async Task test_Event(object sender, EventArgs e)
{
Console.WriteLine("Del1gate 1");
await Task.Delay(5000);
Console.WriteLine("5000 ms later");
}
public class Test
{
public event CustomEvent Event;
public async Task DoneSomethingAsync()
{
var handler = this.Event;
if (handler != null)
{
var tasks = handler.GetInvocationList().Cast<CustomEvent>().Select(s => s(this, EventArgs.Empty));
await Task.WhenAll(tasks);
}
}
}
You can also rewrite this using event add/remove, as suggested by svick:
public class Test
{
private List<CustomEvent> events = new List<CustomEvent>();
public event CustomEvent Event
{
add { lock(events) events.Add(value); }
remove { lock(events) events.Remove(value); }
}
public async Task DoneSomething()
{
List<CustomEvent> handlers;
lock(events)
handlers = this.events.ToList(); // Cache this
var tasks = handlers.Select(s => s(this, EventArgs.Empty));
await Task.WhenAll(tasks);
}
}
My application should not continue its execution before its done notifying all subscribers, where this works as long as someone do not put a async void on the callback.
I have a blog entry on designing for async event handlers. It is possible to use Task-returning delegates or to wrap an existing SynchronizationContext within your own (which would allow you to detect and wait for async void handlers).
However, I recommend you use "deferrals", which are objects designed specifically to solve this problem for Windows Store applications. A simple DeferralManager is available in my AsyncEx library.
Your event args can define a GetDeferral method as such:
public class MyEventArgs : EventArgs
{
private readonly DeferralManager deferrals = new DeferralManager();
... // Your own constructors and properties.
public IDisposable GetDeferral()
{
return deferrals.GetDeferral();
}
internal Task WaitForDeferralsAsync()
{
return deferrals.SignalAndWaitAsync();
}
}
And you can raise an event and (asynchronously) wait for all asynchronous handlers to complete like this:
private Task RaiseMyEventAsync()
{
var handler = MyEvent;
if (handler == null)
return Task.FromResult<object>(null); // or TaskConstants.Completed
var args = new MyEventArgs(...);
handler(args);
return args.WaitForDeferralsAsync();
}
The benefit of the "deferral" pattern is that it is well-established in the Windows Store APIs, so it's likely to be recognized by end users.

Categories