I am using MonoDevelop (.net 2.0) to develop a iOS and Android app. I use BeginGetResponse and EndGetResponse to asynchronously do a webrequest in a background thread.
IAsyncResult result = request.BeginGetResponse(new AsyncCallback(onLogin), state);
However, the callback onLogin does seem to still be running on a background thread, no allowing me to interact with the UI. How do I solve this?
Can see that there are Android and iOS specific solutions but want a cross-platform solution.
Edit: From mhutch answer I've got this far:
IAsyncResult result = request.BeginGetResponse(o => {
state.context.Post(() => { onLogin(o); });
}, state);
Where state contains a context variable of type SynchronizationContext set to SynchronizationContext.Current
It complains that Post requires two arguments, the second one being Object state. Inserting state gives the error
Argument `#1' cannot convert `anonymous method' expression to type `System.Threading.SendOrPostCallback' (CS1503) (Core.Droid)
Both Xamarin.iOS and Xamarin.Android set a SynchronizationContext for the GUI thread.
This means you get the SynchronizationContext.Current from the GUI thread and pass it to your callback (e.g via the state object or captured in a lambda). Then you can use the context's Post method to invoke things on the main thread.
For example:
//don't inline this into the callback, we need to get it from the GUI thread
var ctx = SynchronizationContext.Current;
IAsyncResult result = request.BeginGetResponse(o => {
// calculate stuff on the background thread
var loginInfo = GetLoginInfo (o);
// send it to the GUI thread
ctx.Post (_ => { ShowInGui (loginInfo); }, null);
}, state);
I'm not sure if this works on Mono, but I usually do this on WinForm applications. Let's suppose you want to execute the method X(). Then:
public void ResponseFinished() {
InvokeSafe(() => X()); //Instead of just X();
}
public void InvokeSafe(MethodInvoker m) {
if (InvokeRequired) {
BeginInvoke(m);
} else {
m.Invoke();
}
}
Of course, this is inside a Form class.
Related
I implemented an experimental lightweight in-memory message bus, where recipients can subscribe to messages via the Subscribe() method which I pasted below.
A sender can send messages and the message bus will invoke an internal call back internalCallback. Before the callback is invoked the message may be deep-cloned and marshaled onto a UI thread.
This is where my problem arises: When I comment out the UI dispatcher (as is done in the snippet below) then the callback is invoked correctly. With the dispatcher active the entire application hangs (no run-time error is thrown). What confuses me even more is that the entire below code worked perfectly fine when I ran the calling method on a UI thread. But now the entire framework may also send messages on different tasks/threads and this is when problems arose.
What should I be looking into or possibly adjust?
Thanks
public void Subscribe<T>(string subscriberId, string topic, Action<string, T> callback, bool returnOnUiThread, bool makeDeepCopy, bool catchAll)
{
//create new peer connection if it does not yet exist
if (!_peerConnections.ContainsKey(subscriberId))
{
var newPeer = new PeerConnection(subscriberId)
{
ConnectionStatus = PeerConnectionStatus.Connected,
CreationTimeStamp = DateTime.Now,
LastAliveTimeStamp = DateTime.Now
};
_peerConnections.Add(subscriberId, newPeer);
}
var internalCallBack = new Action<string, object>((header, msg) =>
{
//make a deep copy via serialization if requested
if (makeDeepCopy == true)
{
//try deep clone
var serializedObject = Serializers.JsonStringFromObject(msg);
msg = Serializers.ObjectFromJsonString<T>(serializedObject);
}
var handle = callback;
handle(header, (T)msg);
////return on ui thread if requested
//if (returnOnUiThread == true)
//{
// Application.Current.Dispatcher.Invoke(() =>
// {
// var handle = callback;
// handle(header, (T)msg);
// });
//}
//else
//{
// var handle = callback;
// handle(header, (T)msg);
//}
});
//adding subscription to collection
var subscription = new Subscription(subscriberId, topic, internalCallBack, catchAll);
_subscriptions.Add(subscription);
}
You should use BeginInvoke as the Invoke can lead to a deadlock. Invoke is kind of a lock so it will wait, blocking the current thread until the action finishes. BeginInvoke places the request onto the Windows Message Pump where it will be processed by the UI thread later without blocking the worker thread.
Even though the Windows GUI isn't multithreaded, you can still deadlock it. Checkout the article below.
More
Multithreaded toolkits: A failed dream? Blog, Oracle, October 19 2004
I'm working on a WinRT component in C# which I'm calling from WinJS asyncronously.
I'm calling a library which when called, throws The application called an interface that was marshalled for a different thread exception. I understand this to be an issue with the thread that the library code is running on, via the UI thread the JS code is running under.
I've found some threads on here which mention ways this can potentially work ( Run code on UI thread in WinRT etc ) but none of these touch on calling code from WinJS, they all tend to be XAML.
So, I'm hoping to answer two questions:
At a high level, should I by trying to make the WinRT library code run on the UI thread? thereby making it syncronous? if that is correct, what is the most effective way to make my WinRT code which handles writing to the file system, behave in this way (code below)
RT Code
public IAsyncOperation<string> ButtonPress()
{
return SaveSpreadsheet().AsAsyncOperation();
}
private async Task<string> SaveSpreadsheet()
{
var res = false;
try
{
CreateSpreadsheet();
AddSomeContentToASheet();
var folder = KnownFolders.DocumentsLibrary;
var outFile = await folder.CreateFileAsync("New.xls", CreationCollisionOption.ReplaceExisting);
res = await book.SaveAsAsync(outFile, ExcelSaveType.SaveAsXLS);
book.Close();
engine.Dispose();
}
catch (Exception e)
{
return e.Message;
}
return "Success! " + res;
}
JS Code
button.onclick = function () {
var rtComponent = new WindowsRuntimeComponent1.Class1();
rtComponent.buttonPress().then(function (res) {
document.getElementById('res').innerText = "Export should have: " + res;
});
};
If 1 is wrong and I should by trying to leave the RT code async but running on the same thread as my JS UI code, how can I get a reference to that thread, and then kick off the methods in the RT code? I've tried some Dispatcher.RunAsync() ways of running the RT code, but I come unstuck when I need to get a reference to an IStorageFile through the WinRT framework methods.
Any thoughts greatly appreciated.
I believe what you're missing is a call to Task.Run, which is what actually creates the Task that will run the operation on a separate thread and do the marshaling.
That is, your SaveSpreadsheet function says it's returning Task but doesn't actually create the Task anywhere, and is thus just returning a string. Here's the general structure of an async function in a component:
public IAsyncOperation<string> SomeMethodAsync(int id)
{
var task = Task.Run<string>(async () =>
{
var idString = await GetMyStringAsync(id);
return idString;
});
return task.AsAsyncOperation();
}
So I think you just need to change SaveSpreadsheet to return a String (which your code is doing already, so just change Task to String), and make ButtonPress look like this:
public IAsyncOperation<string> ButtonPress()
{
var task = Task.Run<string>(async () =>
{
return await SaveSpreadsheet();
});
return task.AsAsyncOperation();
}
I cover this subject, by the way, in Chapter 18 of my free ebook from MSPress, Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition, http://aka.ms/BrockschmidtBook2.
P.S. If there's no reason for your component to be instantiable with new, then you can add the static keyboard to ButtonPress (i.e. public static IAsyncOperation ButtonPress()) and then just make the call with the fully-qualified name WindowsRuntimeComponent1.Class1.buttonPress().then(...). That might simplify your code.
I've tried various methods from other SO questions over the last week and this is the best approach I found yet, but I do not know how to unit test this with NUnit.
private void VerifyDispatcherThread()
{
var context = SynchronizationContext.Current;
if (context != null && context is DispatcherSynchronizationContext)
{
Log.For(this).Info("WARNING! - Method Should Not Be Called From Dispatcher Thread.");
if (DispatcherThreadSafetyEnabled)
{
throw new ThreadStateException("Method Should Not Be Called From Dispatcher Thread.");
}
}
}
HERE IS OUR TEST (Not Working)
[Test]
public void Should_throw_exception_when_called_from_dispatcher()
{
// Arrange
var called = false;
Boolean? success = null;
var httpClient = new HttpClient(HttpTimeOut);
// This emulates WPF dispatcher thread
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext());
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
// Act
dispatcher.BeginInvoke(delegate()
{
try
{
ConfigurationManager.AppSettings.Set("DispatcherThreadSafetyEnabled", "true");
httpClient.Post("http://Foo", "content xml");
success = true;
}
catch
{
success = false;
}
finally
{
ConfigurationManager.AppSettings.Set("DispatcherThreadSafetyEnabled", "false");
}
called = true;
});
// this part is a bit ugly
// spinlock for a bit to give the other thread a chance
var timeout = 0;
while (!called && timeout++ < 1000)
Thread.Sleep(1);
// Assert
Assert.IsNotNull(success, "Method was never invoked");
Assert.IsFalse(success.Value, "Expected to fail");
}
DispatcherThreadSafetyEnabled is a app.config setting we have so we can toggle only logging or throwing exceptions.
What we are trying to do is verify the calling method isn't using the GUI thread when invoked. It appears to be working but we are having a hard time trying to unit test this.
Here's hoping someone has done this and can help us out with our challenge.
The current SynchronizationContext is set to different implementations by different frameworks (Winforms, WPF, etc).
Quoting from this MSDN article:
WindowsFormsSynchronizationContext (System.Windows.Forms.dll:
System.Windows.Forms) Windows Forms apps will create and install a
WindowsFormsSynchronizationContext as the current context for any
thread that creates UI controls.
DispatcherSynchronizationContext (WindowsBase.dll:
System.Windows.Threading) WPF and Silverlight applications use a
DispatcherSynchronizationContext, which queues delegates to the UI
thread’s Dispatcher with “Normal” priority. This
SynchronizationContext is installed as the current context when a
thread begins its Dispatcher loop by calling Dispatcher.Run.
Since you are only testing for not null and the type of the SynchronizationContext, try setting current SynchronizationContext to an instance of DispatcherSynchronizationContextby calling SynchronizationContext.SetSynchronizationContext from your unit tests. Sample code below:
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));
Please note this is not a recommended in a Winforms/WPF application though.
When awaiting Dispatcher.RunAsync the continuation occurs when the work is scheduled, not when the work has completed. How can I await the work completing?
Edit
My original question assumed the premature continuation was caused by the design of the API, so here's the real question.
When awaiting Dispatcher.RunAsync using an asynchronous delegate, using await within the delegate's code, the continuation occurs when the await is encountered, not when the work has completed. How can I await the work completing?
Edit 2
One reason you may need to dispatch work that's already on the UI thread is to workaround subtle timing and layout issues. It's quite common for values of sizes and positions of elements in the visual tree to be in flux and scheduling work for a later iteration of the UI can help.
I found the following suggestion on a Microsoft github repository: How to await a UI task sent from a background thread.
Setup
Define this extension method for the CoreDispatcher:
using System;
using System.Threading.Tasks;
using Windows.UI.Core;
public static class DispatcherTaskExtensions
{
public static async Task<T> RunTaskAsync<T>(this CoreDispatcher dispatcher,
Func<Task<T>> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal)
{
var taskCompletionSource = new TaskCompletionSource<T>();
await dispatcher.RunAsync(priority, async () =>
{
try
{
taskCompletionSource.SetResult(await func());
}
catch (Exception ex)
{
taskCompletionSource.SetException(ex);
}
});
return await taskCompletionSource.Task;
}
// There is no TaskCompletionSource<void> so we use a bool that we throw away.
public static async Task RunTaskAsync(this CoreDispatcher dispatcher,
Func<Task> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) =>
await RunTaskAsync(dispatcher, async () => { await func(); return false; }, priority);
}
Once you do that, all you need to do is use the new RunTaskAsync method to have your background task await on the UI work.
Usage example
Let's pretend that this is the method that needs to run in the UI thread. Pay attention to the debug statements, which will help follow the flow:
public static async Task<string> ShowMessageAsync()
{
// Set up a MessageDialog
var popup = new Windows.UI.Popups.MessageDialog("Question", "Please pick a button to continue");
popup.Commands.Add(new Windows.UI.Popups.UICommand("Button 1"));
popup.Commands.Add(new Windows.UI.Popups.UICommand("Button 2"));
popup.CancelCommandIndex = 0;
// About to show the dialog
Debug.WriteLine("Waiting for user choice...");
var command = await popup.ShowAsync();
// Dialog has been dismissed by the user
Debug.WriteLine("User has made a choice. Returning result.");
return command.Label;
}
To await that from your background thread, this is how you would use RunTaskAsync:
// Background thread calls this method
public async void Object_Callback()
{
Debug.WriteLine("Object_Callback() has been called.");
// Do the UI work, and await for it to complete before continuing execution
var buttonLabel = await Dispatcher.RunTaskAsync(ShowMessageAsync);
Debug.WriteLine($"Object_Callback() is running again. User clicked {buttonLabel}.");
}
The output then looks like this:
Object_Callback() has been called.
Waiting for user choice...
User has made a choice. Returning result.
Object_Callback() is running again. User clicked Button 1.
Your question is assuming that you want to schedule (and wait for) work on a UI thread from a background thread.
You'll usually find your code is much cleaner and easier to understand (and it will definitely be more portable) if you have the UI be the "master" and the background threads be the "slaves".
So, instead of having a background thread await some operation for the UI thread to do (using the awkward and unportable Dispatcher.RunAsync), you'll have the UI thread await some operation for the background thread to do (using the portable, made-for-async Task.Run).
You can wrap the call to RunAsync in your own asynchronous method that can be awaited and control the completion of the task and thus the continuation of awaiting callers yourself.
Since async-await is centred on the Task type, you must orchestrate the work using this type. However, usually a Task schedules itself to run on a threadpool thread and so it cannot be used to schedule UI work.
However, the TaskCompletionSource type was invented to act as a kind of puppeteer to an unscheduled Task. In other words, a TaskCompletionSource can create a dummy Task that is not scheduled to do anything, but via methods on the TaskCompletionSource can appear to be running and completing like a normal job.
See this example.
public Task PlayDemoAsync()
{
var completionSource = new TaskCompletionSource<bool>();
this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
try
{
foreach (var ppc in this.Plots.Select(p => this.TransformPlot(p, this.RenderSize)))
{
// For each subsequent stroke plot, we need to start a new figure.
//
if (this.Sketch.DrawingPoints.Any())
this.Sketch.StartNewFigure(ppc.First().Position);
foreach (var point in ppc)
{
await Task.Delay(100);
this.Sketch.DrawingPoints.Add(point.Position);
}
}
completionSource.SetResult(true);
}
catch (Exception e)
{
completionSource.SetException(e);
}
});
return (Task)completionSource.Task;
}
Note: the main work being done on the UI thread is just some lines being drawn on screen every 100ms.
A TaskCompletionSource is created as the puppet master. Look near the end and you'll see that it has a Task property that is returned to the caller. Returning Task satisfies the compilers needs and makes the method awaitable and asynchronous.
However, the Task is just a puppet, a proxy for the actual work going on in the UI thread.
See how in that main UI delegate I use the TaskCompletionSource.SetResult method to force a result into the Task (since returned to the caller) and communicate that work has finished.
If there's an error, I use SetException to 'pull another string' and make it appear that an exception has bubbled-up in the puppet Task.
The async-await subsystem knows no different and so it works as you'd expect.
Edit
As prompted by svick, if the method was designed to be callable only from the UI thread, then this would suffice:
/// <summary>
/// Begins a demonstration drawing of the asterism.
/// </summary>
public async Task PlayDemoAsync()
{
if (this.Sketch != null)
{
foreach (var ppc in this.Plots.Select(p => this.TransformPlot(p, this.RenderSize)))
{
// For each subsequent stroke plot, we need to start a new figure.
//
if (this.Sketch.DrawingPoints.Any())
this.Sketch.StartNewFigure(ppc.First().Position);
foreach (var point in ppc)
{
await Task.Delay(100);
this.Sketch.DrawingPoints.Add(point.Position);
}
}
}
}
A nice way to work the clean way #StephenCleary suggests even if you have to start from a worker thread for some reason, is to use a simple helper object. With the object below you can write code like this:
await DispatchToUIThread.Awaiter;
// Now you're running on the UI thread, so this code is safe:
this.textBox.Text = text;
In your App.OnLaunched you have to initialize the object:
DispatchToUIThread.Initialize(rootFrame.Dispatcher);
The theory behind the code below you can find at await anything;
public class DispatchToUIThread : INotifyCompletion
{
private readonly CoreDispatcher dispatcher;
public static DispatchToUIThread Awaiter { get; private set; }
private DispatchToUIThread(CoreDispatcher dispatcher)
{
this.dispatcher = dispatcher;
}
[CLSCompliant(false)]
public static void Initialize(CoreDispatcher dispatcher)
{
if (dispatcher == null) throw new ArgumentNullException("dispatcher");
Awaiter = new DispatchToUIThread(dispatcher);
}
public DispatchToUIThread GetAwaiter()
{
return this;
}
public bool IsCompleted
{
get { return this.dispatcher.HasThreadAccess; }
}
public async void OnCompleted(Action continuation)
{
if (continuation == null) throw new ArgumentNullException("continuation");
await this.dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => continuation());
}
public void GetResult() { }
}
How could I call the onCompleteCallBack method on the same thread the SomeAsyncMethod was called ?
public void SomeAsycMethod ( Action<object> onCompleteCallBack )
{
// get the current thread
/* var ThisThread = Thread.CurrentThread. */
Task.Factory.StartNew( () =>
{
Thread.Sleep( 1000 );// do some work;
// lastly call the onCompleteCallBack on 'ThisThread'
onCompleteCallBack( "some result" );
// I am looking for something like:
/* ThisThread.Invoke("some result"); */
});
}
While you can't guarantee you callback will be called on the same thread, you can guarantee it will be called in the same Synchronization Context (assuming one exists in the original call).
public void SomeAsycMethod ( Action<object> onCompleteCallBack )
{
// get the current context
var context = SynchronizationContext.Current;
Task.Factory.StartNew( () =>
{
Thread.Sleep( 1000 );// do some work;
// lastly call the onCompleteCallBack on 'ThisThread'
onCompleteCallBack( "some result" );
// I am looking for something like:
context.Post(s => onCompleteCallBack ("some result"), null);
});
}
For example, in a Windows Forms or WPF program, the above will make sure that the callback is called on the GUI thread (via the message loop or dispatcher, accordingly). Similarly for ASP.NET context.
Having said that, I agree with Justin Harvey in that returning a Task<T> will probably be a better design.
Actually if you're using Task-based asynchronous programming I suggested you refactor your code to return Task<T> and give an ability to your client itself to decide in what context to call callback method (and facilitate future migration to C# 5.0 ;):
public Task<string> SomeMethodAsync()
{
return Task.Factory.StartNew(() => "some result");
}
If you definitely know that you're going to call this method from UI thread you can use following:
var task = SomeMethodAsync();
task.ContinueWith(t => textBox.Text = t.Result, TaskScheduler.FromSynchronizationContext);
This approach is better because it provide more clear separation of concern and give an ability to use your asynchronous method in any context without any dependencies to synchronization context. Some client can call this method from UI thread (and in this case TaskScheduler.FromSynchronizationContext would behave as expected - your "continuation" would be called in UI thread), some of them could use your method from non-UI thread as well without such requirements like processing results in the same thread that initiate asynchronous operation.
Task<T> is a perfect class that represents asynchronous operation as a first class object that helps not only obtain only more declarative code but more clear, easy to read and easy to test (you can easily mock this method and return "fake" task object).