Created
March 29, 2011 14:47
-
-
Save prabirshrestha/892474 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // original code from http://tomasp.net/blog/csharp-async.aspx | |
| // converted to C# 2.0 compatible code and modified to support exceptions. | |
| namespace AsyncEnumerator | |
| { | |
| using System; | |
| using System.Collections.Generic; | |
| #if ASYNC_ENUMERATOR_INTERNAL | |
| internal | |
| #else | |
| public | |
| #endif | |
| delegate void Action(); | |
| #if ASYNC_ENUMERATOR_INTERNAL | |
| internal | |
| #else | |
| public | |
| #endif | |
| delegate void ErrorFunc<T>(T obj, Exception ex); | |
| #region Helpers | |
| #if ASYNC_ENUMERATOR_INTERNAL | |
| internal | |
| #else | |
| public | |
| #endif | |
| delegate IAsyncResult Func<TArg1, TArg2, TArg3>(TArg1 buffer, TArg2 offset, TArg3 length, AsyncCallback callback, object state); | |
| #if ASYNC_ENUMERATOR_INTERNAL | |
| internal | |
| #else | |
| public | |
| #endif | |
| delegate TResult Func<TArg1, TResult>(TArg1 arg1); | |
| #if ASYNC_ENUMERATOR_INTERNAL | |
| internal | |
| #else | |
| public | |
| #endif | |
| delegate IAsyncResult Func(AsyncCallback callback, object state); | |
| #endregion | |
| /// <summary> | |
| /// Represents a primitive untyped asynchronous operation. | |
| /// This interface should be used only in asynchronous method declaration. | |
| /// </summary> | |
| #if ASYNC_ENUMERATOR_INTERNAL | |
| internal | |
| #else | |
| public | |
| #endif | |
| interface IAsync | |
| { | |
| void ExecuteStep(Action<Exception> nextAction); | |
| Exception Exception { get; set; } | |
| } | |
| /// <summary> | |
| /// Represents a type with no value - alternative to C# void in | |
| /// situations where void can't be used | |
| /// </summary> | |
| #if ASYNC_ENUMERATOR_INTERNAL | |
| internal | |
| #else | |
| public | |
| #endif | |
| class Unit | |
| { | |
| private Unit() { } | |
| static Unit() | |
| { | |
| Value = new Unit(); | |
| } | |
| public static Unit Value { get; private set; } | |
| } | |
| #if ASYNC_ENUMERATOR_INTERNAL | |
| internal | |
| #else | |
| public | |
| #endif | |
| class Async<T> : IAsync | |
| { | |
| protected T result; | |
| protected bool isCompleted; | |
| protected Exception exception; | |
| Action<ErrorFunc<T>> func; | |
| public Async(Action<ErrorFunc<T>> function) | |
| { | |
| this.func = function; | |
| } | |
| public Async(Func<byte[], int, int> begin, Func<IAsyncResult, T> end, byte[] arg1, int arg2, int arg3, object state) | |
| { | |
| this.func = (cont) => begin(arg1, arg2, arg3, ar => | |
| { | |
| try | |
| { | |
| cont(end(ar), null); | |
| } | |
| catch (Exception ex) | |
| { | |
| cont(default(T), ex); | |
| } | |
| }, state); | |
| } | |
| public Async(Func<byte[], int, int> begin, Action<IAsyncResult> end, byte[] arg1, int arg2, int arg3, object state) | |
| { | |
| this.func = (cont) => begin(arg1, arg2, arg3, ar => | |
| { | |
| try | |
| { | |
| end(ar); | |
| cont(default(T), null); | |
| } | |
| catch (Exception ex) | |
| { | |
| cont(default(T), ex); | |
| } | |
| }, state); | |
| } | |
| public Async(Func begin, Func<IAsyncResult, T> end) | |
| { | |
| this.func = (cont) => begin(ar => | |
| { | |
| try | |
| { | |
| cont(end(ar), null); | |
| } | |
| catch (Exception ex) | |
| { | |
| cont(default(T), ex); | |
| } | |
| }, null); | |
| } | |
| public void ExecuteStep(Action<Exception> nextAction) | |
| { | |
| func((res, ex) => | |
| { | |
| this.result = res; | |
| this.isCompleted = true; | |
| this.exception = ex; | |
| nextAction(ex); | |
| }); | |
| } | |
| public T Result | |
| { | |
| get | |
| { | |
| if (!this.isCompleted) | |
| { | |
| throw new Exception("Operation not completed, did you forgot 'yield return'?"); | |
| } | |
| return result; | |
| } | |
| } | |
| public Exception Exception | |
| { | |
| get | |
| { | |
| //if (!isCompleted) throw new Exception("Operation not completed, did you forgot 'yield return'?"); | |
| return this.exception; | |
| } | |
| set { this.exception = value; } | |
| } | |
| } | |
| #if ASYNC_ENUMERATOR_INTERNAL | |
| internal | |
| #else | |
| public | |
| #endif | |
| static class Async | |
| { | |
| internal static void Run(IEnumerator<IAsync> en, Action<Exception> cont) | |
| { | |
| try | |
| { | |
| if (!en.MoveNext()) | |
| { | |
| cont(null); | |
| return; | |
| } | |
| en.Current.ExecuteStep | |
| (ex => | |
| { | |
| en.Current.Exception = ex; | |
| Run(en, cont); | |
| }); | |
| } | |
| catch (Exception e) | |
| { | |
| cont(e); | |
| return; | |
| } | |
| } | |
| public static void ExecuteAndWait(IEnumerable<IAsync> en) | |
| { | |
| var wh = new System.Threading.ManualResetEvent(false); | |
| Run(en.GetEnumerator(), | |
| e => { wh.Set(); }); | |
| wh.WaitOne(); | |
| } | |
| public static Async<T> FromAsync<T>(Func<byte[], int, int> beginMethod, Func<IAsyncResult, T> endMethod, byte[] arg1, int args2, int args3, object state) | |
| { | |
| return new Async<T>(beginMethod, endMethod, arg1, args2, args3, state); | |
| } | |
| public static Async<Unit> FromAsync(Func<byte[], int, int> beginMethod, Action<IAsyncResult> endMethod, byte[] args1, int args2, int args3, object state) | |
| { | |
| return new Async<Unit>(beginMethod, endMethod, args1, args2, args3, state); | |
| } | |
| public static Async<T> FromAsync<T>(Func begin, Func<IAsyncResult, T> end) | |
| { | |
| return new Async<T>(begin, end); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| namespace FluentHttp | |
| { | |
| using System; | |
| using System.Collections.Generic; | |
| using System.IO; | |
| using System.Net; | |
| using AsyncEnumerator; | |
| internal class HttpWebHelper | |
| { | |
| //public virtual string BuildRequestUrl(string baseUrl, string resourcePath, IEnumerable<Pair<string, string>> queryStrings) | |
| //{ | |
| // var sb = new System.Text.StringBuilder(); | |
| // if (string.IsNullOrEmpty(baseUrl)) | |
| // { | |
| // throw new System.ArgumentNullException("baseUrl"); | |
| // } | |
| // sb.Append(baseUrl); | |
| // sb.Append(AddStartingSlashIfNotPresent(resourcePath)); | |
| // sb.Append("?"); | |
| // if (queryStrings != null) | |
| // { | |
| // foreach (var queryString in queryStrings) | |
| // { | |
| // // note: assume queryString is already url encoded. | |
| // sb.AppendFormat("{0}={1}&", queryString.Name, queryString.Value); | |
| // } | |
| // } | |
| // // remote the last & or ? | |
| // --sb.Length; | |
| // return sb.ToString(); | |
| //} | |
| public virtual IHttpWebRequest CreateHttpWebRequest(string requestUrl, string httpMethod, IEnumerable<Pair<string, string>> requestHeaders, CookieCollection requestCookies) | |
| { | |
| var httpWebRequest = CreateNewHttpWebRequest(requestUrl); | |
| httpWebRequest.Method = httpMethod ?? "GET"; | |
| #if !SILVERLIGHT | |
| if (requestCookies != null) | |
| { | |
| foreach (Cookie requestCookie in requestCookies) | |
| { | |
| httpWebRequest.CookieContainer.Add(requestCookie); | |
| } | |
| } | |
| #endif | |
| #if !WINDOWS_PHONE | |
| if (!httpWebRequest.Method.Equals("GET", StringComparison.OrdinalIgnoreCase)) | |
| { | |
| // set default content-length to 0 if it is not GET. | |
| httpWebRequest.ContentLength = 0; | |
| } | |
| #endif | |
| if (requestHeaders != null) | |
| { | |
| SetHttpWebRequestHeaders(httpWebRequest, requestHeaders); | |
| } | |
| return httpWebRequest; | |
| } | |
| public virtual IEnumerable<IAsync> ExecuteAsync( | |
| IHttpWebRequest httpWebRequest, | |
| Stream requestBody, | |
| Action<ResponseReceivedEventArgs> responseReceivedCallback) | |
| { | |
| if (httpWebRequest == null) | |
| { | |
| throw new ArgumentNullException("httpWebRequest"); | |
| } | |
| // buffer space for the data to be read and written. | |
| byte[] buffer = new byte[4096]; | |
| if (requestBody != null && requestBody.Length != 0) | |
| { | |
| // we have a request body, so write it asynchronously. | |
| #if !WINDOWS_PHONE | |
| httpWebRequest.ContentLength = requestBody.Length; | |
| #endif | |
| // assume content-type and content-lenght is already set. | |
| var request = Async.FromAsync(httpWebRequest.BeginGetRequestStream, httpWebRequest.EndGetRequestStream); | |
| yield return request; | |
| if (request.Exception != null) | |
| { | |
| throw new NotImplementedException(); | |
| } | |
| // while there is data to be read and written. | |
| var requestStream = request.Result; | |
| while (true) | |
| { | |
| // read data asynchronously. | |
| // when the operation completes, if no data could be read then we are done. | |
| var count = Async.FromAsync<int>(requestBody.BeginRead, requestBody.EndRead, buffer, 0, buffer.Length, null); | |
| yield return count; | |
| if (count.Exception != null) | |
| { | |
| throw count.Exception; | |
| } | |
| if (count.Result == 0) | |
| { | |
| break; | |
| } | |
| // write data asynchronously. | |
| var write = Async.FromAsync(requestStream.BeginWrite, requestStream.EndWrite, buffer, 0, count.Result, null); | |
| yield return write; | |
| if (write.Exception != null) | |
| { | |
| throw write.Exception; | |
| } | |
| } | |
| } | |
| // asynchronously get the response from the http server. | |
| var response = Async.FromAsync(httpWebRequest.BeginGetResponse, httpWebRequest.EndGetResponse); | |
| yield return response; | |
| var httpWebResponse = response.Result; | |
| Exception exception = null; | |
| if (response.Exception != null) | |
| { | |
| // exception occurred | |
| WebExceptionWrapper webException = null; | |
| if (response.Exception is WebException) | |
| { | |
| webException = new WebExceptionWrapper((WebException)response.Exception); | |
| } | |
| if (webException != null) | |
| { | |
| exception = webException; | |
| httpWebResponse = webException.GetResponse(); | |
| } | |
| else | |
| { | |
| exception = response.Exception; | |
| } | |
| } | |
| if (exception != null && httpWebResponse == null) | |
| { | |
| // critical error occurred. | |
| // most likely no internet connection or silverlight cross domain policy exception. | |
| throw exception; | |
| } | |
| // we have got the response | |
| Stream responseSaveStream = null; | |
| if (responseReceivedCallback != null) | |
| { | |
| // we have the response headers. | |
| var responseReceived = new ResponseReceivedEventArgs(httpWebResponse); | |
| responseReceivedCallback(responseReceived); | |
| responseSaveStream = responseReceived.ResponseSaveStream; | |
| } | |
| // read response stream | |
| var responseStream = httpWebResponse.GetResponseStream(); | |
| if (responseSaveStream == null) | |
| { | |
| // read the response stream asynchronosuly but don't write. | |
| while (true) | |
| { | |
| var count = Async.FromAsync<int>(responseStream.BeginRead, responseStream.EndRead, buffer, 0, buffer.Length, null); | |
| yield return count; | |
| if (count.Exception != null) | |
| { | |
| throw count.Exception; | |
| } | |
| if (count.Result == 0) | |
| { | |
| break; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| if (!responseSaveStream.CanWrite) | |
| { | |
| throw new ArgumentException("responseSaveStream is not writable."); | |
| } | |
| // while there is data to be read and written. | |
| while (true) | |
| { | |
| // read data asynchronously. | |
| // when the operation completes, if no data could be read then we are done. | |
| var count = Async.FromAsync<int>(responseStream.BeginRead, responseStream.EndRead, buffer, 0, buffer.Length, null); | |
| yield return count; | |
| if (count.Exception != null) | |
| { | |
| throw count.Exception; | |
| } | |
| if (count.Result == 0) | |
| { | |
| break; | |
| } | |
| // write data asynchronously. | |
| var write = Async.FromAsync(responseSaveStream.BeginWrite, responseSaveStream.EndWrite, buffer, 0, count.Result, null); | |
| yield return write; | |
| if (write.Exception != null) | |
| { | |
| throw write.Exception; | |
| } | |
| } | |
| } | |
| } | |
| public virtual void Execute( | |
| IHttpWebRequest httpWebRequest, | |
| Stream requestBody, | |
| Action<ResponseReceivedEventArgs> responseReceivedCallback) | |
| { | |
| Async.ExecuteAndWait(ExecuteAsync(httpWebRequest, requestBody, responseReceivedCallback)); | |
| } | |
| protected virtual IHttpWebRequest CreateNewHttpWebRequest(string requestUrl) | |
| { | |
| if (string.IsNullOrEmpty(requestUrl)) | |
| { | |
| throw new ArgumentException("requestUrl is null or empty", "requestUrl"); | |
| } | |
| return new HttpWebRequestWrapper((HttpWebRequest)WebRequest.Create(requestUrl)); | |
| } | |
| protected virtual void SetHttpWebRequestHeaders(IHttpWebRequest httpWebRequest, IEnumerable<Pair<string, string>> requestHeaders) | |
| { | |
| foreach (var requestHeader in requestHeaders) | |
| { | |
| var name = requestHeader.Name; | |
| var value = requestHeader.Value; | |
| // todo: add more special headers | |
| if (name.Equals("content-type", StringComparison.OrdinalIgnoreCase)) | |
| { | |
| httpWebRequest.ContentType = value; | |
| } | |
| else if (name.Equals("content-length", StringComparison.OrdinalIgnoreCase)) | |
| { | |
| httpWebRequest.ContentLength = Convert.ToInt64(value); | |
| } | |
| else if (name.Equals("user-agent", StringComparison.OrdinalIgnoreCase)) | |
| { | |
| httpWebRequest.UserAgent = value; | |
| } | |
| else | |
| { | |
| httpWebRequest.Headers.Add(name, value); | |
| } | |
| } | |
| } | |
| //internal static IList<Pair<string, string>> ExtractResponseHeaders(WebHeaderCollection headerCollection) | |
| //{ | |
| // var responseHeaders = new List<Pair<string, string>>(); | |
| // for (int i = 0; i < headerCollection.Count; i++) | |
| // { | |
| // responseHeaders.Add(new Pair<string, string>(headerCollection.GetKey(i), headerCollection[i])); | |
| // } | |
| // return responseHeaders; | |
| //} | |
| //public static string AddStartingSlashIfNotPresent(string input) | |
| //{ | |
| // if (string.IsNullOrEmpty(input)) | |
| // { | |
| // return "/"; | |
| // } | |
| // // if not null or empty | |
| // if (input[0] != '/') | |
| // { | |
| // // if doesn't start with / then add / | |
| // return "/" + input; | |
| // } | |
| // else | |
| // { | |
| // // else return the original input. | |
| // return input; | |
| // } | |
| //} | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment