ContinueWith as an alternative to the await operator - c#

My application uses scripts. So far, I've used C# for the scripts and compiled them using the CodeDomProvider. However, I've been thinking about switching to Lua using the NLua fork (a fork of the LuaInterface) because it's much easier to write scripts with plus I'm familiar with the syntax.
However, I'm facing a problem. Currently, I have an asynchronous method that returns a Task<bool>. It uses a TaskCompletionSource object and returns it's Result. That way, I can halt the execution of the script because it waits until the Result of the TaskCompletionSource object has been set, and only then returns this Result.
Now, with Lua - it's different. I obviously can't use the awaitoperator because it's a syntax of C# 5.0, and you can't use that in Lua. So that's why I'm asking if there's a workaround for this. I want to be able to achieve the same result as my old code (which is posted beneath this post) without having to use the awaitoperator. I've been told that I can do that with Task.ContinueWith, but I'm unfamiliar with this and the examples online are dull. If anyone can show me an example with my code, it'd be great.
Here's my method:
public async Task<bool> ReturnResult()
{
this.Response = new TaskCompletionSource<bool>();
return await this.Response.Task;
}
Here's the way I'm using it in my scripts:
var result = await ReturnResult();
The Result of the TaskCompletionSource object is set by another part of my code.
Basically, if you still failed to understand what I want to achieve - a method that halts it's execution until a response has been set by another part of the code. However, it has to be asynchronous, because I don't want my main thread to get stuck.
EDIT: Tried JonSkeet's suggestion and the code just runs without halting. Here's the full Script class.
public class Script
{
private Lua Lua { get; set; }
private TaskCompletionSource<bool> Response { get; set; }
public Script()
{
this.Lua = new Lua();
}
public void Run()
{
this.Lua.RegisterFunction("log", this, typeof(Script).GetMethod("Log"));
this.Lua.RegisterFunction("returnResult", this, typeof(Script).GetMethod("ReturnResult"));
this.Lua.DoFile(#"C:\test.lua");
}
public void SetResponse(bool response)
{
this.Response.SetResult(response);
}
public Task<bool> ReturnResult()
{
this.Response = new TaskCompletionSource<bool>();
return this.Response.Task;
}
public void Log(string text)
{
MessageBox.Show(text);
}
}
Here's the code of Form1:
public partial class Form1 : Form
{
private Script Script { get; set; }
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.Script = new Script();
this.Script.Run();
}
private void button2_Click(object sender, EventArgs e)
{
this.Script.SetResponse(true);
}
}
Just throw two buttons and use the first one to run, second one to set response.
The Lua script is:
result = returnResult()
log("returned " .. result)
Download NLua from here.

Okay, as you now claim this has nothing to do with Lua, here's how you would call the method in C#, then log only when the task had completed:
Task<bool> task = ReturnResult();
task.ContinueWith(t => Log("Returned " + t.Result));
This does not halt execution at all - it just says that when the task returned from ReturnResult completes, it should call the logging code.
For production code, you would probably want to check whether the task was faulted, etc. There are overloads of ContinueWith which allow you to specify under which circumstances you want to run the continuation (only on success, only on fault etc), and you can add multiple continuations. But to get you going, the above is probably good enough.

Related

Kick off async method in constructor in c#

I'm wondering is it safe to call async method in a constructor in the following way:
Let's say we have an async method Refresh that is fetching data from the internet. We are also using Reactive Extensions to notify everyone that is interested that new data was fetched.
I'm wondering is it safe to call Refresh first time in a class constructor? Can I use such construction?
Task.Run(Refresh);
or
Refresh().ConfigureAwait(false)
I'm not really interested here if the method has finished or not, since I will get notified through Reactive Extensions when data is fetched.
Is it ok to do something like this?
public class MyClass
{
BehvaiorSubject<Data> _dataObservable = new BehvaiorSubject(Data.Default);
IObservable DataObservable => _dataObservable;
public MyClass()
{
Refresh().ConfigureAwait(false);
}
public async Task Refresh()
{
try
{
var data = await FetchDataFromNetwork();
_dataObservable.OnNext(data);
}
catch (VariousExceptions e)
{
//do some appropriate stuff
}
catch(Exception)
{
//do some appropriate stuff
}
}
}
Though people are against the idea, we have similar things in our project :)
The thing is you have to properly handle any exceptions thrown from that Task in case they go unobserved. Also you might need to expose the task via either a method or a property, just so that it is possible to await (when necessary) the async part is finished.
class MyClass
{
public MyClass()
{
InitTask = Task.Delay(3000);
// Handle task exception.
InitTask.ContinueWith(task => task.Exception, TaskContinuationOptions.OnlyOnFaulted);
}
public Task InitTask { get; }
}

