This function must be called from a UI thread - c#

Using the following Microsoft web page as a reference..
https://learn.microsoft.com/en-us/windows/msix/store-developer-package-update
I am trying to write code to update a test application I have uploaded to the Microsoft Store. Uploaded to the store is a simple dialog and a few updates (changed background color) written in C# Windows Forms using a UWP wrapper in the form of a Windows Application Packaging Project.
The dialog has a couple of buttons, one of which calls the following cut/paste methods from the above webpage..
private async void InstallUpdatesAsync()
{
StoreContext updateManager = StoreContext.GetDefault();
IReadOnlyList<StorePackageUpdate> updates = await updateManager.GetAppAndOptionalStorePackageUpdatesAsync();
// Save app state here
IAsyncOperationWithProgress<StorePackageUpdateResult, StorePackageUpdateStatus> installOperation =
updateManager.RequestDownloadAndInstallStorePackageUpdatesAsync(updates);
StorePackageUpdateResult result = await installOperation.AsTask();
// Under normal circumstances, app will terminate here
// Handle error cases here using StorePackageUpdateResult from above
}
I am getting the error..
System.Reflection.TargetInvocationException: 'Exception has been
thrown by the target of an invocation.'
Inner Exception Exception: Invalid window handle.
This function must be called from a UI thread
I don't understand this as I am calling it from a button from a dialog box. I have seen various comments elsewhere that the commands have to be called from a UI thread, but I cannot find out how.
Any help much appreciated.
EDIT:
private void installButton_Click(object sender, EventArgs e)
{
rtb.SelectionColor = CommandColor;
rtb.AppendText("Installing updates\n\n");
InstallUpdatesAsync();
}

