|
using System;
using System.Diagnostics;
using System.Threading;
namespace ESB.ExceptionHandling.ServiceModel.Async
{
/// <summary>
/// A generic base class for IAsyncResult implementations
/// that wraps a ManualResetEvent.
/// </summary>
internal abstract class AsyncResult : IAsyncResult
{
#region Private Fields
private object _state;
private ManualResetEvent _manualResetEvent;
private AsyncCallback _callback;
private Exception _exception;
private bool _completedSynchronously;
private bool _endCalled;
private bool _isCompleted;
private object _lock;
#endregion
#region Public Constructors
protected AsyncResult(AsyncCallback callback, object state)
{
_callback = callback;
_state = state;
_lock = new object();
}
#endregion
#region Public Properties
public object AsyncState { get { return _state; } }
public bool CompletedSynchronously { get { return _completedSynchronously; } }
public bool IsCompleted { get { return _isCompleted; } }
object Lock { get { return _lock; } }
public WaitHandle AsyncWaitHandle
{
get
{
if (_manualResetEvent != null)
{
return _manualResetEvent;
}
lock (_lock)
{
if (_manualResetEvent == null)
{
_manualResetEvent = new ManualResetEvent(_isCompleted);
}
}
return _manualResetEvent;
}
}
#endregion
#region Protected Methods
// Call this version of complete when your asynchronous operation is complete. This will update the state
// of the operation and notify the _callback.
protected void Complete(bool completedSynchronously)
{
if (_isCompleted)
{
// It's a bug to call Complete twice.
throw new InvalidOperationException("Cannot call Complete twice");
}
completedSynchronously = _completedSynchronously;
if (completedSynchronously)
{
// If we completedSynchronously, then there's no chance that the _manualResetEvent was created so
// we don't need to worry about a race
Debug.Assert(_manualResetEvent == null, "No ManualResetEvent should be created for a synchronous AsyncResult.");
_isCompleted = true;
}
else
{
lock (_lock)
{
_isCompleted = true;
if (_manualResetEvent != null)
{
_manualResetEvent.Set();
}
}
}
// If the _callback throws, there is a bug in the _callback implementation
if (_callback != null)
{
_callback(this);
}
}
// Call this version of complete if you raise an exception during processing. In addition to notifying
// the _callback, it will capture the exception and store it to be thrown during AsyncResult.End.
protected void Complete(bool completedSynchronously, Exception exception)
{
exception = _exception;
Complete(completedSynchronously);
}
// End should be called when the End function for the asynchronous operation is complete. It
// ensures the asynchronous operation is complete, and does some common validation.
protected static TAsyncResult End<TAsyncResult>(IAsyncResult result)
where TAsyncResult : AsyncResult
{
if (result == null)
{
throw new ArgumentNullException("result");
}
TAsyncResult asyncResult = result as TAsyncResult;
if (asyncResult == null)
{
throw new ArgumentException("Invalid async result.", "result");
}
if (asyncResult._endCalled)
{
throw new InvalidOperationException("Async object already ended.");
}
asyncResult._endCalled = true;
if (!asyncResult._isCompleted)
{
asyncResult.AsyncWaitHandle.WaitOne();
}
if (asyncResult._manualResetEvent != null)
{
asyncResult._manualResetEvent.Close();
}
if (asyncResult._exception != null)
{
throw asyncResult._exception;
}
return asyncResult;
}
protected static void End(AsyncResult asyncResult)
{
if (asyncResult == null)
{
throw new ArgumentNullException("asyncResult");
}
if (asyncResult._endCalled)
{
throw new InvalidOperationException("Async object already ended.");
}
asyncResult._endCalled = true;
if (!asyncResult._isCompleted)
{
using (WaitHandle waitHandle = asyncResult.AsyncWaitHandle)
{
waitHandle.WaitOne();
}
}
if (asyncResult._exception != null)
{
throw asyncResult._exception;
}
}
#endregion
#region Private Methods
private void RaiseUnhandledException(object o)
{
Exception exception = (Exception)o;
throw exception;
}
#endregion
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I have almost 20 years commercial software development using a number of languages from C++ to C#/VB. My main focus has been in the Microsoft space and, since the early 2000's, most of this has been in the web or integration arena. Over the past few years I have been focusing on building business solutions using a variety of products such as BizTalk and Share Point.
In terms of SDLC's, I have experience with various methodologies such as Agile, RUP, Iterative and Waterfall.
Lastly, the roles I have had in the last few years have given me the opportunity to gain a lot of experience as a consultant. Since, over the last 18 years, I have worked with many customers this has further given me the chance to enjoy many and varying challenges that have helped me grow in my career.
Today, I spend a lot of time talking, designing, documenting and mentoring team members. I also spend quite a bit of time authoring software and find the combination a perfect fit for me.
Specialties
Consultancy, Solution architecture, Solution design, Project costing and tracking, Team lead, Software development, C#, VB, ASP.NET, HTML, DHTML, JavaScript, BizTalk, SharePoint