Using async void to implement dataprovider

I have an interface like this
public interface IServerDataProvider
{
string Val1 { get; }
string Val2 { get; }
event EventHandler<EventArgs> Val1Changed;
event EventHandler<EventArgs> Val2Changed;
}
It gives the user access to two strings retrieved from a server and events that are triggered when these strings change.
Learning about async-await in c#, I can make a fairly simple implementation that periodically checks if these values are changed on a server :
public class ServerDataProviderAsync : IServerDataProvider
{
public event EventHandler<EventArgs> Val1Changed;
public event EventHandler<EventArgs> Val2Changed;
private string _val1Url = "someUrl";
private string _val2Url = "otherUrl";
private const int _delayMs = 1000;
public ServerDataProviderAsync()
{
Start();
}
private async void Start()
{
Val1 = await DownloadString(_val1Url);
Val2 = await DownloadString(_val2Url);
Val1UpdateLoop();
Val2UpdateLoop();
}
private async void Val1UpdateLoop()
{
await Task.Delay(_delayMs);
Val1 = await DownloadString(_val2Url);
Val1UpdateLoop();
}
private async void Val2UpdateLoop()
{
await Task.Delay(_delayMs);
Val2 = await DownloadString(_val1Url);
Val2UpdateLoop();
}
private string _val1;
public string Val1
{
get { return _val1; }
private set
{
if (_val1 != value && value != null)
{
_val1 = value;
OnContentChanged(Val1Changed);
}
}
}
private string _val2;
public string Val2
{
//similar to Val1
}
private async Task<string> DownloadString(string url)
{
using (var wb = new WebClient())
{
try { return await wb.DownloadStringTaskAsync(url); }
catch { /*log error*/}
}
return null;
}
private void OnContentChanged(EventHandler<EventArgs> handler)
{
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
And it can be used something like this from MainWindow :
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var dataProvider = new ServerDataProviderAsync();
//hook up to events and display strings in GUI
}
}
Now my question is if this is a good implementaion? Is there a better way?
The first part I'm worried about are the async void methods. I've read they should only be used for event handlers. Are they bad in this case? And if so, why?
The other thing I'm worried about is the recursive way the update loops work. But it seems that since it always awaits tasks that are not already finished, it will not keep adding to the call stack.
You should really use an [iterative] infinite loop to create an infinite loop rather than using infinite recursion.
Using recursion means constantly spending the effort to re-create the exact same state machine from scratch each iteration instead of using the perfectly fine state machine that you already have, and it needlessly obfuscates the code and reduces clarity (to the point that you yourself weren't even sure of the possible negative repercussions; you don't want every single other person who reads the code to have to think through the same problem) for no real gain. Additionally, if you want to be able to propagate exceptions generated in this method to the caller (discussed further below) then using recursion has a number of problems, such as completely messing up the call stack, making actually throwing the exception through all of those levels difficult, and also creating a memory leak in that each "finished" state machine wouldn't be able to be cleaned up.
As for the methods being void, that's not particularly problematic. The reason that one would normally want a Task returned is so that you can tell when the operation finishes. Your operations never finish, they run forever. Getting a task that will never be completed isn't really any more or less useful than not getting a task at all in most circumstances.
The only way it might be relevant is error handling. If your loop generates an error and the method is void it needs to be responsible for handling that error itself, because it is conceptually a top level method. If it returns a Task then it gets the luxury of simply throwing that exception to its caller and leaving that caller responsible for handling that Exception. This would be the only reason to not return void for a method that is supposed to run forever.

