andrew4582

WrappedAsyncOperation

Mar 24th, 2012
248
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.02 KB | None | 0 0
  1. using System;
  2. using System.IO;
  3. using System.Threading;
  4.  
  5. namespace System {
  6.  
  7.     /*See Example at end of class*/
  8.     /// <summary>
  9.     /// A helper class that provides the code needed to wrap an existing
  10.     /// asynchronous operation and return a different implementation of
  11.     /// <see cref="IAsyncResult"/>.
  12.     /// </summary>
  13.     public static class WrappedAsyncOperation {
  14.         /// <summary>
  15.         /// Start an asyncronous operation that wraps a lower-level
  16.         /// async operation.
  17.         /// </summary>
  18.         /// <typeparam name="TWrappingAsyncResult">Type that implements IAsyncResult
  19.         /// that will be returned from this method.</typeparam>
  20.         /// <param name="callback">The user's callback method to be called when
  21.         /// the async operation completes.</param>
  22.         /// <param name="beginOperation">A delegate that invokes the underlying
  23.         /// async operation that we're wrapping.</param>
  24.         /// <param name="wrappingResultCreator">A delegate that takes the inner
  25.         /// async result and returns the wrapping instance of <typeparamref name="TWrappingAsyncResult"/>.
  26.         /// </param>
  27.         /// <returns>The <see cref="IAsyncResult"/>.</returns>
  28.         public static IAsyncResult BeginAsyncOperation<TWrappingAsyncResult>(
  29.             AsyncCallback callback,
  30.             Func<AsyncCallback,IAsyncResult> beginOperation,
  31.             Func<IAsyncResult,TWrappingAsyncResult> wrappingResultCreator = null)
  32.             where TWrappingAsyncResult:class, IAsyncResult {
  33.             // Implmentation here is a little complex, so a few comments are in order.
  34.             // We have our custom AsyncResult object, which needs to be passed to
  35.             // the callback. However, when we call SqlCommand.BeginExecuteReader, what
  36.             // it passes to the callback is it's own IAsyncResult object, not ours.
  37.             // We work around the issue by wrapping the user supplied callback in
  38.             // another lambda function that has access to the DaabAsyncResult we want
  39.             // passed in.
  40.             // HOWEVER, there's a gotcha here. We can't create the DaabAsyncResult instance
  41.             // until we have the inner IAsyncResult object. But we don't get that inner
  42.             // object until BeginExecuteReader completes, so it's too late to pass it in
  43.             // to the new callback. This is why we're using a closure here. The lock is
  44.             // needed to assure we don't call the user callback until after the DaabAsyncResult
  45.             // object has been properly created.
  46.             // And ONE MORE GOTCHA: It's (theoretically) possible that BeginExecuteReader
  47.             // may complete synchronously, and call the callback on the same thread before
  48.             // returning the Async result. In that case, the lock won't help because we're
  49.             // already on the right thread and recursive acquires are fine. So we also check
  50.             // the CompletedSynchronously flag and handle the callback separately.
  51.             if(wrappingResultCreator == null) {
  52.                 wrappingResultCreator = (r) => { return (TWrappingAsyncResult)r; };
  53.             }
  54.             var padlock = new object();
  55.             TWrappingAsyncResult result = null;
  56.             AsyncCallback wrapperCallback = null;
  57.             if(callback != null) {
  58.                 wrapperCallback = ar => {
  59.                     if(!ar.CompletedSynchronously) {
  60.                         lock(padlock) { }
  61.                         callback(result);
  62.                     }
  63.                 };
  64.             }
  65.  
  66.             lock(padlock) {
  67.                 IAsyncResult innerAsyncResult = beginOperation(wrapperCallback);
  68.                 result = wrappingResultCreator(innerAsyncResult);
  69.             }
  70.  
  71.             if(result.CompletedSynchronously && callback != null) {
  72.                 callback(result);
  73.             }
  74.             return result;
  75.         }
  76.     }
  77.  
  78.  
  79. }
  80.  
  81. /*
  82.  Example:
  83. namespace ConsoleApplication1 {
  84.  
  85. class Program {
  86.  
  87.     public readonly static string LINE = "".PadLeft(75,'-');
  88.  
  89.     static void Main(string[] args) {
  90.         string[] urls =
  91.         {
  92.             "http://google.com",
  93.             "http://yahoo.com",
  94.             "http://microsoft.com",
  95.             "http://apple.com",
  96.             "http://jquery.com",
  97.             "http://netflix.com",
  98.         };
  99.            
  100.         Random rnd = new Random(Guid.NewGuid().ToString().GetHashCode());
  101.  
  102.         int rindex = rnd.Next(0,urls.Length - 1);
  103.         string url = urls[rindex];
  104.  
  105.         WrappedAsyncOperationExample(url);
  106.            
  107.         Console.WriteLine(LINE);
  108.         Console.WriteLine("Press any key to exit");
  109.         Console.ReadKey(true);
  110.  
  111.     }
  112.  
  113.     public static void WrappedAsyncOperationExample(string url) {
  114.  
  115.         ManualResetEventSlim reset = new ManualResetEventSlim(false);
  116.         DateTime started = DateTime.Now;
  117.  
  118.         Console.WriteLine("Started...");
  119.         Console.WriteLine(string.Format("url: {0}",url));
  120.  
  121.         var wr = System.Net.WebRequest.Create(url);
  122.  
  123.         WrappedAsyncOperation.BeginAsyncOperation<IAsyncResult>(
  124.         (iresult) => {
  125.  
  126.             try {
  127.                 var resp = wr.EndGetResponse(iresult);
  128.  
  129.                 using(StreamReader sr = new StreamReader(resp.GetResponseStream())) {
  130.                     Console.WriteLine("callback -> Response length:   {0:N0}",sr.ReadToEnd().Length);
  131.                 }
  132.                 reset.Set();
  133.             }
  134.             catch(Exception err) {
  135.                 Console.WriteLine("callback -> ERROR: " + err.Message);
  136.             }
  137.         },
  138.         (callback) => {
  139.  
  140.             Console.WriteLine("beginOperation -> type: {0}",callback.GetType().Name);
  141.  
  142.             return wr.BeginGetResponse(callback,null);
  143.  
  144.         });//,(rr) => {return rr;}
  145.  
  146.         reset.Wait();
  147.  
  148.         Console.WriteLine("Completed");
  149.         TimeSpan duration = DateTime.Now.Subtract(started);
  150.         Console.WriteLine(string.Format("Duration :    {0:N2} Milliseconds",duration.TotalMilliseconds));
  151.  
  152.     }
  153. }
  154. }
  155.      
  156.  */
Advertisement
Add Comment
Please, Sign In to add comment