Async method nevers finishes - c#

I have a form, like below, that accepts a Task<T>, waits for completion and then returns after await by closing the form:
public partial class SomeForm<T> : Form
{
public T ReturnValue { get; private set; }
private Task<T> Task { get; set; }
public SomeForm(string waitingText, Task<T> task)
{
InitializeComponent();
...
PerformTask();
}
private async void PerformTask()
{
ReturnValue = await Task;
this.Close();
}
}
However, whilst this method runs happily, it gets to ReturnValue = await Task; and then does not go any further. The method will run normally without being sent to the method and does not delay. I have a feeling it's to do with how I'm using async and await, but I'm new to TPL etc.
Please help me identify what's wrong with the above script, and in identifying why it never returns.
Edit: TaskA was a typo. Here's the Task's method; ImportedFunctions. BS_Robots_LoadDrive(..) is a DllImport of a C++ function, which works just fine synchronously, even on another thread (like in the final snippet), but not with an async paramter.
public uint LoadDisc()
{
uint response = ImportedFunctions.BS_Robots_LoadDrive(DriveLetters[0],
(int)BSRobotConstants.BIN_ID_DEFAULT,
(int)BSRobotConstants.POSITION_TYPE_INPUTBIN,
0);
switch (response)
{
case BSRobotConstants.OK:
case BSRobotConstants.OK_WITH_MESSAGE:
case BSRobotConstants.FROMTRAY_NO_DISC:
case BSRobotConstants.INVALID_DRIVE:
case BSRobotConstants.INVALID_POSITION:
case BSRobotConstants.TOTRAY_NO_DISC:
case BSRobotConstants.TOTRAY_NOT_OPEN:
case BSRobotConstants.FATAL_ERROR:
break;
case BSRobotConstants.BUSY:
break;
case BSRobotConstants.TOTRAY_HAS_DISC:
RejectDisc();
response = LoadDisc();
break;
}
return response;
}
This works:
private async void PerformTask()
{
Task.Start();
Task.Wait();
ReturnValue = Task.Result;
DialogResult = DialogResult.OK;
}
But the first code snippet doesn't.

The task does not continue past ReturnValue = await TaskA; because it is not returning. Verify the Task is running and not getting stuck.
To property utility async-await for object construction use an async factory method.
See: How to initialize an object using async-await pattern
public class Form1<T> : Form
{
public Form1(string waitingText, Task<T> task)
{
Task = Execute(task);
Controls.Add(new Label { Text = waitingText });
}
public T ReturnValue { get { return Task.Result; } }
public Task<T> Task { get; private set; }
private async Task<T> Execute(Task<T> task)
{
var result = await task;
Close();
return result;
}
}
Usage:
var form = new Form1<int>("Hello", Task.Delay(1000).ContinueWith(_ => 1));
form.Show();
var returnValue = await form.Task;
Console.WriteLine(returnValue);

Related

(A)wait for class to finish instantiate

