Asynchronous implementation
I am trying to develop a class that supports calling asynchronus method. This is what I have come up with so far, however, I am not sure if this is the "right way" to do it.
I want only one async method to execute once, it doesn't need to support multiple executions, so I didn't use the class AsyncOperationManager
.
Can someone who knows asynchronous drawing give me some feedback? Am I doing it right?
Any help would be appreciated as I was unable to find any information on the asynchronous call methods.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;
namespace ConsoleApplication1 {
public delegate void WorkerDelegate();
class Program {
static void Main(string[] args) {
String taskId = new Guid().ToString();
AsyncTest test = new AsyncTest();
test.DoSomethingLongAsyncCompleted += new AsyncCompletedEventHandler(test_DoSomethingLongAsyncCompleted);
test.DoSomethingLongProgressChanged += new ProgressChangedEventHandler(test_DoSomethingLongProgressChanged);
test.DoSomethingLongAsync(ItsOver, taskId);
// Cancel after 2 seconds
Thread.Sleep(2000);
test.DoSomethingLongCancelAsync();
Console.ReadLine(); //Pause the console window
}
static void test_DoSomethingLongProgressChanged(object sender, ProgressChangedEventArgs e) {
Console.WriteLine("Percent complete: " + e.ProgressPercentage);
}
static void test_DoSomethingLongAsyncCompleted(object sender, AsyncCompletedEventArgs e) {
Console.WriteLine("Cancelled? " + e.Cancelled);
Console.WriteLine("Task ID: " + (String)e.UserState);
}
static void ItsOver(IAsyncResult r) {
Console.WriteLine("Task ID: " + (String)r.AsyncState);
}
}
class AsyncTest {
IAsyncResult _asyncResult = null;
Object _stateObj = null;
AsyncCallback _callBackDelegate;
public event ProgressChangedEventHandler DoSomethingLongProgressChanged;
public event AsyncCompletedEventHandler DoSomethingLongAsyncCompleted;
public IAsyncResult DoSomethingLongAsync(AsyncCallback userCallback, Object userState) {
if (_stateObj != null)
throw new InvalidOperationException("Method already started");
WorkerDelegate worker = new WorkerDelegate(DoSomethingLong);
_callBackDelegate = userCallback;
_asyncResult = worker.BeginInvoke(null, userState);
return _asyncResult;
}
public void DoSomethingLongCancelAsync() {
_stateObj = null;
}
public void DoSomethingLong() {
// Set state object if method was called synchronously
if (_stateObj == null)
_stateObj = new Object();
for (int i = 0; i < 10; i++) {
//If state object is null, break out of operation
if (_stateObj == null) break;
Thread.Sleep(1000);
Console.WriteLine("Elapsed 1sec");
if (DoSomethingLongProgressChanged != null) {
// Percentage calculation for demo only :-)
DoSomethingLongProgressChanged(this, new ProgressChangedEventArgs(i+1 * 10, _stateObj));
}
}
// Only execute if method was called async
if (_callBackDelegate != null) {
_callBackDelegate(_asyncResult);
DoSomethingLongAsyncCompleted(
this,
new AsyncCompletedEventArgs(null, (_stateObj == null), _asyncResult.AsyncState)
);
}
}
}
}
a source to share
There are two main ways to handle the asynchronous programming model: check out this MSDN article on the asynchronous programming model . You seem to be trying to use the IAsyncResult technique. I usually only use this for low System IO operations.
For the UI or API, I tend to create an event model as it seems to me to be easier to handle. For your case, you can send an event to the QueueUserWorkItem , monitor the SynchronizationContext and use it when the completed event is fired . (If you are using WPF you can use DispatchObject).
Here is the ContactLoader class that I used earlier.
public class ContactLoader
{
public List<Contact> Contacts { get; private set; }
private readonly IRepository<Contact> contactsRepository;
public ContactLoader(IRepository<Contact> contactsRepository)
{
this.contactsRepository = contactsRepository;
}
public event AsyncCompletedEventHandler Completed;
public void OnCompleted(AsyncCompletedEventArgs args)
{
if (Completed != null)
Completed(this, args);
}
public bool Cancel { get; set; }
private SynchronizationContext _loadContext;
public void LoadAsync(AsyncCompletedEventHandler completed)
{
Completed += completed;
LoadAsync();
}
public void LoadAsync()
{
if (_loadContext != null)
throw new InvalidOperationException("This component can only handle 1 async request at a time");
_loadContext = SynchronizationContext.Current;
ThreadPool.QueueUserWorkItem(new WaitCallback(_Load));
}
public void Load()
{
_Load(null);
}
private void _Load(object state)
{
Exception asyncException = null;
try
{
Contacts = contactsRepository.GetAll();
if (Cancel)
{
_Cancel();
return;
}
}
catch (Exception ex)
{
asyncException = ex;
}
if (_loadContext != null)
{
AsyncCompletedEventArgs e = new AsyncCompletedEventArgs(asyncException, false, null);
_loadContext.Post(args =>
{
OnCompleted(args as AsyncCompletedEventArgs);
}, e);
_loadContext = null;
}
else
{
if (asyncException != null) throw asyncException;
}
}
private void _Cancel()
{
if (_loadContext != null)
{
AsyncCompletedEventArgs e = new AsyncCompletedEventArgs(null, true, null);
_loadContext.Post(args =>
{
OnCompleted(args as AsyncCompletedEventArgs);
}, e);
_loadContext = null;
}
}
}
a source to share