Try creating your own helper class and use it's RunSync extension method, it will be your universal solution, eliminating requirement to adapt different Dispatcher implementations from different platforms.
public static class AsyncHelpers
{
/// <summary>
/// Execute's an async Task<T> method which has a void return value synchronously
/// </summary>
/// <param name="task">Task<T> method to execute</param>
public static void RunSync(Func<Task> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
synch.Post(async _ =>
{
try
{
await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
}
/// <summary>
/// Execute's an async Task<T> method which has a T return type synchronously
/// </summary>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="task">Task<T> method to execute</param>
/// <returns></returns>
public static T RunSync<T>(Func<Task<T>> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
T ret = default;
synch.Post(async _ =>
{
try
{
ret = await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
return ret;
}
private class ExclusiveSynchronizationContext : SynchronizationContext
{
private readonly Queue<Tuple<SendOrPostCallback, object>> _Items =
new Queue<Tuple<SendOrPostCallback, object>>();
private readonly AutoResetEvent _WorkItemsWaiting = new AutoResetEvent(false);
private bool _Done;
public Exception InnerException { get; set; }
public override void Send(SendOrPostCallback d, object state)
{
throw new NotSupportedException("We cannot send to our same thread");
}
public override void Post(SendOrPostCallback d, object state)
{
lock (_Items)
{
_Items.Enqueue(Tuple.Create(d, state));
}
_WorkItemsWaiting.Set();
}
public void EndMessageLoop()
{
Post(_ => _Done = true, null);
}
public void BeginMessageLoop()
{
while (!_Done)
{
Tuple<SendOrPostCallback, object> task = null;
lock (_Items)
{
if (_Items.Count > 0) task = _Items.Dequeue();
}
if (task != null)
{
task.Item1(task.Item2);
if (InnerException != null) // the method threw an exeption
throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
}
else
{
_WorkItemsWaiting.WaitOne();
}
}
}
public override SynchronizationContext CreateCopy()
{
return this;
}
}
}

I did not work in UWP, but some controls are inside the UI thread and because the function that is running is multiple threads, it is not allowed to run. I put a code below but I do not know if it works or not.
private async void installButton_Click(object sender, EventArgs e)
{
rtb.SelectionColor = CommandColor;
rtb.AppendText("Installing updates\n\n");
await this.Dispatcher.RunAsync(CoreDispatcherPriority.High, () => {
InstallUpdatesAsync()
});
}

Related

Convert BackgroundWorker to Task, best practice?

I have a class SimpleTask which looks like this:
public class SimpleTask<T>
{
private readonly Action<Exception> _errorAction;
private readonly Func<T> _produce;
private readonly Action<T> _then;
public SimpleTask(Func<T> produce, Action<T> then, Action<Exception> errorAction)
{
_then = then ?? throw new ArgumentNullException(nameof(then));
_errorAction = errorAction ?? throw new ArgumentNullException(nameof(errorAction));
_produce = produce ?? throw new ArgumentNullException(nameof(produce));
}
public void Run()
{
using (var backgroundWorker = new BackgroundWorker())
{
var item = default(T);
backgroundWorker.DoWork += (_, e) => item = _produce();
backgroundWorker.RunWorkerCompleted += (_, e) =>
{
if (e.Error != null)
{
_errorAction(e.Error);
return;
}
_then(item);
};
backgroundWorker.RunWorkerAsync();
}
}
}
I would like to use a Task instead of a BackgroundWorker but I end up with something like this:
public class SimpleTask<T>
{
private readonly Action<Exception> _errorAction;
private readonly Func<T> _produce;
private readonly Action<T> _then;
public SimpleTask(Func<T> produce, Action<T> then, Action<Exception> errorAction)
{
_then = then ?? throw new ArgumentNullException(nameof(then));
_errorAction = errorAction ?? throw new ArgumentNullException(nameof(errorAction));
_produce = produce ?? throw new ArgumentNullException(nameof(produce));
}
public void Run()
{
try
{
var synchronizationContext = TaskScheduler.FromCurrentSynchronizationContext();
Task.Run(_produce,CancellationToken.None).ContinueWith(t =>
{
if (t.IsFaulted)
{
_errorAction(t.Exception);
}
else if (t.IsCompleted)
{
_then(t.Result);
}
}, CancellationToken.None,TaskContinuationOptions.ExecuteSynchronously,synchronizationContext);
}
catch (Exception ex)
{
_errorAction(ex);
}
}
}
Which is not the same after all. In my unit tests I have to add:
[SetUp]
public void TestSetUp()
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
I wonder if I should keep using the BackgroundWorker and not pollute my code with task/async structures? What is best practice?
You are reinventing the wheel, because the new async functionality handles most of this for you.
I assume you want to:
Run in a background task a compute bound method that returns a result
Handle any exception thrown by that method
Access the returned value if no exception occurred
Here's an example of how to do this using await.
In this example, the compute-bound method is int computeBoundFunction(). The code assumes you have a Windows Forms form with a button called button1 and a multiline TextBox called textBox1:
async void button1_Click(object sender, EventArgs e)
{
textBox1.AppendText("Starting task\r\n");
try
{
int result = await Task.Run(computeBoundFunction);
// Instead of your "then" action, just call the code here.
// In this example, I'm just appending to a multiline text box.
// This runs on the UI thread.
textBox1.AppendText("Task returned " + result);
}
// Instead of your "errorAction" action, handle exceptions here.
// Note that this runs on the UI thread, so you can update controls safely at this point.
catch (Exception exception)
{
textBox1.AppendText("Exception: " + exception.Message);
}
}
int computeBoundFunction()
{
Thread.Sleep(2000); // Emulate workload.
return 42;
// Comment out the return above and uncomment the line below to test the exception handling:
//throw new InvalidOperationException("Test exception");
}
Note that normally you would never use async void instead of async Task, but this rule is relaxed for event handlers such as button1_Click() in this example.

I would like to use Condition Variable in order to know when Messages Queue is not empty, i would like to use it in "HandleMessageQueue" as a thread

I would like to use Condition Variable in order to know when Messages Queue is not empty, i would like to use it in "HandleMessageQueue" as a thread
private static Queue<Message> messages = new Queue<Message>();
/// <summary>
/// function return the first message
/// </summary>
/// <returns>first message element</returns>
public static Message GetFirst()
{
return messages.Dequeue();
}
in another class:
/// <summary>
/// Function run while the clients connected and handle the queue message
/// </summary>
public static void HandleMessageQueue()
{
// ...
}
What you're probably looking for is a simple producer-consumer pattern. In this case I'd recommend using .NET's BlockingCollection, which allows you to easily handle the following cases:
have one thread push stuff in a queue
have another thread block until stuff is available
make the whole thing easy to shutdown without having to forcibly terminate the thread
Here's a short code sample, read the comments for more information about what every bit does:
public class Queue : IDisposable
{
private readonly Thread _messageThread; // thread for processing messages
private readonly BlockingCollection<Message> _messages; // queue for messages
private readonly CancellationTokenSource _cancellation; // used to abort the processing when we're done
// initializes everything and starts a processing thread
public Queue()
{
_messages = new BlockingCollection<Message>();
_cancellation = new CancellationTokenSource();
_messageThread = new Thread(ProcessMessages);
_messageThread.Start();
}
// processing thread function
private void ProcessMessages()
{
try
{
while (!_cancellation.IsCancellationRequested)
{
// Take() blocks until either:
// 1) a message is available, in which case it returns it, or
// 2) the cancellation token is cancelled, in which case it throws an OperationCanceledException
var message = _messages.Take(_cancellation.Token);
// process the message here
}
}
catch (OperationCanceledException)
{
// Take() was cancelled, let the thread exit
}
}
// pushes a message
public void QueueMessage(Message message)
{
_messages.Add(message);
}
// stops processing and clean up resources
public void Dispose()
{
_cancellation.Cancel(); // let Take() abort by throwing
_messageThread.Join(); // wait for thread to exit
_cancellation.Dispose(); // release the cancellation source
_messages.Dispose(); // release the queue
}
}
Another option would be to combine a ConcurrentQueue<T> with a ManualResetEvent (events are roughly the .NET equivalent to condition variables), but that would be doing by hand what BlockingCollection<T> does).
something like this?
public class EventArgs<T> : EventArgs
{
private T eventData;
public EventArgs(T eventData)
{
this.eventData = eventData;
}
public T EventData
{
get { return eventData; }
}
}
public class ObservableQueue<T>
{
public event EventHandler<EventArgs<T>> EnQueued;
public event EventHandler<EventArgs<T>> DeQueued;
public int Count { get { return queue.Count; } }
private readonly Queue<T> queue = new Queue<T>();
protected virtual void OnEnqueued(T item)
{
if (EnQueued != null)
EnQueued(this, new EventArgs<T>(item));
}
protected virtual void OnDequeued(T item)
{
if (DeQueued != null)
DeQueued(this, new EventArgs<T>(item));
}
public virtual void Enqueue(T item)
{
queue.Enqueue(item);
OnEnqueued(item);
}
public virtual T Dequeue()
{
var item = queue.Dequeue();
OnDequeued(item);
return item;
}
}
and use it
static void Main(string[] args)
{
ObservableQueue<string> observableQueue = new ObservableQueue<string>();
observableQueue.EnQueued += ObservableQueue_EnQueued;
observableQueue.DeQueued += ObservableQueue_DeQueued;
observableQueue.Enqueue("abc");
observableQueue.Dequeue();
Console.Read();
}

How to queue incoming events in event handler while waiting for user's response

I use C#, .NET Framework 4.5, VS2015.
I implement an event handler for event (TcpRequest) that is fired by a black-boxed module.
My event handler call a private method that fires an event to client/GUI and waiting for user's response.
Meanwhile the black-boxed module keeps firing TcpRequest event. Somehow I need to queue the incoming events while waiting.
As soon as the user gives response for the first event, the queue can be "flushed".
Is there any design pattern or best practice for such case (to queue while wait for user's response)? Do I need to use await or something?
Following are my codes. Please feel free to modify them. Thank you in advance.
public void TcpRequestHandler(int id, CONN_INFO connInfo)
{
if (SomeCondition)
{
var myArgs = new MyEventArgs()
{
Id = id,
ConnInfo = connInfo
}
// this the way I tried and I know it is wrong,
// because it always fires event without "waiting in queue"
lock (_eventQueue)
{
_eventQueue.Add(myArgs);
}
FireEventToClient(myArgs);
}
}
private void FireEventToClient(MyEventArgs myArgs)
{
EventToClient(this, myArgs);
if (myArgs.Continue)
{
// "flush" the event queue
...
// do other things
...
}
}
public class MyEventArgs : EventArgs
{
public int Id {get; private set;}
public CONN_INFO ConnInfo {get; private set;}
public bool Continue {get; set;}
}
Declare your event EventToClient with return value and use the returned value for validation and flush the event queue
Check this, it may help
public class TCPServer
{
private int _port;
private TcpListener _tcpListener;
private bool _running, _disposed;
private BinaryFormatter _bFormatter;
private Thread _connectionThread;
private BackgroundWorker _bgwListener;
private BackgroundWorker _bgwSender;
private object syncobject = new object();
private object syncsendmessageobject = new object();
/// <summary>
/// Constructor - Initialises the TCPServer with the given port and a tcplistener. Starts a thread to monitor the message queue
/// </summary>
/// <param name="port"></param>
public TCPServer(int port)
{
try
{
this._port = port;
this._tcpListener = new TcpListener(IPAddress.Loopback, port);
this._running = false;
this._bFormatter = new BinaryFormatter();
Thread thread = new Thread(ReadQueue);
thread.Start();
}
catch (Exception ex)
{
}
}
/// <summary>
/// Starts the tcplistener.
/// </summary>
public void Start()
{
try
{
if (!_running)
{
this.MessageReceived -= TCPServer_MessageReceived;
this._tcpListener.Start();
this._running = true;
this._connectionThread = new Thread(new ThreadStart(ListenForClientConnections));
this._connectionThread.Start();
this._connectionThread.IsBackground = true;
this.MessageReceived += TCPServer_MessageReceived;
}
}
catch (Exception ex)
{
}
}
/// <summary>
/// Stops the tcplistener
/// </summary>
public void Stop()
{
if (this._running)
{
this._tcpListener.Stop();
this._tcpListener = null;
this._running = false;
}
}
public bool Running()
{
return this._running;
}
public void StopListening()
{
try
{
lock (this)
{
if (this._running)
{
this._tcpListener.AcceptTcpClient().Close();
_running = false;
}
}
}
catch (Exception ex)
{
}
}
/// <summary>
/// Thread body for listening for client connections
/// </summary>
private void ListenForClientConnections()
{
try
{
while (this._running)
{
lock (this)
{
TcpClient connectedTcpClient = this._tcpListener.AcceptTcpClient();
this._bgwListener = new BackgroundWorker();
this._bgwListener.DoWork += _bgwListener_DoWork;
this._bgwListener.WorkerReportsProgress = true;
this._bgwListener.ProgressChanged += _bgwListener_ProgressChanged;
this._bgwListener.RunWorkerAsync(connectedTcpClient);
}
}
}
catch (Exception ex)
{
}
}
/// <summary>
/// background worker listens to messages sent by clients. Categorises them based on messages/commands/applicationcommands/
/// progress response etc..
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private TcpClient clientGUI = null;
private Queue<string> messageQueue = new Queue<string>();
private void _bgwListener_DoWork(object sender, DoWorkEventArgs e)
{
TcpClient client = e.Argument as TcpClient;
BackgroundWorker bgWorker = sender as BackgroundWorker;
if (client != null)
{
try
{
while (this._running)
{
// Block until an instance Message is received
string message = this._bFormatter.Deserialize(client.GetStream()).ToString();
if (message.Equals("GUI", StringComparison.InvariantCultureIgnoreCase)
{
// Chek for first message from tcp client, if it is GUI then store it in a member variable, if you have multiple cleints then use a dictionary
clientGUI = client;
}
if(!clientGUI.Equals(client))
{
lock (syncobject)
{
messageQueue.Enqueue(message);
}
}
}
}
catch (Exception ex)
{
}
}
}
/// <summary>
/// Thread that continuously monitors the message queue for messages and
/// sends them to clients
/// </summary>
private void ReadQueue()
{
try
{
while (true)
{
try
{
TCPMessage message = null;
if (messageQueue.Count > 0)
{
lock (syncobject)
{
message = messageQueue.Dequeue();
}
if (!string.IsNullOrEmpty(message) && clientGUI != null)
{
SendMessage(clientGUI, message);
}
}
else { Thread.Sleep(10); }
}
catch (Exception ex)
{
}
}
}
catch (Exception ex)
{
}
}
private MessageReceivedEventHandler _messageReceived;
public event MessageReceivedEventHandler MessageReceived
{
add { _messageReceived += value; }
remove { _messageReceived -= value; }
}
private EventHandler<MessageEventArgs> _serverMessageSent;
public event EventHandler<MessageEventArgs> ServerMessageSent
{
add { _serverMessageSent += value; }
remove { _serverMessageSent -= value; }
}
private void SendMessage(TcpClient client, TCPMessage message)
{
try
{
lock (syncsendmessageobject)
_bFormatter.Serialize(client.GetStream(), message);
}
catch (Exception ex)
{
}
}
}

What is the alternative for BackgroundWorker in Windows 8.1 Universal Apps?

I am migrating my Windows Phone App to Windows Universal Apps. In Phone App, I used BackgroundWorker for database retrieval and then show in UI. Below is the class which I prepared in Windows Phone 8 and how it was called.
public class TestBackgroundWorker
{
private BackgroundWorker backgroundWorker;
ProgressIndicator progressIndicator;
public delegate void functionToRunInBackground();
public functionToRunInBackground currentFunctionToExecute;
public delegate void callbackFunction();
public callbackFunction functionToSendResult;
private bool isCancellationSupported;
private string message;
/// <summary>
///
/// </summary>
/// <param name="functionNameToExecute">specifies function name to be executed in background</param>
/// <param name="isCancellable">Flag which specifies whether the operation is cancellable or not</param>
/// <param name="functionNameWhichGetsResult">Specifies call back function to be executed after the completion of operation</param>
public MCSBackgroundWorker(functionToRunInBackground functionNameToExecute, bool isCancellable, string messageToDisplay, callbackFunction functionNameWhichGetsResult)
{
currentFunctionToExecute = functionNameToExecute;
functionToSendResult = functionNameWhichGetsResult;
isCancellationSupported = isCancellable;
message = messageToDisplay;
backgroundWorker = new BackgroundWorker();
backgroundWorker.WorkerSupportsCancellation = isCancellable;
backgroundWorker.DoWork += backgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
}
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
deactivateProgressIndicator();
functionToSendResult();
}
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (currentFunctionToExecute != null)
{
currentFunctionToExecute();
}
}
public void cancelBackgroundOperation()
{
if (isCancellationSupported == true)
{
backgroundWorker.CancelAsync();
}
}
public void Start()
{
backgroundWorker.RunWorkerAsync();
activateProgressIndicator();
}
void activateProgressIndicator()
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
var currentPage = App.RootFrame.Content as PhoneApplicationPage;
SystemTray.SetIsVisible(currentPage, true);
SystemTray.SetOpacity(currentPage, 0.5);
SystemTray.SetBackgroundColor(currentPage, Colors.White);
SystemTray.SetForegroundColor(currentPage, Colors.Black);
progressIndicator = new ProgressIndicator();
progressIndicator.IsVisible = true;
progressIndicator.IsIndeterminate = true;
progressIndicator.Text = message;
SystemTray.SetProgressIndicator(currentPage, progressIndicator);
});
}
void deactivateProgressIndicator()
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (progressIndicator != null)
{
var currentPage = App.RootFrame.Content as PhoneApplicationPage;
progressIndicator.IsVisible = false;
SystemTray.SetIsVisible(currentPage, false);
}
});
}
public bool isBackgroundWorkerBusy()
{
return backgroundWorker != null ? backgroundWorker.IsBusy : false;
}
}
}
And calling that as below to run the process in background.
private void loadReports()
{
bgWorker = new TestBackgroundWorker(loadReportsFromDB, true, "Loading...", showReports);
bgWorker.Start();
}
Here, loadReprtsFromDB and showReports are two functions.
Questions:
Can anyone suggest how to achieve same thing in Windows 8.1?
Is there any alternative for PhoneApplicationService.Current.State?
IMHO, even for the desktop, the Task<T> and Progress<T> classes offer a nice alternative to BackgroundWorker, and they are both supported on Windows Phone 8.1. The Task<T> class provides the mechanism to start and then cleanly wait for background operations, while the Progress<T> class provides the mechanism for reporting progress (not part of your example or question, but I mention it because that's the one thing Task along with async/await doesn't provide from BackgroundWorker).
Your example could be changed to something like this:
public class TestBackgroundWorker
{
private Task _task;
private CancellationTokenSource _cancelSource;
public CancellationToken CancellationToken
{
get { return _cancelSource != null ? _cancelSource.Token : null; }
}
ProgressIndicator progressIndicator;
public readonly Action<TestBackgroundWorker> currentFunctionToExecute;
private string message;
/// <summary>
///
/// </summary>
/// <param name="functionNameToExecute">specifies function name to be executed in background</param>
/// <param name="isCancellable">Flag which specifies whether the operation is cancellable or not</param>
/// <param name="functionNameWhichGetsResult">Specifies call back function to be executed after the completion of operation</param>
public MCSBackgroundWorker(Action<TestBackgroundWorker> functionNameToExecute, bool isCancellable, string messageToDisplay)
{
currentFunctionToExecute = functionNameToExecute;
_cancelSource = isCancellable ? new CancellationTokenSource() : null;
message = messageToDisplay;
}
public void cancelBackgroundOperation()
{
if (_cancelSource != null)
{
_cancelSource.Cancel();
}
}
public async Task Start()
{
activateProgressIndicator();
_task = Task.Run(() => currentFunctionToExecute(this));
await _task;
_task = null;
deactivateProgressIndicator();
}
void activateProgressIndicator()
{
// In theory, you should not need to use Dispatcher here with async/await.
// But without a complete code example, it's impossible for me to
// say for sure, so I've left it as-is.
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
var currentPage = App.RootFrame.Content as PhoneApplicationPage;
SystemTray.SetIsVisible(currentPage, true);
SystemTray.SetOpacity(currentPage, 0.5);
SystemTray.SetBackgroundColor(currentPage, Colors.White);
SystemTray.SetForegroundColor(currentPage, Colors.Black);
progressIndicator = new ProgressIndicator();
progressIndicator.IsVisible = true;
progressIndicator.IsIndeterminate = true;
progressIndicator.Text = message;
SystemTray.SetProgressIndicator(currentPage, progressIndicator);
});
}
void deactivateProgressIndicator()
{
// Likewise.
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (progressIndicator != null)
{
var currentPage = App.RootFrame.Content as PhoneApplicationPage;
progressIndicator.IsVisible = false;
SystemTray.SetIsVisible(currentPage, false);
}
});
}
public bool isBackgroundWorkerBusy()
{
return _task != null;
}
}
Then you could use it something like this:
private async Task loadReports()
{
bgWorker = new TestBackgroundWorker(loadReportsFromDB, true, "Loading...");
await bgWorker.Start();
showReports();
}
void loadReportsFromDB(TaskBackgroundWorker worker)
{
while (...)
{
if (worker.CancellationToken.IsCancellationRequested)
{
return; // or whatever
}
}
}
To deal with cancellation, the functionNameToExecute delegate would need to be for a method that accepts an instance of TaskBackgroundWorker as a parameter, so that it can retrieve the CancellationToken property value to check for cancellation (similar to the DoWork() event handler…though your code example didn't actually suggest any mechanism by which the actual background operation code would even detect cancellation).
Note that with async/await, your task can also return a value if you like, via the Task<T> type instead of Task. The above example could easily be modified to accommodate that, and that feature of async/await is one of the biggest reasons I prefer it over BackgroundWorker (which has no clean, compiler-supported mechanism for returning results from the background operation).
Caveat: Lacking a complete code example to start with, there is no point for me to try to actually compile and test any of the code. So the above is strictly "browser-authored". It should suffice for the purposes of illustration, but I apologize in advance for any typos that might exist.

Performing work asynchronously in .NET 4

I have legacy code which performs some very long operations on the UI thread.
What I want to do is to show a progress bar with message and run the work on another thread. Unfortunately , for now I don't have access to VS2012 so I can't use the async keyword.
I've written some code which works fine with operations of 0-1 parameters and no return value using Action.
But when I tried adjusting it to support Func I encountered some issues with
invoking the tasks and returning TResult.
Attached is my original code, would appreciate any suggestions. Thanks, Omer
public partial class FreeProgressBarFrm : System.Windows.Forms.Form
{
#region Members
/// <summary>
/// timer for the progress bar.
/// </summary>
private Timer m_Timer = new Timer();
/// <summary>
/// Delegate for the background operation to perform.
/// </summary>
private Action m_backgroundOperation;
/// <summary>
/// Standard operation to show the user while the operation is in progress.
/// </summary>
private static readonly string m_performingUpdatesMessage = IO_Global.GetResourceString("Performing updates, please wait", "Performing updates, please wait", null);
#endregion
#region Constructor
/// <summary>
/// Constructor
/// </summary>
/// <param name="backgroundDelegate"> Delegate for the background operation to perform</param>
/// <param name="operationName">meessage to show the user while the operation is in progress.</param>
public FreeProgressBarFrm(Action backgroundDelegate, string operationName)
{
InitializeComponent();
m_backgroundOperation = backgroundDelegate;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.lblOperation.Text = operationName;
m_Timer.Interval = 1000;
m_Timer.Tick += new EventHandler(m_Timer_Tick);
}
/// <summary>
/// Constructor , for progressbar with defalt user message (performing updates, please wait).
/// </summary>
/// <param name="backgroundDelegate"> Delegate for the background operation to perform</param>
/// <param name="operationName">operation display name</param>
public FreeProgressBarFrm(Action backgroundDelegate): this(backgroundDelegate, m_performingUpdatesMessage)
{
}
#endregion
#region Methods
/// <summary>
/// Call this method to begin backgorund operation while
/// showing the progress bar to the client.
/// </summary>
public void Wait()
{
ShowDialog(ControlsHelper.MainFrm);
}
/// <summary>
/// Advance the progress bar
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void m_Timer_Tick(object sender, EventArgs e)
{
PerformStep();
}
/// <summary>
/// Advance the progress bar
/// </summary>
private void PerformStep()
{
this.progressBar1.PerformStep();
this.lblOperation.Refresh();
if (this.progressBar1.Value == this.progressBar1.Maximum)
{
this.progressBar1.Value = this.progressBar1.Minimum;
}
}
/// <summary>
/// Load the form , start the progress bar and backroud task.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ProgressBarFrm_Load(object sender, EventArgs e)
{
m_Timer.Start();
this.lblOperation.Refresh();
Task task = new Task(m_backgroundOperation);
Task UITask = task.ContinueWith(delegate { OnWorkCompleted(); },
TaskScheduler.FromCurrentSynchronizationContext());
try
{
task.Start();
}
catch (Exception)
{
Close();
throw;
}
}
/// <summary>
/// Called when the work has been completed.
/// </summary>
private void OnWorkCompleted()
{
Close();
}
/// <summary>
/// Close the timer.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ProgressBarFrm_FormClosing(object sender, FormClosingEventArgs e)
{
if (m_Timer != null)
{
m_Timer.Dispose();
m_Timer = null;
}
}
#endregion
}
Here is the way i'm executing some async work,
public static class TaskExecuter
{
private static readonly ThreadLocal<List<BackgroundTask>> TasksToExecute =
new ThreadLocal<List<BackgroundTask>>(() => new List<BackgroundTask>());
public static Action<Exception> ExceptionHandler { get; set; }
public static void ExecuteLater(BackgroundTask task)
{
TasksToExecute.Value.Add(task);
}
public static void Discard()
{
TasksToExecute.Value.Clear();
}
public static void StartExecuting()
{
var value = TasksToExecute.Value;
var copy = value.ToArray();
value.Clear();
if (copy.Length > 0)
{
Task.Factory.StartNew(() =>
{
foreach (var backgroundTask in copy)
ExecuteTask(backgroundTask);
}, TaskCreationOptions.LongRunning)
.ContinueWith(task =>
{
if (ExceptionHandler != null)
ExceptionHandler(task.Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
}
}
public static void ExecuteTask(BackgroundTask task)
{
task.Run();
}
}
Here is the base class
public abstract class BackgroundTask
{
protected readonly Logger Logger = LogManager.GetCurrentClassLogger();
protected virtual void Initialize()
{
}
protected virtual void OnError(Exception e)
{
//do some work
}
public bool? Run()
{
Logger.Info("Started task: {0}", GetType().Name);
Initialize();
try
{
Execute();
TaskExecuter.StartExecuting();
return true;
}
catch (Exception e)
{
Logger.ErrorException("Could not execute task " + GetType().Name, e);
OnError(e);
return false;
}
finally
{
TaskExecuter.Discard();
Logger.Info("Finished task: {0}", GetType().Name);
}
}
public abstract void Execute();
}
Here is the example of using
public class SendEmailTask : BackgroundTask
{
private const string MailServerIp = "yourip";
public string[] To { get; set; }
public string From { get; set; }
public string Template { get; set; }
public object ViewContext { get; set; }
public string[] Attachments { get; set; }
public string Subject { get; set; }
public override void Execute()
{
MailMessage message = new MailMessage();
try
{
MailAddress mailAddress = new MailAddress(From);
message.From = mailAddress;
foreach (string to in To) message.To.Add(to);
message.Subject = Subject;
if (Attachments.ReturnSuccess())
{
foreach (string attachment in Attachments)
message.Attachments.Add(new Attachment(attachment));
}
message.Priority = MailPriority.High;
message.Body = Template;
message.AlternateViews
.Add(AlternateView
.CreateAlternateViewFromString(ViewContext.ToString(), new ContentType("text/html")));
message.IsBodyHtml = true;
new SmtpClient(MailServerIp)
{
Port = 25,
UseDefaultCredentials = true
}.Send(message);
}
catch (Exception e)
{
Logger.FatalException("Error sending email:", e);
}
finally
{
message.Dispose();
}
}
public override string ToString()
{
return string.Format("To: {0}, From: {1}, Template: {2}, ViewContext: {3}, Attachments: {4}, Subject: {5}", To, From, Template, ViewContext, Attachments, Subject);
}
}
Here i've added a changed version for your needs
public static class AsyncExecuter
{
private static readonly ThreadLocal<List<Action>> TasksToExecute =
new ThreadLocal<List<Action>>(() => new List<BackgroundTask>());
public static Action<Exception> ExceptionHandler { get; set; }
public static void ExecuteLater(BackgroundTask task)
{
TasksToExecute.Value.Add(task);
}
public static void Discard()
{
TasksToExecute.Value.Clear();
}
public static void StartExecuting()
{
var value = TasksToExecute.Value;
var copy = value.ToArray();
value.Clear();
if (copy.Length > 0)
{
Task.Factory.StartNew(() =>
{
foreach (var backgroundTask in copy)
ExecuteTask(backgroundTask);
}, TaskCreationOptions.LongRunning)
.ContinueWith(task =>
{
if (ExceptionHandler != null)
ExceptionHandler(task.Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
}
}
public static void ExecuteTask(Action task)
{
task.Invoke();
}
}

Categories