I try to wait for the class to be finished with instantiate.
My architecture is the following. Cook is inheriade from CookChief.
And if I instantiate cook, CookChief is creating himself, but CookChief is calling 1 other class named Cookhelper the cookhelper is waiting for a input and for this input method i want to wait in Cook.
The thing is iam creating this in MVVM Galasoft and my entry point is the CookViewmodel, with a relaycommand.
In the code below you can see my architecture. To say it short I want to wait until this bool processed = await Task.Run(() => ValidateForDeviceId()); is finished.
My first step was to outsource the constructer of each class. And create a init method.
This is my code:
public CookViewModel()
{
startCookButtonCommand = new RelayCommand(Cook);
}
private async Task Cook()
{
cook.Init();
}
public class Cook : CookChief
{
public Cook()
{
}
public async Task Init()
{
await this.CookChiefInit();
//here I want to wait until CookChiefInit is finished
Cooking();
}
public void Cooking()
{
MessageBox.Show("Input received");
}
}
Now the Cookchief:
public Cookchief()
{
}
protected async Task CookchiefInit()
{
this.Cookhelper = new Cookhelper();
Cookhelper.CookHelperInit();
}
And in the CookHelper we do this:
public CookHelper()
{
}
public void CookHelperInit()
{
this.driverWindow = new DriverWindow();
startProc();
}
private async void startProc()
{
ShowOrCloseDriverWindow(true);
//this is the task what we wait for before we can repeat
bool processed = await Task.Run(() => ValidateForDeviceId());
if(processed)
{
ShowOrCloseDriverWindow(false);
}
else
{
MessageBox.Show("DriverError");
}
}
private bool ValidateForDeviceId()
{
for (; ; )
{
this.deviceId = Input.deviceId;
if (deviceId > 0)
{
break;
}
}
return true;
}
Per the discussion in the comments, the problem here was that the initialization routine mixed synchronous and asynchronous methods and calls. Additionally, some async methods were called without the await keyword. The solution was to make all calls asynchronous and await them.
cook.Init() needs an await:
private async Task Cook()
{
await cook.Init();
}
In CookchiefInit(), the CookHelperInit() call needs to be awaited:
protected async Task CookchiefInit()
{
this.Cookhelper = new Cookhelper();
Cookhelper.CookHelperInit();
}
In order to await CookHelperInit(), it needs to be made asynchronous. The startProc() call is to an async method, so it must also be awaited:
public async Task CookHelperInit()
{
this.driverWindow = new DriverWindow();
await startProc();
}

"Sorry my bot code is having issues" message on calling PromptDialog.Choice()

Code flow is as follows:
I have a DialogA which calls a qnaMaker Dialog in its StartAsync method.
The qnaMaker Dialog callback calls promptDialog function in a helper class(which is not a Dialog by the way)
Once user selects appropriate choice on the prompt, a callback is called which post a message
Error appears after the message("Helpful"/ "Not helpful") has been posted
My first incination was to use context.Wait() after the message has been posted from OnOptionSelectedForPrompt callback, bit it seems that calling wait here somehow executes the ResumeAfter callback for DialogA.
Code Sample: DialogA.cs
[Serializable]
public class DialogA : IDialog<object>
{
private string tool = "sometool";
private string userInput = String.Empty;
private bool sendToQnaMaker = false;
public DialogA(string userQuery)
{
if (userQuery.Length > 0)
{
sendToQnaMaker = true;
userInput = userQuery;
}
}
public async Task StartAsync(IDialogContext context)
{
if(sendToQnaMaker)
{
await context.Forward(new QnaDialog(), QnaMakerDialogCallback, BotHelper.CreateMessageActivityForQnaMaker(userInput), CancellationToken.None);
} else
{
await BotHelper.ShowWelcomeMessageOnMenuSection(context, tool);
context.Wait(OnMessageReceived);
}
}
private async Task QnaMakerDialogCallback(IDialogContext context, IAwaitable<object> result)
{
var response = await result;
bool isInQnaMaker = Convert.ToBoolean(response);
BotHelper botHelper = new BotHelper(tool);
botHelper.showPrompt(context)
}
BotHelper.cs
public void showPrompt(IDialogContext context)
{
PromptDialog.Choice(context, OnOptionSelectedForPrompt, Constants.promptChoices, MiscellaneousResponses.answerFeedbackMessage, MiscellaneousResponses.invalidOptionMessage, 3);
}
public async Task OnOptionSelectedForPrompt(IDialogContext context, IAwaitable<string> result)
{
string optionSelected = await result;
switch (optionSelected)
{
case MiscellaneousResponses.helpfulMessage:
string botreply = "Helpful";
await context.PostAsync(botreply);
break;
case MiscellaneousResponses.notHelpfulMessage:
string botResponse = "Not Helpful";
await context.PostAsync(botResponse);
break;
}
}
}
Created a separate dialog instead of using the BotHelper class and properly handled dialog stack using Context.Done and Context.Wait.

Shared resource and async Web API call

I have a simple Web API method that looks like this:
public async Task<HttpResponseMessage> RunTask(TaskType taskType)
{
var taskId = await TaskManager.CreateTask(taskType);
TaskManager.Run(taskId);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content =
new StringContent($"Task {taskType.GetDescription()} was started.")
};
}
TaskManager.Run is decalared like this:
public async Task Run(int id)
I was expecting it to return "Task was started" message immediately after TaskManager.Run(taskId) But the request continues to run synchronously.
But if to replace the call TaskManager.Run(taskId) with:
Task.Run(() => Thread.Sleep(TimeSpan.FromSeconds(100)));
Then it runs asynchronously.
So I believe this is something to do with the resources shared by TaskManager and main thread. Can a shared resource lock the execution?
I'm using Castle Windsor. One WindsorContainer container is declared in Web API project.
TaskManager utilizes BaseTaskRunner class inside of it. One more WindsorContainer is declared in BaseTaskRunner.
Web API's container uses LifeStyle.PerWebRequest for all components. BaseTaskRunner's container uses LifeStyle.Singleton (not sure if it's correct LifeStyle). Could the call be locked for example by DdContext or other classes declared in both of the containers?
UPD:
I don't want to wait the TaskManager.Run to complete. But what happens is that return statement still waits for the TaskManager.Run to complete (even without await statement on TaskManager.Run).
In other words it does not matter how I call the TaskManager.Run:
TaskManager.Run(taskId);
or
await TaskManager.Run(taskId);
It waits for TaskManager.Run to complete in both cases.
Here is the code of TaskManager:
public class TaskManager : ITaskManager
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
public async Task<int> CreateTask(TaskType type, byte[] data = null, object config = null)
{
var task = new BackgroundTask
{
Type = type,
Status = BackgroundTaskStatus.New,
Config = config?.SerializeToXml(),
Created = DateTime.Now,
Data = data
};
TaskRepository.Add(task);
TaskRepository.SaveChanges();
return task.Id;
}
public async Task Run(int id, bool removeOnComplete = true)
{
var task = TaskRepository.GetById(id);
Run(task, removeOnComplete);
}
public async Task Run(TaskType type, bool removeOnComplete = true)
{
var tasksToRun = TaskRepository.Get(t => t.Type == type);
tasksToRun.ForEachAsync(t => Run(t, removeOnComplete));
}
public async Task Run(BackgroundTask task, bool removeOnComplete = true)
{
switch (task.Type)
{
case TaskType.SpreadsheetImport:
new SpreadsheetImportTaskRunner().Run(task);
break;
}
}
}
And some other classes:
public class SpreadsheetImportTaskRunner : BaseTaskRunner
{
public IForecastSpreadsheetManager SpreadsheetManager { get; set; }
protected override void Execute()
{
SpreadsheetManager.ImportActuals(Task.Data);
}
protected override void Initialize()
{
base.Initialize();
SpreadsheetManager = _container.Resolve<IForecastSpreadsheetManager>();
}
}
BaseTaskRunner:
public class BaseTaskRunner
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
protected IWindsorContainer _container = new WindsorContainer();
protected BackgroundTask Task { get; set; }
public async Task Run(BackgroundTask task)
{
Initialize();
Task = task;
try
{
Execute();
}
catch (Exception ex)
{
SetError(ex.ToString());
}
}
protected virtual void Execute()
{
}
protected virtual void Initialize()
{
_container.Install(new TaskRunnerComponentsInstaller());
TaskRepository = _container.Resolve<IRepository<BackgroundTask>>();
}
}
I still believe this is something to do with the WindsorContainer and common classes which are resolved in several different threads.
The issue is that you're not using await on the Task being returned from the invocation of the TaskManager.Run function. Consider the below:
public async Task<HttpResponseMessage> RunTask(TaskType taskType)
{
var taskId = await TaskManager.CreateTask(taskType);
await TaskManager.Run(taskId);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content =
new StringContent($"Task {taskType.GetDescription()} was started.")
};
}
Now it will work asynchronously as you'd expect. The await sets a continuation marker in the async state-machine, instructing it to return to this portion of the method upon completion of the asynchronous operation defined in the TaskManager.Run.
UPDATE
You are missing lots of await statements, and there are times where you need to not mark methods as async. It appears as though there are some mis-understandings as it pertains to these keywords. Here is what your TaskManager class should look like.
public class TaskManager : ITaskManager
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
public async Task<int> CreateTask(TaskType type,
byte[] data = null,
object config = null)
{
var task = new BackgroundTask
{
Type = type,
Status = BackgroundTaskStatus.New,
Config = config?.SerializeToXml(),
Created = DateTime.Now,
Data = data
};
TaskRepository.Add(task);
TaskRepository.SaveChanges();
return task.Id;
}
public ask Run(int id, bool removeOnComplete = true)
{
var task = TaskRepository.GetById(id);
return Run(task, removeOnComplete);
}
public Task Run(TaskType type, bool removeOnComplete = true)
{
var tasksToRun = TaskRepository.Get(t => t.Type == type);
return tasksToRun.ForEachAsync(t => Run(t, removeOnComplete));
}
public Task Run(BackgroundTask task, bool removeOnComplete = true)
{
switch (task.Type)
{
case TaskType.SpreadsheetImport:
return new SpreadsheetImportTaskRunner().Run(task);
break;
}
}
}
}
Ideally, if the method is marked as a return type of Task and the method doesn't need to unwind any tasks within its execution it can simply return the Task functionality for its implementation. For example, notice how dramatically my TaskManager class differs from yours -- I'm only marking methods as async that need to actually await. These two keywords should be married, if a method uses async there should be an await. But only use await if the method needs to unwind and use the asynchronous operation.

await a Task and silently stop on cancel or failure

What I would like to write is the following:
async void Foo()
{
var result = await GetMyTask().IgnoreCancelAndFailure();
ProcessResult(result);
}
Instead of:
void Foo()
{
GetMyTask().ContinueWith(task => ProcessResult(task.Result),
TaskContinuationOptions.OnlyOnRanToCompletion);
}
However I don't know how to implement the method IgnoreCancelAndFailure, which would have the following signature:
//On cancel or failure this task should simply stop and never complete.
Task<T> IgnoreCancelAndFailure<T>(this Task<T> task)
{
throw new NotImplementedException();
}
If possible, how should I implement IgnoreCancelAndFailure?
You could do something like that, but you need to know what you want the method to return in case of failure, since a return value is expected:
public static async Task<T> IgnoreCancelAndFailure<T>(this Task<T> task)
{
try
{
return await task;
}
catch
{
return ???; // whatever you want to return in this case
}
}
If it's a Task with no result, just leave the catch empty (or perhaps log the exception... swallowed exceptions make for hard debugging)
If you just want to execute ProcessResult only when GetMyTask succeeds, you can do this:
async void Foo()
{
try
{
var result = await GetMyTask();
ProcessResult(result);
}
catch(Exception ex)
{
// handle the exception somehow, or ignore it (not recommended)
}
}
You will never be able to stop your code from continuing expect when killing the thread or process. keep in mind that the await task can be considered a function call that will always have to return a value or throw an exception.
The closest way to shorten your code is creating a wrapper function that uses the ProcessResult method as Action argument.
Something like that:
public static async Task IgnoreCancelAndFailure<T>(this Task<T> task, Action<T> resultProcessor)
{
task.ContinueWith(t => resultProcessor(t.Result),
TaskContinuationOptions.OnlyOnRanToCompletion);
}
async void Foo()
{
GetMyTask().IgnoreCancelAndFailure(ProcessResult);
}
I think I found the answer. The following seems to do the trick. It uses the awaitable pattern. Could you guys confirm that this isn't evil?
class User
{
async void Foo()
{
var result = await GetMyTask().IgnoreCancelAndFailure();
ProcessResult(result);
}
}
public static class TaskExtenstions
{
public static SilentTask<T> IgnoreCancelAndFailure<T>(this Task<T> task)
{
return new SilentTask<T>(task);
}
}
public class SilentTask<T>
{
private readonly Task<T> _inner;
public SilentTask(Task<T> inner)
{
_inner = inner;
}
public SilentAwaiter GetAwaiter()
{
return new SilentAwaiter(_inner);
}
public class SilentAwaiter : INotifyCompletion
{
private readonly TaskAwaiter<T> _inner;
private readonly Task<T> _task;
public SilentAwaiter(Task<T> task)
{
_task = task;
_inner = task.GetAwaiter();
}
public bool IsCompleted
{
get
{
return _task.Status == TaskStatus.RanToCompletion;
}
}
public void OnCompleted(Action continuation)
{
_inner.OnCompleted(() =>
{
if (IsCompleted)
{
continuation();
}
});
}
public T GetResult()
{
return _inner.GetResult();
}
}
}

