From: Roger Meier Date: Thu, 8 Dec 2011 13:39:56 +0000 (+0000) Subject: THRIFT-1037 Proposed changes to support Silverlight, Windows Phone and AsyncCTP v3 X-Git-Tag: 0.9.1~507 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=284a9b56d73194d8a123f7bf88e2dace9c3cbec0;p=common%2Fthrift.git 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/compiler/cpp/src/generate/t_csharp_generator.cc b/compiler/cpp/src/generate/t_csharp_generator.cc index 93a39f97..9f882e66 100644 --- a/compiler/cpp/src/generate/t_csharp_generator.cc +++ b/compiler/cpp/src/generate/t_csharp_generator.cc @@ -44,8 +44,12 @@ class t_csharp_generator : public t_oop_generator const std::string& option_string) : t_oop_generator(program) { - (void) parsed_options; (void) option_string; + + std::map::const_iterator iter; + iter = parsed_options.find("async"); + async_ctp_ = (iter != parsed_options.end()); + out_dir_base_ = "gen-csharp"; } void init_generator(); @@ -101,6 +105,9 @@ class t_csharp_generator : public t_oop_generator std::string type_name(t_type* ttype, bool in_countainer=false, bool in_init=false); std::string base_type_name(t_base_type* tbase, bool in_container=false); std::string declare_field(t_field* tfield, bool init=false, std::string prefix=""); + std::string function_signature_async_begin(t_function* tfunction, std::string prefix = ""); + std::string function_signature_async_end(t_function* tfunction, std::string prefix = ""); + std::string function_signature_async_ctp(t_function* tfunction, std::string prefix = ""); std::string function_signature(t_function* tfunction, std::string prefix=""); std::string argument_list(t_struct* tstruct); std::string type_to_enum(t_type* ttype); @@ -121,6 +128,7 @@ class t_csharp_generator : public t_oop_generator std::string namespace_name_; std::ofstream f_service_; std::string namespace_dir_; + bool async_ctp_; }; @@ -166,6 +174,7 @@ string t_csharp_generator::csharp_type_usings() { "using System.Collections.Generic;\n" + "using System.Text;\n" + "using System.IO;\n" + + (async_ctp_ ? "using System.Threading.Tasks;\n" : "") + "using Thrift;\n" + "using Thrift.Collections;\n"; } @@ -408,7 +417,9 @@ void t_csharp_generator::generate_csharp_struct_definition(ofstream &out, t_stru } out << endl; - indent(out) << "[Serializable]" << endl; + indent(out) << "#if !SILVERLIGHT" << endl; + indent(out) << "[Serializable]" << endl; + indent(out) << "#endif" << endl; bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); indent(out) << "public " << (is_final ? "sealed " : "") << "partial class " << tstruct->get_name() << " : "; @@ -440,7 +451,9 @@ void t_csharp_generator::generate_csharp_struct_definition(ofstream &out, t_stru out << endl << indent() << "public Isset __isset;" << endl << + indent() << "#if !SILVERLIGHT" << endl << indent() << "[Serializable]" << endl << + indent() << "#endif" << endl << indent() << "public struct Isset {" << endl; indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { @@ -778,6 +791,15 @@ void t_csharp_generator::generate_service_interface(t_service* tservice) { { indent(f_service_) << function_signature(*f_iter) << ";" << endl; + indent(f_service_) << "#if SILVERLIGHT" << endl; + indent(f_service_) << + function_signature_async_begin(*f_iter, "Begin_") << ";" << endl; + indent(f_service_) << + function_signature_async_end(*f_iter, "End_") << ";" << endl; + if( async_ctp_) + indent(f_service_) << + function_signature_async_ctp(*f_iter) << ";" << endl; + indent(f_service_) << "#endif" << endl; } indent_down(); f_service_ << @@ -852,17 +874,104 @@ void t_csharp_generator::generate_service_client(t_service* tservice) { for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string funname = (*f_iter)->get_name(); + indent(f_service_) << endl; + indent(f_service_) << "#if SILVERLIGHT" << endl; + // Begin_ indent(f_service_) << - "public " << function_signature(*f_iter) << endl; + "public " << function_signature_async_begin(*f_iter, "Begin_") << endl; scope_up(f_service_); indent(f_service_) << - "send_" << funname << "("; + "return " << "send_" << funname << "(callback, state"; t_struct* arg_struct = (*f_iter)->get_arglist(); const vector& fields = arg_struct->get_members(); vector::const_iterator fld_iter; - bool first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + f_service_ << ", "; + f_service_ << (*fld_iter)->get_name(); + } + f_service_ << ");" << endl; + scope_down(f_service_); + f_service_ << endl; + + // End + indent(f_service_) << + "public " << function_signature_async_end(*f_iter, "End_") << endl; + scope_up(f_service_); + indent(f_service_) << + "oprot_.Transport.EndFlush(asyncResult);" << endl; + if (!(*f_iter)->is_oneway()) { + f_service_ << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << "return "; + } + f_service_ << + "recv_" << funname << "();" << endl; + } + scope_down(f_service_); + f_service_ << endl; + + // async CTP + bool first; + if( async_ctp_) + { + indent(f_service_) << + "public async " << function_signature_async_ctp(*f_iter, "") << endl; + scope_up(f_service_); + + if (!(*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << + type_name( (*f_iter)->get_returntype()) << " retval;" << endl; + indent(f_service_) << + "retval = "; + } + else + { + indent(f_service_); + } + f_service_ << + "await TaskEx.Run(() =>" << endl; + scope_up(f_service_); + indent(f_service_); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << + "return "; + } + f_service_ << + funname << "("; + first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << (*fld_iter)->get_name(); + } + f_service_ << ");" << endl; + indent_down(); + indent(f_service_) << + "});" << endl; + if (!(*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << + "return retval;" << endl; + } + scope_down(f_service_); + f_service_ << endl; + } + + indent(f_service_) << "#endif" << endl << endl; + + // "Normal" Synchronous invoke + indent(f_service_) << + "public " << function_signature(*f_iter) << endl; + scope_up(f_service_); + indent(f_service_) << "#if !SILVERLIGHT" << endl; + indent(f_service_) << + "send_" << funname << "("; + + first = true; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { if (first) { first = false; @@ -881,17 +990,49 @@ void t_csharp_generator::generate_service_client(t_service* tservice) { f_service_ << "recv_" << funname << "();" << endl; } - scope_down(f_service_); f_service_ << endl; + indent(f_service_) << "#else" << endl; + + // Silverlight synchronous invoke + indent(f_service_) << "var asyncResult = Begin_" << funname << "(null, null, "; + first = true; + for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + f_service_ << (*fld_iter)->get_name(); + } + f_service_ << ");" << endl; + + if (!(*f_iter)->is_oneway()) { + f_service_ << indent(); + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << "return "; + } + f_service_ << + "End_" << funname << "(asyncResult);" << endl; + } + f_service_ << endl; + + + indent(f_service_) << "#endif" << endl; + scope_down(f_service_); + + // Send t_function send_function(g_type_void, string("send_") + (*f_iter)->get_name(), (*f_iter)->get_arglist()); string argsname = (*f_iter)->get_name() + "_args"; - indent(f_service_) << - "public " << function_signature(&send_function) << endl; + indent(f_service_) << "#if SILVERLIGHT" << endl; + indent(f_service_) << "public " << function_signature_async_begin(&send_function) << endl; + indent(f_service_) << "#else" << endl; + indent(f_service_) << "public " << function_signature(&send_function) << endl; + indent(f_service_) << "#endif" << endl; scope_up(f_service_); f_service_ << @@ -905,8 +1046,13 @@ void t_csharp_generator::generate_service_client(t_service* tservice) { f_service_ << indent() << "args.Write(oprot_);" << endl << - indent() << "oprot_.WriteMessageEnd();" << endl << - indent() << "oprot_.Transport.Flush();" << endl; + indent() << "oprot_.WriteMessageEnd();" << endl;; + + indent(f_service_) << "#if SILVERLIGHT" << endl; + indent(f_service_) << "return oprot_.Transport.BeginFlush(callback, state);" << endl; + indent(f_service_) << "#else" << endl; + indent(f_service_) << "oprot_.Transport.Flush();" << endl; + indent(f_service_) << "#endif" << endl; scope_down(f_service_); f_service_ << endl; @@ -1650,6 +1796,24 @@ string t_csharp_generator::function_signature(t_function* tfunction, string pref return type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")"; } +string t_csharp_generator::function_signature_async_begin(t_function* tfunction, string prefix) { + return "IAsyncResult " + prefix + tfunction->get_name() + "(AsyncCallback callback, object state, " + argument_list(tfunction->get_arglist()) + ")"; +} + +string t_csharp_generator::function_signature_async_end(t_function* tfunction, string prefix) { + t_type* ttype = tfunction->get_returntype(); + return type_name(ttype) + " " + prefix + tfunction->get_name() + "(IAsyncResult asyncResult)"; +} + +string t_csharp_generator::function_signature_async_ctp(t_function* tfunction, string prefix) { + t_type* ttype = tfunction->get_returntype(); + string task = "Task"; + if( ! ttype->is_void()) + task += "<" + type_name(ttype) + ">"; + return task + " " + prefix + tfunction->get_name() + "Async(" + argument_list(tfunction->get_arglist()) + ")"; +} + + string t_csharp_generator::argument_list(t_struct* tstruct) { string result = ""; const vector& fields = tstruct->get_members(); @@ -1707,5 +1871,6 @@ string t_csharp_generator::type_to_enum(t_type* type) { } -THRIFT_REGISTER_GENERATOR(csharp, "C#", "") +THRIFT_REGISTER_GENERATOR(csharp, "C#", +" async: add AsyncCTP support.\n") diff --git a/lib/csharp/src/Collections/THashSet.cs b/lib/csharp/src/Collections/THashSet.cs index 0ddea549..e2fc8b52 100644 --- a/lib/csharp/src/Collections/THashSet.cs +++ b/lib/csharp/src/Collections/THashSet.cs @@ -23,11 +23,13 @@ using System.Collections.Generic; namespace Thrift.Collections { +#if !SILVERLIGHT [Serializable] +#endif public class THashSet : ICollection { -#if NET_2_0 - TDictSet set = new TDictSet(); +#if NET_2_0 || SILVERLIGHT + TDictSet set = new TDictSet(); #else HashSet set = new HashSet(); #endif @@ -76,8 +78,8 @@ namespace Thrift.Collections return set.Remove(item); } -#if NET_2_0 - private class TDictSet : ICollection +#if NET_2_0 || SILVERLIGHT + private class TDictSet : ICollection { Dictionary> dict = new Dictionary>(); diff --git a/lib/csharp/src/Properties/AssemblyInfo.WP7.cs b/lib/csharp/src/Properties/AssemblyInfo.WP7.cs new file mode 100644 index 00000000..697d7aa4 --- /dev/null +++ b/lib/csharp/src/Properties/AssemblyInfo.WP7.cs @@ -0,0 +1,56 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Thrift.WP7")] +[assembly: AssemblyDescription("C# bindings for the Apache Thrift RPC system")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("The Apache Software Foundation")] +[assembly: AssemblyProduct("Thrift")] +[assembly: AssemblyCopyright("The Apache Software Foundation")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +//@TODO where to put License information? + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a343f89c-57dd-4fa8-a9c6-35391cd5f655")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.9.0.0")] +[assembly: AssemblyFileVersion("0.9.0.0")] diff --git a/lib/csharp/src/Protocol/TBinaryProtocol.cs b/lib/csharp/src/Protocol/TBinaryProtocol.cs index 4b3980e7..e6b69d65 100644 --- a/lib/csharp/src/Protocol/TBinaryProtocol.cs +++ b/lib/csharp/src/Protocol/TBinaryProtocol.cs @@ -201,7 +201,12 @@ namespace Thrift.Protocol public override void WriteDouble(double d) { +#if !SILVERLIGHT WriteI64(BitConverter.DoubleToInt64Bits(d)); +#else + var bytes = BitConverter.GetBytes(d); + WriteI64(BitConverter.ToInt64(bytes, 0)); +#endif } public override void WriteBinary(byte[] b) @@ -348,7 +353,13 @@ namespace Thrift.Protocol public override double ReadDouble() { +#if !SILVERLIGHT return BitConverter.Int64BitsToDouble(ReadI64()); +#else + var value = ReadI64(); + var bytes = BitConverter.GetBytes(value); + return BitConverter.ToDouble(bytes, 0); +#endif } public void SetReadLength(int readLength) @@ -382,7 +393,7 @@ namespace Thrift.Protocol CheckReadLength(size); byte[] buf = new byte[size]; trans.ReadAll(buf, 0, size); - return Encoding.UTF8.GetString(buf); + return Encoding.UTF8.GetString(buf, 0, buf.Length); } private int ReadAll(byte[] buf, int off, int len) diff --git a/lib/csharp/src/Protocol/TJSONProtocol.cs b/lib/csharp/src/Protocol/TJSONProtocol.cs index a35fcd39..ed6970e9 100644 --- a/lib/csharp/src/Protocol/TJSONProtocol.cs +++ b/lib/csharp/src/Protocol/TJSONProtocol.cs @@ -841,7 +841,7 @@ namespace Thrift.Protocol if (reader.Peek() == QUOTE[0]) { byte[] arr = ReadJSONString(true); - double dub = Double.Parse(utf8Encoding.GetString(arr), CultureInfo.InvariantCulture); + double dub = Double.Parse(utf8Encoding.GetString(arr,0,arr.Length), CultureInfo.InvariantCulture); if (!context.EscapeNumbers() && !Double.IsNaN(dub) && !Double.IsInfinity(dub)) @@ -938,7 +938,8 @@ namespace Thrift.Protocol "Message contained bad version."); } - message.Name = utf8Encoding.GetString(ReadJSONString(false)); + var buf = ReadJSONString(false); + message.Name = utf8Encoding.GetString(buf,0,buf.Length); message.Type = (TMessageType)ReadJSONInteger(); message.SeqID = (int)ReadJSONInteger(); return message; @@ -1059,7 +1060,8 @@ namespace Thrift.Protocol public override String ReadString() { - return utf8Encoding.GetString(ReadJSONString(false)); + var buf = ReadJSONString(false); + return utf8Encoding.GetString(buf,0,buf.Length); } public override byte[] ReadBinary() diff --git a/lib/csharp/src/Protocol/TProtocol.cs b/lib/csharp/src/Protocol/TProtocol.cs index 4f723ddd..b6884c93 100644 --- a/lib/csharp/src/Protocol/TProtocol.cs +++ b/lib/csharp/src/Protocol/TProtocol.cs @@ -84,8 +84,9 @@ namespace Thrift.Protocol public abstract long ReadI64(); public abstract double ReadDouble(); public virtual string ReadString() { - return Encoding.UTF8.GetString(ReadBinary()); - } + var buf = ReadBinary(); + return Encoding.UTF8.GetString(buf, 0, buf.Length); + } public abstract byte[] ReadBinary(); } } diff --git a/lib/csharp/src/Thrift.WP7.csproj b/lib/csharp/src/Thrift.WP7.csproj new file mode 100644 index 00000000..be38bc83 --- /dev/null +++ b/lib/csharp/src/Thrift.WP7.csproj @@ -0,0 +1,110 @@ + + + + + Debug + AnyCPU + 10.0.20506 + 2.0 + {DF58BDB0-2457-4A52-9981-65A0E8B50833} + {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Thrift.WP7 + Thrift.WP7 + v4.0 + $(TargetFrameworkVersion) + WindowsPhone + Silverlight + false + true + true + + + true + full + false + Bin\Debug + DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + pdbonly + true + Bin\Release + TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/csharp/src/Transport/THttpClient.cs b/lib/csharp/src/Transport/THttpClient.cs index bf6ca4d1..768b64e1 100644 --- a/lib/csharp/src/Transport/THttpClient.cs +++ b/lib/csharp/src/Transport/THttpClient.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Net; +using System.Threading; namespace Thrift.Transport { @@ -119,6 +120,7 @@ namespace Thrift.Transport outputStream.Write(buf, off, len); } +#if !SILVERLIGHT public override void Flush() { try @@ -153,11 +155,12 @@ namespace Thrift.Transport 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 @@ namespace Thrift.Transport { 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 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 + } } diff --git a/lib/csharp/src/Transport/TTransport.cs b/lib/csharp/src/Transport/TTransport.cs index cecde872..520ba469 100644 --- a/lib/csharp/src/Transport/TTransport.cs +++ b/lib/csharp/src/Transport/TTransport.cs @@ -71,5 +71,14 @@ namespace Thrift.Transport public virtual void Flush() { } - } + + public virtual IAsyncResult BeginFlush(AsyncCallback callback, object state) + { + return null; + } + + public virtual void EndFlush(IAsyncResult asyncResult) + { + } + } }