THRIFT-1037 Proposed changes to support Silverlight, Windows Phone and AsyncCTP v3
Patch: Damian Mehers & Jens Geyer
git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1211880 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/csharp/src/Transport/THttpClient.cs b/lib/csharp/src/Transport/THttpClient.cs
index bf6ca4d..768b64e 100644
--- a/lib/csharp/src/Transport/THttpClient.cs
+++ b/lib/csharp/src/Transport/THttpClient.cs
@@ -23,6 +23,7 @@
using System.Collections.Generic;
using System.IO;
using System.Net;
+using System.Threading;
namespace Thrift.Transport
{
@@ -119,6 +120,7 @@
outputStream.Write(buf, off, len);
}
+#if !SILVERLIGHT
public override void Flush()
{
try
@@ -153,11 +155,12 @@
throw new TTransportException(TTransportException.ExceptionType.Unknown, "Couldn't connect to server: " + wx);
}
}
-
- private HttpWebRequest CreateRequest()
+#endif
+ private HttpWebRequest CreateRequest()
{
HttpWebRequest connection = (HttpWebRequest)WebRequest.Create(uri);
+#if !SILVERLIGHT
if (connectTimeout > 0)
{
connection.Timeout = connectTimeout;
@@ -166,23 +169,190 @@
{
connection.ReadWriteTimeout = readTimeout;
}
-
+#endif
// Make the request
connection.ContentType = "application/x-thrift";
connection.Accept = "application/x-thrift";
connection.UserAgent = "C#/THttpClient";
connection.Method = "POST";
+#if !SILVERLIGHT
connection.ProtocolVersion = HttpVersion.Version10;
+#endif
- //add custom headers here
+ //add custom headers here
foreach (KeyValuePair<string, string> item in customHeaders)
{
+#if !SILVERLIGHT
connection.Headers.Add(item.Key, item.Value);
+#else
+ connection.Headers[item.Key] = item.Value;
+#endif
}
connection.Proxy = null;
- return connection;
+ return connection;
}
- }
+
+#if SILVERLIGHT
+ public override IAsyncResult BeginFlush(AsyncCallback callback, object state)
+ {
+ // Extract request and reset buffer
+ var data = outputStream.ToArray();
+
+ //requestBuffer_ = new MemoryStream();
+
+ try
+ {
+ // Create connection object
+ var flushAsyncResult = new FlushAsyncResult(callback, state);
+ flushAsyncResult.Connection = CreateRequest();
+
+ flushAsyncResult.Data = data;
+
+
+ flushAsyncResult.Connection.BeginGetRequestStream(GetRequestStreamCallback, flushAsyncResult);
+ return flushAsyncResult;
+
+ }
+ catch (IOException iox)
+ {
+ throw new TTransportException(iox.ToString());
+ }
+ }
+
+ public override void EndFlush(IAsyncResult asyncResult)
+ {
+ try
+ {
+ var flushAsyncResult = (FlushAsyncResult) asyncResult;
+
+ if (!flushAsyncResult.IsCompleted)
+ {
+ var waitHandle = flushAsyncResult.AsyncWaitHandle;
+ waitHandle.WaitOne(); // blocking INFINITEly
+ waitHandle.Close();
+ }
+
+ if (flushAsyncResult.AsyncException != null)
+ {
+ throw flushAsyncResult.AsyncException;
+ }
+ } finally
+ {
+ outputStream = new MemoryStream();
+ }
+
+ }
+
+
+ private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
+ {
+ var flushAsyncResult = (FlushAsyncResult)asynchronousResult.AsyncState;
+ try
+ {
+ var reqStream = flushAsyncResult.Connection.EndGetRequestStream(asynchronousResult);
+ reqStream.Write(flushAsyncResult.Data, 0, flushAsyncResult.Data.Length);
+ reqStream.Flush();
+ reqStream.Close();
+
+ // Start the asynchronous operation to get the response
+ flushAsyncResult.Connection.BeginGetResponse(GetResponseCallback, flushAsyncResult);
+ }
+ catch (Exception exception)
+ {
+ flushAsyncResult.AsyncException = new TTransportException(exception.ToString());
+ flushAsyncResult.UpdateStatusToComplete();
+ flushAsyncResult.NotifyCallbackWhenAvailable();
+ }
+ }
+
+ private void GetResponseCallback(IAsyncResult asynchronousResult)
+ {
+ var flushAsyncResult = (FlushAsyncResult)asynchronousResult.AsyncState;
+ try
+ {
+ inputStream = flushAsyncResult.Connection.EndGetResponse(asynchronousResult).GetResponseStream();
+ }
+ catch (Exception exception)
+ {
+ flushAsyncResult.AsyncException = new TTransportException(exception.ToString());
+ }
+ flushAsyncResult.UpdateStatusToComplete();
+ flushAsyncResult.NotifyCallbackWhenAvailable();
+ }
+
+ // Based on http://msmvps.com/blogs/luisabreu/archive/2009/06/15/multithreading-implementing-the-iasyncresult-interface.aspx
+ class FlushAsyncResult : IAsyncResult
+ {
+ private volatile Boolean _isCompleted;
+ private ManualResetEvent _evt;
+ private readonly AsyncCallback _cbMethod;
+ private readonly Object _state;
+
+ public FlushAsyncResult(AsyncCallback cbMethod, Object state)
+ {
+ _cbMethod = cbMethod;
+ _state = state;
+ }
+
+ internal byte[] Data { get; set; }
+ internal HttpWebRequest Connection { get; set; }
+ internal TTransportException AsyncException { get; set; }
+
+ public object AsyncState
+ {
+ get { return _state; }
+ }
+ public WaitHandle AsyncWaitHandle
+ {
+ get { return GetEvtHandle(); }
+ }
+ public bool CompletedSynchronously
+ {
+ get { return false; }
+ }
+ public bool IsCompleted
+ {
+ get { return _isCompleted; }
+ }
+ private readonly Object _locker = new Object();
+ private ManualResetEvent GetEvtHandle()
+ {
+ lock (_locker)
+ {
+ if (_evt == null)
+ {
+ _evt = new ManualResetEvent(false);
+ }
+ if (_isCompleted)
+ {
+ _evt.Set();
+ }
+ }
+ return _evt;
+ }
+ internal void UpdateStatusToComplete()
+ {
+ _isCompleted = true; //1. set _iscompleted to true
+ lock (_locker)
+ {
+ if (_evt != null)
+ {
+ _evt.Set(); //2. set the event, when it exists
+ }
+ }
+ }
+
+ internal void NotifyCallbackWhenAvailable()
+ {
+ if (_cbMethod != null)
+ {
+ _cbMethod(this);
+ }
+ }
+ }
+
+#endif
+ }
}