Deadlock when combining app domain remoting and tasks

My app needs to load plugins into separate app domains and then execute some code inside of them asynchronously. I've written some code to wrap Task in marshallable types:
static class RemoteTask
{
public static async Task<T> ClientComplete<T>(RemoteTask<T> remoteTask,
CancellationToken cancellationToken)
{
T result;
using (cancellationToken.Register(remoteTask.Cancel))
{
RemoteTaskCompletionSource<T> tcs = new RemoteTaskCompletionSource<T>();
remoteTask.Complete(tcs);
result = await tcs.Task;
}
await Task.Yield(); // HACK!!
return result;
}
public static RemoteTask<T> ServerStart<T>(Func<CancellationToken, Task<T>> func)
{
return new RemoteTask<T>(func);
}
}
class RemoteTask<T> : MarshalByRefObject
{
readonly CancellationTokenSource cts = new CancellationTokenSource();
readonly Task<T> task;
internal RemoteTask(Func<CancellationToken, Task<T>> starter)
{
this.task = starter(cts.Token);
}
internal void Complete(RemoteTaskCompletionSource<T> tcs)
{
task.ContinueWith(t =>
{
if (t.IsFaulted)
{
tcs.TrySetException(t.Exception);
}
else if (t.IsCanceled)
{
tcs.TrySetCancelled();
}
else
{
tcs.TrySetResult(t.Result);
}
}, TaskContinuationOptions.ExecuteSynchronously);
}
internal void Cancel()
{
cts.Cancel();
}
}
class RemoteTaskCompletionSource<T> : MarshalByRefObject
{
readonly TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
public bool TrySetResult(T result) { return tcs.TrySetResult(result); }
public bool TrySetCancelled() { return tcs.TrySetCanceled(); }
public bool TrySetException(Exception ex) { return tcs.TrySetException(ex); }
public Task<T> Task
{
get
{
return tcs.Task;
}
}
}
It's used like:
sealed class ControllerAppDomain
{
PluginAppDomain plugin;
public Task<int> SomethingAsync()
{
return RemoteTask.ClientComplete(plugin.SomethingAsync(), CancellationToken.None);
}
}
sealed class PluginAppDomain : MarshalByRefObject
{
public RemoteTask<int> SomethingAsync()
{
return RemoteTask.ServerStart(async cts =>
{
cts.ThrowIfCancellationRequested();
return 1;
});
}
}
But I've run into a snag. If you look in ClientComplete, there's a Task.Yield() I've inserted. If I comment this line, ClientComplete will never return. Any ideas?
My best guess is that you are facing these issues because of the async method that contains await and this is managed via the ThreadPool which can allocate some recycled Thread.
Reference
Best practice to call ConfigureAwait for all server-side code
Actually, just doing an await can do that(put you on a different thread). Once your async method hits
an await, the method is blocked but the thread returns to the thread
pool. When the method is ready to continue, any thread is snatched
from the thread pool and used to resume the method.
Try to streamline the code, generate threads for baseline cases and
performance is last.

Categories