C# Call a showdialog inside backgroundworker from a Class library [duplicate]

I am working on a VS project/solution that is used by different applications. My job is to refactor the project and change it from using xxxAsync method to using BeginInvoke.
I came up to something similar to the following code:
public class AsyncTestModel {
private delegate string DoTaskDelegate();
public static EventHandler<TaskCompletedEventArgs> OnTaskCompleted;
public static void InvokeTask() {
DoTaskDelegate taskDelegate = Task;
taskDelegate.BeginInvoke(new AsyncCallback(TaskCallback), null);
}
private static string Task() {
Thread.Sleep(5000);
return "Thread Task successfully completed.";
}
private static void TaskCallback(IAsyncResult ar) {
string result = ((DoTaskDelegate)((System.Runtime.Remoting.Messaging.AsyncResult)ar).AsyncDelegate).EndInvoke(ar);
if (OnTaskCompleted != null) {
OnTaskCompleted(null, new TaskCompletedEventArgs(result));
}
}
}
public class TaskCompletedEventArgs : EventArgs {
private string _message;
public TaskCompletedEventArgs(string message) : base() {
_message = message;
}
public string Message {
get {
return _message;
}
}
}
I've tested this on a new UI project I've created. The UI project contains a button and a label controls. The UI has the following code:
private void button1_Click(object sender, EventArgs e) {
AsyncTestModel.OnTaskCompleted += OnTaskCompleted;
AsyncTestModel.InvokeTask();
}
private void OnTaskCompleted(object sender, TaskCompletedEventArgs e) {
UpdateLabel(e.Message);
}
private void UpdateLabel(string message) {
this.label1.Text = message;
}
After running this, I've encountered the cross-thread exception saying the the control 'label1' is being accessed from other thread aside the thread that it was created.
Is there a way for me to invoke the OnTaskCompleted event handler on the same thread that calls the BeginInvoke method? I know I could just use the form's InvokeRequired and call the form's BeginInvoke like the following:
private delegate void DoUpdateLabelDelegate(string message);
private void UpdateLabel(string message) {
if (this.InvokeRequired) {
IAsyncResult ar = this.BeginInvoke(new DoUpdateLabelDelegate(UpdateLabel), message);
this.EndInvoke(ar);
return;
}
this.label1.Text = message;
}
But the solution above will require me to ask and apply that solution to the other development team handling applications that uses my project/solution. Those other developers shouldn't be required to know that the methods hooked to the event handler are running from different thread.
Thanks, in advance.
As designed, no, you have absolutely no idea which thread is the one on which the client's UI runs.
You can arbitrarily demand that your InvokeTask() is to be called from that UI thread. Now you know, you can copy SynchronizationContext.Current in the InvokeTask() method and, later, call its Post() or Send() method to call a method that fires the event. This is the pattern used by, for example, BackgroundWorker and async/await. Do note that copying the Current property is required to make this work, don't skip it.
That of course still won't work when your InvokeTask() method is not called from the UI thread, you'll see that Synchronization.Current is null and have no hope to marshal the call. If that's a concern then you could expose a property of type ISynchronizeInvoke, call it SynchronizingObject. Now it is up to the client code to make the call, they'll have no trouble setting the property, they'll simply assign this in their form class constructor. And you use the property's Post or Send method to call the method that raises the event. This is the pattern used by for example the Process and FileSystemWatcher classes. Don't use it if you expect your library to be used by non-Winforms client apps, unfortunately later GUI libraries like WPF and Silverlight don't implement the interface. Otherwise the exact same problem with approaches like calling Control.Begin/Invoke() yourself.
try to use this, maybe it can help you.
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
//Do something...
});

Multiple Asynchronous Task execution

