Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.IO;
- using System.Threading;
- namespace System {
- /*See Example at end of class*/
- /// <summary>
- /// A helper class that provides the code needed to wrap an existing
- /// asynchronous operation and return a different implementation of
- /// <see cref="IAsyncResult"/>.
- /// </summary>
- public static class WrappedAsyncOperation {
- /// <summary>
- /// Start an asyncronous operation that wraps a lower-level
- /// async operation.
- /// </summary>
- /// <typeparam name="TWrappingAsyncResult">Type that implements IAsyncResult
- /// that will be returned from this method.</typeparam>
- /// <param name="callback">The user's callback method to be called when
- /// the async operation completes.</param>
- /// <param name="beginOperation">A delegate that invokes the underlying
- /// async operation that we're wrapping.</param>
- /// <param name="wrappingResultCreator">A delegate that takes the inner
- /// async result and returns the wrapping instance of <typeparamref name="TWrappingAsyncResult"/>.
- /// </param>
- /// <returns>The <see cref="IAsyncResult"/>.</returns>
- public static IAsyncResult BeginAsyncOperation<TWrappingAsyncResult>(
- AsyncCallback callback,
- Func<AsyncCallback,IAsyncResult> beginOperation,
- Func<IAsyncResult,TWrappingAsyncResult> wrappingResultCreator = null)
- where TWrappingAsyncResult:class, IAsyncResult {
- // Implmentation here is a little complex, so a few comments are in order.
- // We have our custom AsyncResult object, which needs to be passed to
- // the callback. However, when we call SqlCommand.BeginExecuteReader, what
- // it passes to the callback is it's own IAsyncResult object, not ours.
- // We work around the issue by wrapping the user supplied callback in
- // another lambda function that has access to the DaabAsyncResult we want
- // passed in.
- // HOWEVER, there's a gotcha here. We can't create the DaabAsyncResult instance
- // until we have the inner IAsyncResult object. But we don't get that inner
- // object until BeginExecuteReader completes, so it's too late to pass it in
- // to the new callback. This is why we're using a closure here. The lock is
- // needed to assure we don't call the user callback until after the DaabAsyncResult
- // object has been properly created.
- // And ONE MORE GOTCHA: It's (theoretically) possible that BeginExecuteReader
- // may complete synchronously, and call the callback on the same thread before
- // returning the Async result. In that case, the lock won't help because we're
- // already on the right thread and recursive acquires are fine. So we also check
- // the CompletedSynchronously flag and handle the callback separately.
- if(wrappingResultCreator == null) {
- wrappingResultCreator = (r) => { return (TWrappingAsyncResult)r; };
- }
- var padlock = new object();
- TWrappingAsyncResult result = null;
- AsyncCallback wrapperCallback = null;
- if(callback != null) {
- wrapperCallback = ar => {
- if(!ar.CompletedSynchronously) {
- lock(padlock) { }
- callback(result);
- }
- };
- }
- lock(padlock) {
- IAsyncResult innerAsyncResult = beginOperation(wrapperCallback);
- result = wrappingResultCreator(innerAsyncResult);
- }
- if(result.CompletedSynchronously && callback != null) {
- callback(result);
- }
- return result;
- }
- }
- }
- /*
- Example:
- namespace ConsoleApplication1 {
- class Program {
- public readonly static string LINE = "".PadLeft(75,'-');
- static void Main(string[] args) {
- string[] urls =
- {
- "http://google.com",
- "http://yahoo.com",
- "http://microsoft.com",
- "http://apple.com",
- "http://jquery.com",
- "http://netflix.com",
- };
- Random rnd = new Random(Guid.NewGuid().ToString().GetHashCode());
- int rindex = rnd.Next(0,urls.Length - 1);
- string url = urls[rindex];
- WrappedAsyncOperationExample(url);
- Console.WriteLine(LINE);
- Console.WriteLine("Press any key to exit");
- Console.ReadKey(true);
- }
- public static void WrappedAsyncOperationExample(string url) {
- ManualResetEventSlim reset = new ManualResetEventSlim(false);
- DateTime started = DateTime.Now;
- Console.WriteLine("Started...");
- Console.WriteLine(string.Format("url: {0}",url));
- var wr = System.Net.WebRequest.Create(url);
- WrappedAsyncOperation.BeginAsyncOperation<IAsyncResult>(
- (iresult) => {
- try {
- var resp = wr.EndGetResponse(iresult);
- using(StreamReader sr = new StreamReader(resp.GetResponseStream())) {
- Console.WriteLine("callback -> Response length: {0:N0}",sr.ReadToEnd().Length);
- }
- reset.Set();
- }
- catch(Exception err) {
- Console.WriteLine("callback -> ERROR: " + err.Message);
- }
- },
- (callback) => {
- Console.WriteLine("beginOperation -> type: {0}",callback.GetType().Name);
- return wr.BeginGetResponse(callback,null);
- });//,(rr) => {return rr;}
- reset.Wait();
- Console.WriteLine("Completed");
- TimeSpan duration = DateTime.Now.Subtract(started);
- Console.WriteLine(string.Format("Duration : {0:N2} Milliseconds",duration.TotalMilliseconds));
- }
- }
- }
- */
Advertisement
Add Comment
Please, Sign In to add comment