Please bear with me :-)
I'm struggling with the TPL in c# and am stuck trying to figure out the best way to design a solution for kicking off multiple async tasks, waiting for them to complete, and moving on. My initial POC is below. Each IDataGatherer instance needs to get the data and massage it into a DataObject instance.
I'm unsure of how to handle the continuation from the DownloadStringTaskAsync call such that I can take the result and massage it into a DataObject. ContinueWith wants to be provided a method with void return signature but I feel like the ExtractData method needs to return a Task instance or else I don't have a Task instance to return from the GetDataAsync() method.
I'm also wondering if I need to introduce a TaskCompletionSource in my IDataGatherer instances but how do I hitch that onto the task(s) that are doing the real work - DownloadstringTaskAsync and ExtractData for example?
interface IDataGatherer
{
Task<DataObject> GetDataAsync();
}
class DataObject
{
public string Data { get; set; }
}
class IpGatherer : IDataGatherer
{
private readonly string _url = "http://ip.jsontest.com";
public Task<DataObject> GetDataAsync()
{
var tcs = new TaskCompletionSource<DataObject>(); // Do I need this???
var client = new WebClient();
// stuck here
var task = client.DownloadStringTaskAsync(_url).ContinueWith(ExtractData);
}
private void ExtractData(Task<string> obj)
{
}
}
class Program
{
private static void Main(string[] args)
{
// takes a list of IDataGatherers and waits for them
// all to complete, handles exceptions, etc.
}
}
Designing the solution this way may be over-complicating things so I'm open to suggestions to clean things up or do them more succinctly.
I'm using .NET 4.5
First, you don't need TaskCompletionSource. That's because ContinueWith() can be provided with a method with non-void signature. E.g.:
public Task<DataObject> GetDataAsync()
{
var client = new WebClient();
return client.DownloadStringTaskAsync(_url)
.ContinueWith((Func<Task<string>, DataObject>)ExtractData);
}
private DataObject ExtractData(Task<string> task)
{
return new DataObject(task.Result);
}
(Using Result won't block, because you can be certain the Task will be completed at that point.)
But since you're using DownloadStringTaskAsync(), you're likely on .Net 4.5, which means you can use await. That makes the code even simpler:
public async Task<DataObject> GetDataAsync()
{
var client = new WebClient();
var s = await client.DownloadStringTaskAsync(_url);
return ExtractData(s);
}
private DataObject ExtractData(string s)
{
return new DataObject(s);
}

Metro - write async c# operation and call from javascript

I have create a metro app which is composed by
- a c# windows runtime component
- a javascript application, wich contains the UI and is the main application.
In the c# component I created an async method:
async public void createDocument() {
}
but when I try to call it from the javascript code, I cannot use the .done() or the then() function to handle the method completed evet, because there is an error: javascript error, cannot call done() from object not set to an instance of object.
If I try to assign Task or Task to the function I have another error, which tell me Task is not a windows runtime type and to use IAsyncOperation, IAsyncAction, ecc.. instead.
So, how can I create an async function in the c# windows runtime component and call it from javascript handling the done() or then() events?
I found an article that seems to be related to the problem you are having. I haven't done this myself, but the gist of it says that you can't use the async keyword from C# for Javascript promises - you must wrap the method in a slightly different way:
instead of:
public sealed class Class1
{
public async void testAsync()
{
// do this asynchronously ...
}
}
try:
public sealed class Class1
{
public IAsyncActionWithProgress<Result> testAsync()
{
return AsyncInfo.Run<Result>((token, result) =>
Task.Run<Result>(()=>
{
// do this asynchronously ...
return new Result();
}
));
}
}
public sealed class Result { ... }
}
I copied and pasted the examples from this article by Ronald Widha - http://www.ronaldwidha.net/2012/05/10/winrt-consumer-preview-calling-c-csharp-async-class-libraries-from-javascript-winjs-promises-using-then-clause/ It was written during the consumer preview, so it might have changed between then and the final release
Hopefully that will help you a bit more!
Just for information, if you need to call asyncronous methods inside the procedure, you need to use:
public static IAsyncOperation<IList<string>> DownloadAsStringsAsync(string id)
{
return Task.Run<Type retourned>(async () =>
{
var data = await AsyncMethod(...);
return (somethingOfTypeRetourned;
}).AsAsyncOperation();
}

Categories