Revert "THRIFT-4982 Remove deprecated C# bindings from the code base"

Only compiler, test, lib and tutorial code.
diff --git a/.gitignore b/.gitignore
index d11897e..eacff5b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -184,6 +184,9 @@
 /lib/c_glib/test/testserialization
 /lib/c_glib/thriftc.pc
 /lib/c_glib/thrift_c_glib.pc
+/lib/csharp/**/bin/
+/lib/csharp/**/obj/
+/lib/csharp/src/packages
 /lib/d/test/*.pem
 /lib/d/libthriftd*.a
 /lib/d/test/async_test
@@ -231,6 +234,8 @@
 /lib/js/dist
 /lib/js/doc
 /lib/js/test/build
+/lib/netcore/**/bin
+/lib/netcore/**/obj
 /lib/netstd/**/bin
 /lib/netstd/**/obj
 /lib/nodejs/coverage
@@ -323,6 +328,8 @@
 /test/cpp/StressTestNonBlocking
 /test/cpp/TestClient
 /test/cpp/TestServer
+/test/csharp/obj
+/test/csharp/bin
 /test/dart/**/.dart_tool
 /test/dart/**/.packages
 /test/dart/**/packages
@@ -351,6 +358,9 @@
 /test/php/php_ext_dir/
 /test/py.twisted/_trial_temp/
 /test/rb/Gemfile.lock
+/test/netcore/**/bin
+/test/netcore/**/obj
+/test/netcore/Thrift
 /test/netstd/**/bin
 /test/netstd/**/obj
 /test/netstd/**/launchSettings.json
@@ -383,6 +393,10 @@
 /tutorial/cpp/TutorialServer
 /tutorial/c_glib/tutorial_client
 /tutorial/c_glib/tutorial_server
+/tutorial/csharp/CsharpServer/obj
+/tutorial/csharp/CsharpServer/bin
+/tutorial/csharp/CsharpClient/obj
+/tutorial/csharp/CsharpClient/bin
 /tutorial/d/async_client
 /tutorial/d/client
 /tutorial/d/server
@@ -407,6 +421,9 @@
 /tutorial/hs/dist/
 /tutorial/java/build/
 /tutorial/js/build/
+/tutorial/netcore/**/bin
+/tutorial/netcore/**/obj
+/tutorial/netcore/Thrift
 /tutorial/netstd/**/bin
 /tutorial/netstd/**/obj
 /tutorial/netstd/Interfaces
diff --git a/compiler/cpp/CMakeLists.txt b/compiler/cpp/CMakeLists.txt
index 0675f0e..0d80f79 100644
--- a/compiler/cpp/CMakeLists.txt
+++ b/compiler/cpp/CMakeLists.txt
@@ -76,6 +76,7 @@
 THRIFT_ADD_COMPILER(c_glib  "Enable compiler for C with Glib" ON)
 THRIFT_ADD_COMPILER(cl      "Enable compiler for Common LISP" ON)
 THRIFT_ADD_COMPILER(cpp     "Enable compiler for C++" ON)
+THRIFT_ADD_COMPILER(csharp  "Enable compiler for C#" ON)
 THRIFT_ADD_COMPILER(d       "Enable compiler for D" ON)
 THRIFT_ADD_COMPILER(dart    "Enable compiler for Dart" ON)
 THRIFT_ADD_COMPILER(delphi  "Enable compiler for Delphi" ON)
diff --git a/compiler/cpp/Makefile.am b/compiler/cpp/Makefile.am
index 05c9121..2f962fe 100644
--- a/compiler/cpp/Makefile.am
+++ b/compiler/cpp/Makefile.am
@@ -73,6 +73,7 @@
                   src/thrift/generate/t_c_glib_generator.cc \
                   src/thrift/generate/t_cl_generator.cc \
                   src/thrift/generate/t_cpp_generator.cc \
+                  src/thrift/generate/t_csharp_generator.cc \
                   src/thrift/generate/t_d_generator.cc \
                   src/thrift/generate/t_dart_generator.cc \
                   src/thrift/generate/t_delphi_generator.cc \
diff --git a/compiler/cpp/compiler.vcxproj b/compiler/cpp/compiler.vcxproj
index dc9793f..cbcf8ea 100644
--- a/compiler/cpp/compiler.vcxproj
+++ b/compiler/cpp/compiler.vcxproj
@@ -57,6 +57,7 @@
     <ClCompile Include="src\thrift\generate\t_c_glib_generator.cc" />
     <ClCompile Include="src\thrift\generate\t_cl_generator.cc" />
     <ClCompile Include="src\thrift\generate\t_cpp_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_csharp_generator.cc" />
     <ClCompile Include="src\thrift\generate\t_d_generator.cc" />
     <ClCompile Include="src\thrift\generate\t_dart_generator.cc" />
     <ClCompile Include="src\thrift\generate\t_delphi_generator.cc" />
diff --git a/compiler/cpp/compiler.vcxproj.filters b/compiler/cpp/compiler.vcxproj.filters
index 360c446..fcb3230 100644
--- a/compiler/cpp/compiler.vcxproj.filters
+++ b/compiler/cpp/compiler.vcxproj.filters
@@ -101,6 +101,9 @@
     <ClCompile Include="src\generate\t_cpp_generator.cc">
       <Filter>generate</Filter>
     </ClCompile>
+    <ClCompile Include="src\generate\t_csharp_generator.cc">
+      <Filter>generate</Filter>
+    </ClCompile>
     <ClCompile Include="src\generate\t_c_glib_generator.cc">
       <Filter>generate</Filter>
     </ClCompile>
diff --git a/compiler/cpp/src/thrift/generate/t_csharp_generator.cc b/compiler/cpp/src/thrift/generate/t_csharp_generator.cc
new file mode 100644
index 0000000..e4d99b2
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_csharp_generator.cc
@@ -0,0 +1,3259 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+#include <cassert>
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <cctype>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+struct member_mapping_scope {
+  void* scope_member;
+  std::map<std::string, std::string> mapping_table;
+};
+
+class t_csharp_generator : public t_oop_generator {
+public:
+  t_csharp_generator(t_program* program,
+                     const std::map<std::string, std::string>& parsed_options,
+                     const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+
+    std::map<std::string, std::string>::const_iterator iter;
+
+    async_ = false;
+    nullable_ = false;
+    hashcode_ = false;
+    union_ = false;
+    serialize_ = false;
+    wcf_ = false;
+    wcf_namespace_.clear();
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("async") == 0) {
+        async_ = true;
+      } else if( iter->first.compare("nullable") == 0) {
+        nullable_ = true;
+      } else if( iter->first.compare("hashcode") == 0) {
+        hashcode_ = true;
+      } else if( iter->first.compare("union") == 0) {
+        union_ = true;
+      } else if( iter->first.compare("serial") == 0) {
+        serialize_ = true;
+        wcf_namespace_ = iter->second; // since there can be only one namespace
+      } else if( iter->first.compare("wcf") == 0) {
+        wcf_ = true;
+        wcf_namespace_ = iter->second;
+      } else {
+        throw "unknown option csharp:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-csharp";
+  }
+  void init_generator() override;
+  void close_generator() override;
+
+  void generate_consts(std::vector<t_const*> consts) override;
+
+  void generate_typedef(t_typedef* ttypedef) override;
+  void generate_enum(t_enum* tenum) override;
+  void generate_struct(t_struct* tstruct) override;
+  void generate_union(t_struct* tunion);
+  void generate_xception(t_struct* txception) override;
+  void generate_service(t_service* tservice) override;
+  void generate_property(ostream& out, t_field* tfield, bool isPublic, bool generateIsset);
+  void generate_csharp_property(ostream& out,
+                                t_field* tfield,
+                                bool isPublic,
+                                bool includeIsset = true,
+                                std::string fieldPrefix = "");
+  bool print_const_value(std::ostream& out,
+                         std::string name,
+                         t_type* type,
+                         t_const_value* value,
+                         bool in_static,
+                         bool defval = false,
+                         bool needtype = false);
+  std::string render_const_value(std::ostream& out,
+                                 std::string name,
+                                 t_type* type,
+                                 t_const_value* value);
+  void print_const_constructor(std::ostream& out, std::vector<t_const*> consts);
+  void print_const_def_value(std::ostream& out,
+                             std::string name,
+                             t_type* type,
+                             t_const_value* value);
+
+  void generate_csharp_struct(t_struct* tstruct, bool is_exception);
+  void generate_csharp_union(t_struct* tunion);
+  void generate_csharp_struct_definition(std::ostream& out,
+                                         t_struct* tstruct,
+                                         bool is_xception = false,
+                                         bool in_class = false,
+                                         bool is_result = false);
+  void generate_csharp_union_definition(std::ostream& out, t_struct* tunion);
+  void generate_csharp_union_class(std::ostream& out, t_struct* tunion, t_field* tfield);
+  void generate_csharp_wcffault(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_struct_result_writer(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_struct_tostring(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_struct_equals(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_struct_hashcode(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_union_reader(std::ostream& out, t_struct* tunion);
+
+  void generate_function_helpers(t_function* tfunction);
+  void generate_service_interface(t_service* tservice);
+  void generate_separate_service_interfaces(t_service* tservice);
+  void generate_sync_service_interface(t_service* tservice);
+  void generate_async_service_interface(t_service* tservice);
+  void generate_combined_service_interface(t_service* tservice);
+  void generate_silverlight_async_methods(t_service* tservice);
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_client(t_service* tservice);
+  void generate_service_server(t_service* tservice);
+  void generate_service_server_sync(t_service* tservice);
+  void generate_service_server_async(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* function);
+  void generate_process_function_async(t_service* tservice, t_function* function);
+
+  void generate_deserialize_field(std::ostream& out,
+                                  t_field* tfield,
+                                  std::string prefix = "",
+                                  bool is_propertyless = false);
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+  void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+  void generate_deserialize_list_element(std::ostream& out, t_list* list, std::string prefix = "");
+  void generate_serialize_field(std::ostream& out,
+                                t_field* tfield,
+                                std::string prefix = "",
+                                bool is_element = false,
+                                bool is_propertyless = false);
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string iter,
+                                      std::string map);
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  void generate_csharp_doc(std::ostream& out, t_field* field);
+  void generate_csharp_doc(std::ostream& out, t_doc* tdoc);
+  void generate_csharp_doc(std::ostream& out, t_function* tdoc);
+  void generate_csharp_docstring_comment(std::ostream& out, string contents);
+
+  void start_csharp_namespace(std::ostream& out);
+  void end_csharp_namespace(std::ostream& out);
+
+  std::string csharp_type_usings();
+  std::string csharp_thrift_usings();
+
+  std::string type_name(t_type* ttype,
+                        bool in_countainer = false,
+                        bool in_init = false,
+                        bool in_param = false,
+                        bool is_required = false);
+  std::string base_type_name(t_base_type* tbase,
+                             bool in_container = false,
+                             bool in_param = false,
+                             bool is_required = 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(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);
+  std::string prop_name(t_field* tfield, bool suppress_mapping = false);
+  std::string get_enum_class_name(t_type* type) override;
+
+  bool field_has_default(t_field* tfield) { return tfield->get_value() != NULL; }
+
+  bool field_is_required(t_field* tfield) { return tfield->get_req() == t_field::T_REQUIRED; }
+
+  bool type_can_be_null(t_type* ttype) {
+    while (ttype->is_typedef()) {
+      ttype = ((t_typedef*)ttype)->get_type();
+    }
+
+    return ttype->is_container() || ttype->is_struct() || ttype->is_xception()
+           || ttype->is_string();
+  }
+
+private:
+  std::string namespace_name_;
+  ofstream_with_content_based_conditional_update f_service_;
+  std::string namespace_dir_;
+  bool async_;
+  bool nullable_;
+  bool union_;
+  bool hashcode_;
+  bool serialize_;
+  bool wcf_;
+  std::string wcf_namespace_;
+
+  std::map<std::string, int> csharp_keywords;
+  std::vector<member_mapping_scope>  member_mapping_scopes;
+
+  void init_keywords();
+  std::string normalize_name(std::string name);
+  std::string make_valid_csharp_identifier(std::string const& fromName);
+  void prepare_member_name_mapping(t_struct* tstruct);
+  void prepare_member_name_mapping(void* scope,
+                                   const vector<t_field*>& members,
+                                   const string& structname);
+  void cleanup_member_name_mapping(void* scope);
+  string get_mapped_member_name(string oldname);
+};
+
+void t_csharp_generator::init_generator() {
+  MKDIR(get_out_dir().c_str());
+  namespace_name_ = program_->get_namespace("csharp");
+
+  string dir = namespace_name_;
+  string subdir = get_out_dir().c_str();
+  string::size_type loc;
+
+  while ((loc = dir.find(".")) != string::npos) {
+    subdir = subdir + "/" + dir.substr(0, loc);
+    MKDIR(subdir.c_str());
+    dir = dir.substr(loc + 1);
+  }
+  if (dir.size() > 0) {
+    subdir = subdir + "/" + dir;
+    MKDIR(subdir.c_str());
+  }
+
+  namespace_dir_ = subdir;
+  init_keywords();
+
+  while( ! member_mapping_scopes.empty()) {
+    cleanup_member_name_mapping( member_mapping_scopes.back().scope_member);
+  }
+
+  pverbose("C# options:\n");
+  pverbose("- async ...... %s\n", (async_ ? "ON" : "off"));
+  pverbose("- nullable ... %s\n", (nullable_ ? "ON" : "off"));
+  pverbose("- union ...... %s\n", (union_ ? "ON" : "off"));
+  pverbose("- hashcode ... %s\n", (hashcode_ ? "ON" : "off"));
+  pverbose("- serialize .. %s\n", (serialize_ ? "ON" : "off"));
+  pverbose("- wcf ........ %s\n", (wcf_ ? "ON" : "off"));
+}
+
+std::string t_csharp_generator::normalize_name(std::string name) {
+  string tmp(name);
+  std::transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast<int (*)(int)>(std::tolower));
+
+  // un-conflict keywords by prefixing with "@"
+  if (csharp_keywords.find(tmp) != csharp_keywords.end()) {
+    return "@" + name;
+  }
+
+  // no changes necessary
+  return name;
+}
+
+void t_csharp_generator::init_keywords() {
+  csharp_keywords.clear();
+
+  // C# keywords
+  csharp_keywords["abstract"] = 1;
+  csharp_keywords["as"] = 1;
+  csharp_keywords["base"] = 1;
+  csharp_keywords["bool"] = 1;
+  csharp_keywords["break"] = 1;
+  csharp_keywords["byte"] = 1;
+  csharp_keywords["case"] = 1;
+  csharp_keywords["catch"] = 1;
+  csharp_keywords["char"] = 1;
+  csharp_keywords["checked"] = 1;
+  csharp_keywords["class"] = 1;
+  csharp_keywords["const"] = 1;
+  csharp_keywords["continue"] = 1;
+  csharp_keywords["decimal"] = 1;
+  csharp_keywords["default"] = 1;
+  csharp_keywords["delegate"] = 1;
+  csharp_keywords["do"] = 1;
+  csharp_keywords["double"] = 1;
+  csharp_keywords["else"] = 1;
+  csharp_keywords["enum"] = 1;
+  csharp_keywords["event"] = 1;
+  csharp_keywords["explicit"] = 1;
+  csharp_keywords["extern"] = 1;
+  csharp_keywords["false"] = 1;
+  csharp_keywords["finally"] = 1;
+  csharp_keywords["fixed"] = 1;
+  csharp_keywords["float"] = 1;
+  csharp_keywords["for"] = 1;
+  csharp_keywords["foreach"] = 1;
+  csharp_keywords["goto"] = 1;
+  csharp_keywords["if"] = 1;
+  csharp_keywords["implicit"] = 1;
+  csharp_keywords["in"] = 1;
+  csharp_keywords["int"] = 1;
+  csharp_keywords["interface"] = 1;
+  csharp_keywords["internal"] = 1;
+  csharp_keywords["is"] = 1;
+  csharp_keywords["lock"] = 1;
+  csharp_keywords["long"] = 1;
+  csharp_keywords["namespace"] = 1;
+  csharp_keywords["new"] = 1;
+  csharp_keywords["null"] = 1;
+  csharp_keywords["object"] = 1;
+  csharp_keywords["operator"] = 1;
+  csharp_keywords["out"] = 1;
+  csharp_keywords["override"] = 1;
+  csharp_keywords["params"] = 1;
+  csharp_keywords["private"] = 1;
+  csharp_keywords["protected"] = 1;
+  csharp_keywords["public"] = 1;
+  csharp_keywords["readonly"] = 1;
+  csharp_keywords["ref"] = 1;
+  csharp_keywords["return"] = 1;
+  csharp_keywords["sbyte"] = 1;
+  csharp_keywords["sealed"] = 1;
+  csharp_keywords["short"] = 1;
+  csharp_keywords["sizeof"] = 1;
+  csharp_keywords["stackalloc"] = 1;
+  csharp_keywords["static"] = 1;
+  csharp_keywords["string"] = 1;
+  csharp_keywords["struct"] = 1;
+  csharp_keywords["switch"] = 1;
+  csharp_keywords["this"] = 1;
+  csharp_keywords["throw"] = 1;
+  csharp_keywords["true"] = 1;
+  csharp_keywords["try"] = 1;
+  csharp_keywords["typeof"] = 1;
+  csharp_keywords["uint"] = 1;
+  csharp_keywords["ulong"] = 1;
+  csharp_keywords["unchecked"] = 1;
+  csharp_keywords["unsafe"] = 1;
+  csharp_keywords["ushort"] = 1;
+  csharp_keywords["using"] = 1;
+  csharp_keywords["virtual"] = 1;
+  csharp_keywords["void"] = 1;
+  csharp_keywords["volatile"] = 1;
+  csharp_keywords["while"] = 1;
+
+  // C# contextual keywords
+  csharp_keywords["add"] = 1;
+  csharp_keywords["alias"] = 1;
+  csharp_keywords["ascending"] = 1;
+  csharp_keywords["async"] = 1;
+  csharp_keywords["await"] = 1;
+  csharp_keywords["descending"] = 1;
+  csharp_keywords["dynamic"] = 1;
+  csharp_keywords["from"] = 1;
+  csharp_keywords["get"] = 1;
+  csharp_keywords["global"] = 1;
+  csharp_keywords["group"] = 1;
+  csharp_keywords["into"] = 1;
+  csharp_keywords["join"] = 1;
+  csharp_keywords["let"] = 1;
+  csharp_keywords["orderby"] = 1;
+  csharp_keywords["partial"] = 1;
+  csharp_keywords["remove"] = 1;
+  csharp_keywords["select"] = 1;
+  csharp_keywords["set"] = 1;
+  csharp_keywords["value"] = 1;
+  csharp_keywords["var"] = 1;
+  csharp_keywords["where"] = 1;
+  csharp_keywords["yield"] = 1;
+}
+
+void t_csharp_generator::start_csharp_namespace(ostream& out) {
+  if (!namespace_name_.empty()) {
+    out << "namespace " << namespace_name_ << "\n";
+    scope_up(out);
+  }
+}
+
+void t_csharp_generator::end_csharp_namespace(ostream& out) {
+  if (!namespace_name_.empty()) {
+    scope_down(out);
+  }
+}
+
+string t_csharp_generator::csharp_type_usings() {
+  return string() + "using System;\n" + "using System.Collections;\n"
+         + "using System.Collections.Generic;\n" + "using System.Text;\n" + "using System.IO;\n"
+         + ((async_) ? "using System.Threading.Tasks;\n" : "") + "using Thrift;\n"
+         + "using Thrift.Collections;\n" + ((serialize_ || wcf_) ? "#if !SILVERLIGHT\n" : "")
+         + ((serialize_ || wcf_) ? "using System.Xml.Serialization;\n" : "")
+         + ((serialize_ || wcf_) ? "#endif\n" : "")
+         + "using System.Runtime.Serialization;\n";
+}
+
+string t_csharp_generator::csharp_thrift_usings() {
+  return string() + "using Thrift.Protocol;\n" + "using Thrift.Transport;\n";
+}
+
+void t_csharp_generator::close_generator() {
+}
+void t_csharp_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+void t_csharp_generator::generate_enum(t_enum* tenum) {
+  string f_enum_name = namespace_dir_ + "/" + (tenum->get_name()) + ".cs";
+  ofstream_with_content_based_conditional_update f_enum;
+  f_enum.open(f_enum_name.c_str());
+
+  f_enum << autogen_comment() << endl;
+
+  start_csharp_namespace(f_enum);
+
+  generate_csharp_doc(f_enum, tenum);
+
+  indent(f_enum) << "public enum " << tenum->get_name() << "\n";
+  scope_up(f_enum);
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    generate_csharp_doc(f_enum, *c_iter);
+
+    int value = (*c_iter)->get_value();
+    indent(f_enum) << (*c_iter)->get_name() << " = " << value << "," << endl;
+  }
+
+  scope_down(f_enum);
+
+  end_csharp_namespace(f_enum);
+
+  f_enum.close();
+}
+
+void t_csharp_generator::generate_consts(std::vector<t_const*> consts) {
+  if (consts.empty()) {
+    return;
+  }
+  string f_consts_name = namespace_dir_ + '/' + program_name_ + ".Constants.cs";
+  ofstream_with_content_based_conditional_update f_consts;
+  f_consts.open(f_consts_name.c_str());
+
+  f_consts << autogen_comment() << csharp_type_usings() << endl;
+
+  start_csharp_namespace(f_consts);
+
+  indent(f_consts) << "public static class " << make_valid_csharp_identifier(program_name_)
+                   << "Constants" << endl;
+  scope_up(f_consts);
+
+  vector<t_const*>::iterator c_iter;
+  bool need_static_constructor = false;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    generate_csharp_doc(f_consts, (*c_iter));
+    if (print_const_value(f_consts,
+                          (*c_iter)->get_name(),
+                          (*c_iter)->get_type(),
+                          (*c_iter)->get_value(),
+                          false)) {
+      need_static_constructor = true;
+    }
+  }
+
+  if (need_static_constructor) {
+    print_const_constructor(f_consts, consts);
+  }
+
+  scope_down(f_consts);
+  end_csharp_namespace(f_consts);
+  f_consts.close();
+}
+
+void t_csharp_generator::print_const_def_value(std::ostream& out,
+                                               string name,
+                                               t_type* type,
+                                               t_const_value* value) {
+  if (type->is_struct() || type->is_xception()) {
+    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    prepare_member_name_mapping((t_struct*)type);
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_field* field = NULL;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+          field = (*f_iter);
+        }
+      }
+      if (field == NULL) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+      t_type* field_type = field->get_type();
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      indent(out) << name << "." << prop_name(field) << " = " << val << ";" << endl;
+    }
+    cleanup_member_name_mapping((t_struct*)type);
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << name << "[" << key << "]"
+                  << " = " << val << ";" << endl;
+    }
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, name, etype, *v_iter);
+      indent(out) << name << ".Add(" << val << ");" << endl;
+    }
+  }
+}
+
+void t_csharp_generator::print_const_constructor(std::ostream& out, std::vector<t_const*> consts) {
+  indent(out) << "static " << make_valid_csharp_identifier(program_name_).c_str() << "Constants()"
+              << endl;
+  scope_up(out);
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    t_type* type = (*c_iter)->get_type();
+    t_const_value* value = (*c_iter)->get_value();
+
+    print_const_def_value(out, name, type, value);
+  }
+  scope_down(out);
+}
+
+// it seems like all that methods that call this are using in_static to be the opposite of what it
+// would imply
+bool t_csharp_generator::print_const_value(std::ostream& out,
+                                           string name,
+                                           t_type* type,
+                                           t_const_value* value,
+                                           bool in_static,
+                                           bool defval,
+                                           bool needtype) {
+  indent(out);
+  bool need_static_construction = !in_static;
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  if (!defval || needtype) {
+    out << (in_static ? "" : type->is_base_type() ? "public const " : "public static ")
+        << type_name(type) << " ";
+  }
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, name, type, value);
+    out << name << " = " << v2 << ";" << endl;
+    need_static_construction = false;
+  } else if (type->is_enum()) {
+    out << name << " = " << type_name(type, false, true) << "." << value->get_identifier_name()
+        << ";" << endl;
+    need_static_construction = false;
+  } else if (type->is_struct() || type->is_xception()) {
+    out << name << " = new " << type_name(type) << "();" << endl;
+  } else if (type->is_map()) {
+    out << name << " = new " << type_name(type, true, true) << "();" << endl;
+  } else if (type->is_list() || type->is_set()) {
+    out << name << " = new " << type_name(type) << "();" << endl;
+  }
+
+  if (defval && !type->is_base_type() && !type->is_enum()) {
+    print_const_def_value(out, name, type, value);
+  }
+
+  return need_static_construction;
+}
+
+std::string t_csharp_generator::render_const_value(ostream& out,
+                                                   string name,
+                                                   t_type* type,
+                                                   t_const_value* value) {
+  (void)name;
+  std::ostringstream render;
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      render << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "true" : "false");
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer();
+      } else {
+        render << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    render << type->get_name() << "." << value->get_identifier_name();
+  } else {
+    string t = tmp("tmp");
+    print_const_value(out, t, type, value, true, true, true);
+    render << t;
+  }
+
+  return render.str();
+}
+
+void t_csharp_generator::generate_struct(t_struct* tstruct) {
+  if (union_ && tstruct->is_union()) {
+    generate_csharp_union(tstruct);
+  } else {
+    generate_csharp_struct(tstruct, false);
+  }
+}
+
+void t_csharp_generator::generate_xception(t_struct* txception) {
+  generate_csharp_struct(txception, true);
+}
+
+void t_csharp_generator::generate_csharp_struct(t_struct* tstruct, bool is_exception) {
+  string f_struct_name = namespace_dir_ + "/" + (tstruct->get_name()) + ".cs";
+  ofstream_with_content_based_conditional_update f_struct;
+
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct << autogen_comment() << csharp_type_usings() << csharp_thrift_usings() << endl;
+
+  generate_csharp_struct_definition(f_struct, tstruct, is_exception);
+
+  f_struct.close();
+}
+
+void t_csharp_generator::generate_csharp_struct_definition(ostream& out,
+                                                           t_struct* tstruct,
+                                                           bool is_exception,
+                                                           bool in_class,
+                                                           bool is_result) {
+
+  if (!in_class) {
+    start_csharp_namespace(out);
+  }
+
+  out << endl;
+
+  generate_csharp_doc(out, tstruct);
+  prepare_member_name_mapping(tstruct);
+
+  indent(out) << "#if !SILVERLIGHT" << endl;
+  indent(out) << "[Serializable]" << endl;
+  indent(out) << "#endif" << endl;
+  if ((serialize_ || wcf_) && !is_exception) {
+    indent(out) << "[DataContract(Namespace=\"" << wcf_namespace_ << "\")]"
+                << endl; // do not make exception classes directly WCF serializable, we provide a
+                         // separate "fault" for that
+  }
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+
+  indent(out) << "public " << (is_final ? "sealed " : "") << "partial class "
+              << normalize_name(tstruct->get_name()) << " : ";
+
+  if (is_exception) {
+    out << "TException, ";
+  }
+  out << "TBase";
+
+  out << endl;
+
+  scope_up(out);
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  // make private members with public Properties
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    // if the field is requied, then we use auto-properties
+    if (!field_is_required((*m_iter)) && (!nullable_ || field_has_default((*m_iter)))) {
+      indent(out) << "private " << declare_field(*m_iter, false, "_") << endl;
+    }
+  }
+  out << endl;
+
+  bool has_non_required_fields = false;
+  bool has_non_required_default_value_fields = false;
+  bool has_required_fields = false;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    generate_csharp_doc(out, *m_iter);
+    generate_property(out, *m_iter, true, true);
+    bool is_required = field_is_required((*m_iter));
+    bool has_default = field_has_default((*m_iter));
+    if (is_required) {
+      has_required_fields = true;
+    } else {
+      if (has_default) {
+        has_non_required_default_value_fields = true;
+      }
+      has_non_required_fields = true;
+    }
+  }
+
+  bool generate_isset = (nullable_ && has_non_required_default_value_fields)
+                        || (!nullable_ && has_non_required_fields);
+  if (generate_isset) {
+    out << endl;
+    if (serialize_ || wcf_) {
+      out << indent() << "[XmlIgnore] // XmlSerializer" << endl << indent()
+          << "[DataMember(Order = 1)]  // XmlObjectSerializer, DataContractJsonSerializer, etc."
+          << endl;
+    }
+    out << indent() << "public Isset __isset;" << endl << indent() << "#if !SILVERLIGHT" << endl
+        << indent() << "[Serializable]" << endl << indent() << "#endif" << endl;
+    if (serialize_ || wcf_) {
+      indent(out) << "[DataContract]" << endl;
+    }
+    indent(out) << "public struct Isset {" << endl;
+    indent_up();
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      bool is_required = field_is_required((*m_iter));
+      bool has_default = field_has_default((*m_iter));
+      // if it is required, don't need Isset for that variable
+      // if it is not required, if it has a default value, we need to generate Isset
+      // if we are not nullable, then we generate Isset
+      if (!is_required && (!nullable_ || has_default)) {
+        if (serialize_ || wcf_) {
+          indent(out) << "[DataMember]" << endl;
+        }
+        indent(out) << "public bool " << normalize_name((*m_iter)->get_name()) << ";" << endl;
+      }
+    }
+
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    if (generate_isset && (serialize_ || wcf_)) {
+      indent(out) << "#region XmlSerializer support" << endl << endl;
+
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        bool is_required = field_is_required((*m_iter));
+        bool has_default = field_has_default((*m_iter));
+        // if it is required, don't need Isset for that variable
+        // if it is not required, if it has a default value, we need to generate Isset
+        // if we are not nullable, then we generate Isset
+        if (!is_required && (!nullable_ || has_default)) {
+          indent(out) << "public bool ShouldSerialize" << prop_name((*m_iter)) << "()" << endl;
+          indent(out) << "{" << endl;
+          indent_up();
+          indent(out) << "return __isset." << normalize_name((*m_iter)->get_name()) << ";" << endl;
+          indent_down();
+          indent(out) << "}" << endl << endl;
+        }
+      }
+
+      indent(out) << "#endregion XmlSerializer support" << endl << endl;
+    }
+  }
+
+  // We always want a default, no argument constructor for Reading
+  indent(out) << "public " << normalize_name(tstruct->get_name()) << "() {" << endl;
+  indent_up();
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = (*m_iter)->get_type();
+    while (t->is_typedef()) {
+      t = ((t_typedef*)t)->get_type();
+    }
+    if ((*m_iter)->get_value() != NULL) {
+      if (field_is_required((*m_iter))) {
+        print_const_value(out, "this." + prop_name(*m_iter), t, (*m_iter)->get_value(), true, true);
+      } else {
+        print_const_value(out,
+                          "this._" + (*m_iter)->get_name(),
+                          t,
+                          (*m_iter)->get_value(),
+                          true,
+                          true);
+        // Optionals with defaults are marked set
+        indent(out) << "this.__isset." << normalize_name((*m_iter)->get_name()) << " = true;"
+                    << endl;
+      }
+    }
+  }
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  if (has_required_fields) {
+    indent(out) << "public " << tstruct->get_name() << "(";
+    bool first = true;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (field_is_required((*m_iter))) {
+        if (first) {
+          first = false;
+        } else {
+          out << ", ";
+        }
+        out << type_name((*m_iter)->get_type()) << " " << normalize_name((*m_iter)->get_name());
+      }
+    }
+    out << ") : this() {" << endl;
+    indent_up();
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (field_is_required((*m_iter))) {
+        indent(out) << "this." << prop_name((*m_iter)) << " = " << normalize_name((*m_iter)->get_name()) << ";"
+                    << endl;
+      }
+    }
+
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+
+  generate_csharp_struct_reader(out, tstruct);
+  if (is_result) {
+    generate_csharp_struct_result_writer(out, tstruct);
+  } else {
+    generate_csharp_struct_writer(out, tstruct);
+  }
+  if (hashcode_) {
+    generate_csharp_struct_equals(out, tstruct);
+    generate_csharp_struct_hashcode(out, tstruct);
+  }
+  generate_csharp_struct_tostring(out, tstruct);
+  scope_down(out);
+  out << endl;
+
+  // generate a corresponding WCF fault to wrap the exception
+  if ((serialize_ || wcf_) && is_exception) {
+    generate_csharp_wcffault(out, tstruct);
+  }
+
+  cleanup_member_name_mapping(tstruct);
+  if (!in_class) {
+    end_csharp_namespace(out);
+  }
+}
+
+void t_csharp_generator::generate_csharp_wcffault(ostream& out, t_struct* tstruct) {
+  out << endl;
+  indent(out) << "#if !SILVERLIGHT" << endl;
+  indent(out) << "[Serializable]" << endl;
+  indent(out) << "#endif" << endl;
+  indent(out) << "[DataContract]" << endl;
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+
+  indent(out) << "public " << (is_final ? "sealed " : "") << "partial class " << tstruct->get_name()
+              << "Fault" << endl;
+
+  scope_up(out);
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  // make private members with public Properties
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    // if the field is requied, then we use auto-properties
+    if (!field_is_required((*m_iter)) && (!nullable_ || field_has_default((*m_iter)))) {
+      indent(out) << "private " << declare_field(*m_iter, false, "_") << endl;
+    }
+  }
+  out << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    generate_property(out, *m_iter, true, false);
+  }
+
+  scope_down(out);
+  out << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_reader(ostream& out, t_struct* tstruct) {
+  indent(out) << "public void Read (TProtocol iprot)" << endl;
+  scope_up(out);
+
+  out << indent() << "iprot.IncrementRecursionDepth();" << endl;
+  out << indent() << "try" << endl;
+  scope_up(out);
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Required variables aren't in __isset, so we need tmp vars to check them
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (field_is_required((*f_iter))) {
+      indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
+    }
+  }
+
+  indent(out) << "TField field;" << endl << indent() << "iprot.ReadStructBegin();" << endl;
+
+  indent(out) << "while (true)" << endl;
+  scope_up(out);
+
+  indent(out) << "field = iprot.ReadFieldBegin();" << endl;
+
+  indent(out) << "if (field.Type == TType.Stop) { " << endl;
+  indent_up();
+  indent(out) << "break;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent(out) << "switch (field.ID)" << endl;
+
+  scope_up(out);
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool is_required = field_is_required((*f_iter));
+    indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
+    indent_up();
+    indent(out) << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+    indent_up();
+
+    generate_deserialize_field(out, *f_iter);
+    if (is_required) {
+      indent(out) << "isset_" << (*f_iter)->get_name() << " = true;" << endl;
+    }
+
+    indent_down();
+    out << indent() << "} else { " << endl << indent() << "  TProtocolUtil.Skip(iprot, field.Type);"
+        << endl << indent() << "}" << endl << indent() << "break;" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default: " << endl;
+  indent_up();
+  indent(out) << "TProtocolUtil.Skip(iprot, field.Type);" << endl;
+  indent(out) << "break;" << endl;
+  indent_down();
+
+  scope_down(out);
+
+  indent(out) << "iprot.ReadFieldEnd();" << endl;
+
+  scope_down(out);
+
+  indent(out) << "iprot.ReadStructEnd();" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (field_is_required((*f_iter))) {
+      indent(out) << "if (!isset_" << (*f_iter)->get_name() << ")" << endl;
+      indent_up();
+      out << indent()
+          << "throw new TProtocolException(TProtocolException.INVALID_DATA, "
+          << "\"required field " << prop_name((*f_iter)) << " not set\");"
+          << endl;
+      indent_down();
+    }
+  }
+
+  scope_down(out);
+  out << indent() << "finally" << endl;
+  scope_up(out);
+  out << indent() << "iprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_writer(ostream& out, t_struct* tstruct) {
+  out << indent() << "public void Write(TProtocol oprot) {" << endl;
+  indent_up();
+
+  out << indent() << "oprot.IncrementRecursionDepth();" << endl;
+  out << indent() << "try" << endl;
+  scope_up(out);
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "TStruct struc = new TStruct(\"" << name << "\");" << endl;
+  indent(out) << "oprot.WriteStructBegin(struc);" << endl;
+
+  if (fields.size() > 0) {
+    indent(out) << "TField field = new TField();" << endl;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      bool is_required = field_is_required((*f_iter));
+      bool has_default = field_has_default((*f_iter));
+      bool null_allowed = type_can_be_null((*f_iter)->get_type());
+
+      if (is_required)
+      {
+        if (null_allowed) {
+          indent(out) << "if (" << prop_name((*f_iter)) << " == null)" << endl;
+          indent_up();
+          out << indent()
+              << "throw new TProtocolException(TProtocolException.INVALID_DATA, "
+              << "\"required field " << prop_name((*f_iter)) << " not set\");"
+              << endl;
+          indent_down();
+        }
+      }
+      else
+      {
+        if (nullable_ && !has_default) {
+            indent(out) << "if (" << prop_name((*f_iter)) << " != null) {" << endl;
+        }
+        else if (null_allowed) {
+          out << indent()
+              << "if (" << prop_name((*f_iter)) << " != null && __isset."
+              << normalize_name((*f_iter)->get_name()) << ") {"
+              << endl;
+        }
+        else {
+           indent(out) << "if (__isset." << normalize_name((*f_iter)->get_name()) << ") {" << endl;
+        }
+        indent_up();
+      }
+      indent(out) << "field.Name = \"" << (*f_iter)->get_name() << "\";" << endl;
+      indent(out) << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl;
+      indent(out) << "field.ID = " << (*f_iter)->get_key() << ";" << endl;
+      indent(out) << "oprot.WriteFieldBegin(field);" << endl;
+
+      generate_serialize_field(out, *f_iter);
+
+      indent(out) << "oprot.WriteFieldEnd();" << endl;
+      if (!is_required) {
+        indent_down();
+        indent(out) << "}" << endl;
+      }
+    }
+  }
+
+  indent(out) << "oprot.WriteFieldStop();" << endl;
+  indent(out) << "oprot.WriteStructEnd();" << endl;
+
+  scope_down(out);
+  out << indent() << "finally" << endl;
+  scope_up(out);
+  out << indent() << "oprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_result_writer(ostream& out, t_struct* tstruct) {
+  indent(out) << "public void Write(TProtocol oprot) {" << endl;
+  indent_up();
+
+  out << indent() << "oprot.IncrementRecursionDepth();" << endl;
+  out << indent() << "try" << endl;
+  scope_up(out);
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "TStruct struc = new TStruct(\"" << name << "\");" << endl;
+  indent(out) << "oprot.WriteStructBegin(struc);" << endl;
+
+  if (fields.size() > 0) {
+    indent(out) << "TField field = new TField();" << endl;
+    bool first = true;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      if (first) {
+        first = false;
+        out << endl << indent() << "if ";
+      } else {
+        out << " else if ";
+      }
+
+      if (nullable_) {
+        out << "(this." << prop_name((*f_iter)) << " != null) {" << endl;
+      } else {
+        out << "(this.__isset." << normalize_name((*f_iter)->get_name()) << ") {" << endl;
+      }
+      indent_up();
+
+      bool null_allowed = !nullable_ && type_can_be_null((*f_iter)->get_type());
+      if (null_allowed) {
+        indent(out) << "if (" << prop_name(*f_iter) << " != null) {" << endl;
+        indent_up();
+      }
+
+      indent(out) << "field.Name = \"" << prop_name(*f_iter) << "\";" << endl;
+      indent(out) << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl;
+      indent(out) << "field.ID = " << (*f_iter)->get_key() << ";" << endl;
+      indent(out) << "oprot.WriteFieldBegin(field);" << endl;
+
+      generate_serialize_field(out, *f_iter);
+
+      indent(out) << "oprot.WriteFieldEnd();" << endl;
+
+      if (null_allowed) {
+        indent_down();
+        indent(out) << "}" << endl;
+      }
+
+      indent_down();
+      indent(out) << "}";
+    }
+  }
+
+  out << endl << indent() << "oprot.WriteFieldStop();" << endl << indent()
+      << "oprot.WriteStructEnd();" << endl;
+
+  scope_down(out);
+  out << indent() << "finally" << endl;
+  scope_up(out);
+  out << indent() << "oprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_tostring(ostream& out, t_struct* tstruct) {
+  indent(out) << "public override string ToString() {" << endl;
+  indent_up();
+
+  indent(out) << "StringBuilder __sb = new StringBuilder(\"" << tstruct->get_name() << "(\");"
+              << endl;
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  bool useFirstFlag = false;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (!field_is_required((*f_iter))) {
+      indent(out) << "bool __first = true;" << endl;
+      useFirstFlag = true;
+    }
+    break;
+  }
+
+  bool had_required = false; // set to true after first required field has been processed
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool is_required = field_is_required((*f_iter));
+    bool has_default = field_has_default((*f_iter));
+    if (nullable_ && !has_default && !is_required) {
+      indent(out) << "if (" << prop_name((*f_iter)) << " != null) {" << endl;
+      indent_up();
+    } else if (!is_required) {
+      bool null_allowed = type_can_be_null((*f_iter)->get_type());
+      if (null_allowed) {
+        indent(out) << "if (" << prop_name((*f_iter)) << " != null && __isset."
+                    << normalize_name((*f_iter)->get_name()) << ") {" << endl;
+        indent_up();
+      } else {
+        indent(out) << "if (__isset." << normalize_name((*f_iter)->get_name()) << ") {" << endl;
+        indent_up();
+      }
+    }
+
+    if (useFirstFlag && (!had_required)) {
+      indent(out) << "if(!__first) { __sb.Append(\", \"); }" << endl;
+      if (!is_required) {
+        indent(out) << "__first = false;" << endl;
+      }
+      indent(out) << "__sb.Append(\"" << prop_name((*f_iter)) << ": \");" << endl;
+    } else {
+      indent(out) << "__sb.Append(\", " << prop_name((*f_iter)) << ": \");" << endl;
+    }
+
+    t_type* ttype = (*f_iter)->get_type();
+    if (ttype->is_xception() || ttype->is_struct()) {
+      indent(out) << "__sb.Append(" << prop_name((*f_iter))
+                  << "== null ? \"<null>\" : " << prop_name((*f_iter)) << ".ToString());" << endl;
+    } else {
+      indent(out) << "__sb.Append(" << prop_name((*f_iter)) << ");" << endl;
+    }
+
+    if (!is_required) {
+      indent_down();
+      indent(out) << "}" << endl;
+    } else {
+      had_required = true; // now __first must be false, so we don't need to check it anymore
+    }
+  }
+
+  indent(out) << "__sb.Append(\")\");" << endl;
+  indent(out) << "return __sb.ToString();" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_union(t_struct* tunion) {
+  string f_union_name = namespace_dir_ + "/" + (tunion->get_name()) + ".cs";
+  ofstream_with_content_based_conditional_update f_union;
+
+  f_union.open(f_union_name.c_str());
+
+  f_union << autogen_comment() << csharp_type_usings() << csharp_thrift_usings() << endl;
+
+  generate_csharp_union_definition(f_union, tunion);
+
+  f_union.close();
+}
+
+void t_csharp_generator::generate_csharp_union_definition(std::ostream& out, t_struct* tunion) {
+  // Let's define the class first
+  start_csharp_namespace(out);
+
+  indent(out) << "public abstract partial class " << tunion->get_name() << " : TAbstractBase {"
+              << endl;
+
+  indent_up();
+
+  indent(out) << "public abstract void Write(TProtocol protocol);" << endl;
+  indent(out) << "public readonly int Isset;" << endl;
+  indent(out) << "public abstract object Data { get; }" << endl;
+
+  indent(out) << "protected " << tunion->get_name() << "(int isset) {" << endl;
+  indent_up();
+  indent(out) << "Isset = isset;" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "public class ___undefined : " << tunion->get_name() << " {" << endl;
+  indent_up();
+
+  indent(out) << "public override object Data { get { return null; } }" << endl;
+
+  indent(out) << "public ___undefined() : base(0) {}" << endl << endl;
+
+  indent(out) << "public override void Write(TProtocol protocol) {" << endl;
+  indent_up();
+  indent(out) << "throw new TProtocolException( TProtocolException.INVALID_DATA, \"Cannot persist "
+                 "an union type which is not set.\");" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  const vector<t_field*>& fields = tunion->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    generate_csharp_union_class(out, tunion, (*f_iter));
+  }
+
+  generate_csharp_union_reader(out, tunion);
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  end_csharp_namespace(out);
+}
+
+void t_csharp_generator::generate_csharp_union_class(std::ostream& out,
+                                                     t_struct* tunion,
+                                                     t_field* tfield) {
+  indent(out) << "public " << type_name(tfield->get_type()) << " As_" << tfield->get_name() << endl;
+  indent(out) << "{" << endl;
+  indent_up();
+  indent(out) << "get" << endl;
+  indent(out) << "{" << endl;
+  indent_up();
+  indent(out) << "return (" << tfield->get_key() << " == Isset) ? (" << type_name(tfield->get_type()) << ")Data : default(" << type_name(tfield->get_type()) << ");" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+  indent_down();
+  indent(out) << "}" << endl
+      << endl;
+	
+	
+  indent(out) << "public class " << tfield->get_name() << " : " << tunion->get_name() << " {"
+              << endl;
+  indent_up();
+  indent(out) << "private " << type_name(tfield->get_type()) << " _data;" << endl;
+  indent(out) << "public override object Data { get { return _data; } }" << endl;
+  indent(out) << "public " << tfield->get_name() << "(" << type_name(tfield->get_type())
+              << " data) : base("<< tfield->get_key() <<") {" << endl;
+  indent_up();
+  indent(out) << "this._data = data;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+  indent(out) << "public override void Write(TProtocol oprot) {" << endl;
+  indent_up();
+
+  out << indent() << "oprot.IncrementRecursionDepth();" << endl;
+  out << indent() << "try" << endl;
+  scope_up(out);
+
+  indent(out) << "TStruct struc = new TStruct(\"" << tunion->get_name() << "\");" << endl;
+  indent(out) << "oprot.WriteStructBegin(struc);" << endl;
+
+  indent(out) << "TField field = new TField();" << endl;
+  indent(out) << "field.Name = \"" << tfield->get_name() << "\";" << endl;
+  indent(out) << "field.Type = " << type_to_enum(tfield->get_type()) << ";" << endl;
+  indent(out) << "field.ID = " << tfield->get_key() << ";" << endl;
+  indent(out) << "oprot.WriteFieldBegin(field);" << endl;
+
+  generate_serialize_field(out, tfield, "_data", true, true);
+
+  indent(out) << "oprot.WriteFieldEnd();" << endl;
+  indent(out) << "oprot.WriteFieldStop();" << endl;
+  indent(out) << "oprot.WriteStructEnd();" << endl;
+  indent_down();
+
+  scope_down(out);
+  out << indent() << "finally" << endl;
+  scope_up(out);
+  out << indent() << "oprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_equals(ostream& out, t_struct* tstruct) {
+  indent(out) << "public override bool Equals(object that) {" << endl;
+  indent_up();
+
+  indent(out) << "var other = that as " << type_name(tstruct) << ";" << endl;
+  indent(out) << "if (other == null) return false;" << endl;
+  indent(out) << "if (ReferenceEquals(this, other)) return true;" << endl;
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  bool first = true;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      indent(out) << "return ";
+      indent_up();
+    } else {
+      out << endl;
+      indent(out) << "&& ";
+    }
+    if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) {
+      out << "((__isset." << normalize_name((*f_iter)->get_name()) << " == other.__isset."
+          << normalize_name((*f_iter)->get_name()) << ") && ((!__isset."
+          << normalize_name((*f_iter)->get_name()) << ") || (";
+    }
+    t_type* ttype = (*f_iter)->get_type();
+    if (ttype->is_container() || ttype->is_binary()) {
+      out << "TCollections.Equals(";
+    } else {
+      out << "System.Object.Equals(";
+    }
+    out << prop_name((*f_iter)) << ", other." << prop_name((*f_iter)) << ")";
+    if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) {
+      out << ")))";
+    }
+  }
+  if (first) {
+    indent(out) << "return true;" << endl;
+  } else {
+    out << ";" << endl;
+    indent_down();
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_hashcode(ostream& out, t_struct* tstruct) {
+  indent(out) << "public override int GetHashCode() {" << endl;
+  indent_up();
+
+  indent(out) << "int hashcode = 0;" << endl;
+  indent(out) << "unchecked {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_type* ttype = (*f_iter)->get_type();
+    indent(out) << "hashcode = (hashcode * 397) ^ ";
+    if (field_is_required((*f_iter))) {
+      out << "(";
+    } else if (nullable_) {
+      out << "(" << prop_name((*f_iter)) << " == null ? 0 : ";
+    } else {
+      out << "(!__isset." << normalize_name((*f_iter)->get_name()) << " ? 0 : ";
+    }
+    if (ttype->is_container()) {
+      out << "(TCollections.GetHashCode(" << prop_name((*f_iter)) << "))";
+    } else {
+      out << "(" << prop_name((*f_iter)) << ".GetHashCode())";
+    }
+    out << ");" << endl;
+  }
+
+  indent_down();
+  indent(out) << "}" << endl;
+  indent(out) << "return hashcode;" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_service(t_service* tservice) {
+  string f_service_name = namespace_dir_ + "/" + service_name_ + ".cs";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << autogen_comment() << csharp_type_usings() << csharp_thrift_usings() << endl;
+
+  start_csharp_namespace(f_service_);
+
+  indent(f_service_) << "public partial class " << normalize_name(service_name_) << " {" << endl;
+  indent_up();
+
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+
+  indent_down();
+
+  indent(f_service_) << "}" << endl;
+  end_csharp_namespace(f_service_);
+  f_service_.close();
+}
+
+void t_csharp_generator::generate_service_interface(t_service* tservice) {
+  generate_separate_service_interfaces(tservice);
+}
+
+void t_csharp_generator::generate_separate_service_interfaces(t_service* tservice) {
+  generate_sync_service_interface(tservice);
+
+  if (async_) {
+    generate_async_service_interface(tservice);
+  }
+
+  generate_combined_service_interface(tservice);
+}
+
+void t_csharp_generator::generate_sync_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_iface = " : " + extends + ".ISync";
+  }
+
+  generate_csharp_doc(f_service_, tservice);
+
+  if (wcf_) {
+    indent(f_service_) << "[System.ServiceModel.ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
+  }
+  indent(f_service_) << "public interface ISync" << extends_iface << " {" << endl;
+
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_csharp_doc(f_service_, *f_iter);
+
+    // if we're using WCF, add the corresponding attributes
+    if (wcf_) {
+      indent(f_service_) << "[System.ServiceModel.OperationContract]" << endl;
+
+      const std::vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        indent(f_service_) << "[System.ServiceModel.FaultContract(typeof("
+          + type_name((*x_iter)->get_type(), false, false) + "Fault))]" << endl;
+      }
+    }
+
+    indent(f_service_) << function_signature(*f_iter) << ";" << endl;
+  }
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_async_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_iface = " : " + extends + ".IAsync";
+  }
+
+  generate_csharp_doc(f_service_, tservice);
+
+  if (wcf_) {
+    indent(f_service_) << "[System.ServiceModel.ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
+  }
+  indent(f_service_) << "public interface IAsync" << extends_iface << " {" << endl;
+
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_csharp_doc(f_service_, *f_iter);
+
+    // if we're using WCF, add the corresponding attributes
+    if (wcf_) {
+      indent(f_service_) << "[System.ServiceModel.OperationContract]" << endl;
+
+      const std::vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        indent(f_service_) << "[System.ServiceModel.FaultContract(typeof("
+          + type_name((*x_iter)->get_type(), false, false) + "Fault))]" << endl;
+      }
+    }
+
+    indent(f_service_) << function_signature_async(*f_iter) << ";" << endl;
+  }
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_combined_service_interface(t_service* tservice) {
+  string extends_iface = " : ISync";
+
+  if (async_) {
+    extends_iface += ", IAsync";
+  }
+
+  generate_csharp_doc(f_service_, tservice);
+
+  if (wcf_) {
+    indent(f_service_) << "[System.ServiceModel.ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
+  }
+
+  indent(f_service_) << "public interface Iface" << extends_iface << " {" << endl;
+
+  indent_up();
+
+  // We need to generate extra old style async methods for silverlight. Since
+  // this isn't something you'd want to implement server-side, just put them into
+  // the main Iface interface.
+  generate_silverlight_async_methods(tservice);
+
+  indent_down();
+
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_silverlight_async_methods(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_csharp_doc(f_service_, *f_iter);
+
+    // For backwards compatibility, include the Begin_, End_ methods if we're generating
+    // with the async flag. I'm not sure this is necessary, so someone with more knowledge
+    // can maybe remove these checks if they know it's safe.
+    if (!async_) {
+      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_) {
+      indent(f_service_) << "#endif" << endl;
+    }
+  }
+}
+
+void t_csharp_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_csharp_struct_definition(f_service_, ts, false, true);
+    generate_function_helpers(*f_iter);
+  }
+}
+
+void t_csharp_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_client = extends + ".Client, ";
+  } else {
+    extends_client = "IDisposable, ";
+  }
+
+  generate_csharp_doc(f_service_, tservice);
+
+  indent(f_service_) << "public class Client : " << extends_client << "Iface {" << endl;
+  indent_up();
+  indent(f_service_) << "public Client(TProtocol prot) : this(prot, prot)" << endl;
+  scope_up(f_service_);
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  indent(f_service_) << "public Client(TProtocol iprot, TProtocol oprot)";
+  if (!extends.empty()) {
+    f_service_ << " : base(iprot, oprot)";
+  }
+  f_service_ << endl;
+
+  scope_up(f_service_);
+  if (extends.empty()) {
+    f_service_ << indent() << "iprot_ = iprot;" << endl << indent() << "oprot_ = oprot;" << endl;
+  }
+  scope_down(f_service_);
+
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_ << indent() << "protected TProtocol iprot_;" << endl << indent()
+               << "protected TProtocol oprot_;" << endl << indent() << "protected int seqid_;"
+               << endl << endl;
+
+    f_service_ << indent() << "public TProtocol InputProtocol" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "get { return iprot_; }" << endl;
+    scope_down(f_service_);
+
+    f_service_ << indent() << "public TProtocol OutputProtocol" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "get { return oprot_; }" << endl;
+    scope_down(f_service_);
+    f_service_ << endl << endl;
+
+    indent(f_service_) << "#region \" IDisposable Support \"" << endl;
+    indent(f_service_) << "private bool _IsDisposed;" << endl << endl;
+    indent(f_service_) << "// IDisposable" << endl;
+    indent(f_service_) << "public void Dispose()" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "Dispose(true);" << endl;
+    scope_down(f_service_);
+    indent(f_service_) << endl << endl;
+    indent(f_service_) << "protected virtual void Dispose(bool disposing)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "if (!_IsDisposed)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "if (disposing)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "if (iprot_ != null)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "((IDisposable)iprot_).Dispose();" << endl;
+    scope_down(f_service_);
+    indent(f_service_) << "if (oprot_ != null)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "((IDisposable)oprot_).Dispose();" << endl;
+    scope_down(f_service_);
+    scope_down(f_service_);
+    scope_down(f_service_);
+    indent(f_service_) << "_IsDisposed = true;" << endl;
+    scope_down(f_service_);
+    indent(f_service_) << "#endregion" << endl;
+    f_service_ << endl << endl;
+  }
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funname = (*f_iter)->get_name();
+
+    indent(f_service_) << endl;
+
+    if (!async_) {
+      indent(f_service_) << "#if SILVERLIGHT" << endl;
+      indent(f_service_) << endl;
+    }
+    // Begin_
+    indent(f_service_) << "public " << function_signature_async_begin(*f_iter, "Begin_") << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "return "
+                       << "send_" << funname << "(callback, state";
+
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    prepare_member_name_mapping(arg_struct);
+
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << ", ";
+      f_service_ << normalize_name((*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
+    bool first;
+    if (async_) {
+      indent(f_service_) << "public async " << function_signature_async(*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 Task.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;
+    }
+
+    if (!async_) {
+      indent(f_service_) << "#endif" << endl << endl;
+    }
+
+    generate_csharp_doc(f_service_, *f_iter);
+    indent(f_service_) << "public " << function_signature(*f_iter) << endl;
+    scope_up(f_service_);
+
+    // silverlight invoke
+    if (!async_) {
+      indent(f_service_) << "#if SILVERLIGHT" << endl;
+
+      indent(f_service_) << "var asyncResult = Begin_" << funname << "(null, null";
+      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+        f_service_ << ", " << normalize_name((*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_) << "#else" << endl;
+    }
+
+    // synchronous invoke
+    indent(f_service_) << "send_" << funname << "(";
+  
+    first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << normalize_name((*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_ << "recv_" << funname << "();" << endl;
+    }
+    f_service_ << endl;
+
+    if (!async_) {
+      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";
+
+    if (!async_) {
+      indent(f_service_) << "#if SILVERLIGHT" << endl;
+    }
+
+    indent(f_service_) << "public " << function_signature_async_begin(&send_function) << endl;
+    scope_up(f_service_);
+
+    f_service_ << indent() << "oprot_.WriteMessageBegin(new TMessage(\"" << funname << "\", "
+               << ((*f_iter)->is_oneway() ? "TMessageType.Oneway" : "TMessageType.Call")
+               << ", seqid_));" << endl << indent() << argsname << " args = new " << argsname
+               << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << indent() << "args." << prop_name(*fld_iter) << " = "
+                 << normalize_name((*fld_iter)->get_name()) << ";" << endl;
+    }
+
+    f_service_ << indent() << "args.Write(oprot_);" << endl << indent()
+               << "oprot_.WriteMessageEnd();" << endl;
+    indent(f_service_) << "return oprot_.Transport.BeginFlush(callback, state);" << endl;
+      
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    if (!async_) {
+      indent(f_service_) << "#else" << endl;
+      f_service_ << endl;
+    }
+
+    indent(f_service_) << "public " << function_signature(&send_function) << endl;
+    scope_up(f_service_);
+
+    f_service_ << indent() << "oprot_.WriteMessageBegin(new TMessage(\"" << funname << "\", "
+               << ((*f_iter)->is_oneway() ? "TMessageType.Oneway" : "TMessageType.Call")
+               << ", seqid_));" << endl << indent() << argsname << " args = new " << argsname
+               << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << indent() << "args." << prop_name(*fld_iter) << " = "
+                 << normalize_name((*fld_iter)->get_name()) << ";" << endl;
+    }
+
+    f_service_ << indent() << "args.Write(oprot_);" << endl << indent()
+               << "oprot_.WriteMessageEnd();" << endl;
+
+    indent(f_service_) << "oprot_.Transport.Flush();" << endl;
+    cleanup_member_name_mapping(arg_struct);
+    scope_down(f_service_);
+
+    if (!async_) {
+      indent(f_service_) << "#endif" << endl;
+    }
+
+    f_service_ << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      string resultname = (*f_iter)->get_name() + "_result";
+
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs,
+                               (*f_iter)->get_xceptions());
+      indent(f_service_) << "public " << function_signature(&recv_function) << endl;
+      scope_up(f_service_);
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      prepare_member_name_mapping(xs, xs->get_members(), resultname);
+
+      f_service_ << indent() << "TMessage msg = iprot_.ReadMessageBegin();" << endl << indent()
+                 << "if (msg.Type == TMessageType.Exception) {" << endl;
+      indent_up();
+      f_service_ << indent() << "TApplicationException x = TApplicationException.Read(iprot_);"
+                 << endl << indent() << "iprot_.ReadMessageEnd();" << endl << indent() << "throw x;"
+                 << endl;
+      indent_down();
+      f_service_ << indent() << "}" << endl << indent() << resultname << " result = new "
+                 << resultname << "();" << endl << indent() << "result.Read(iprot_);" << endl
+                 << indent() << "iprot_.ReadMessageEnd();" << endl;
+
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        if (nullable_) {
+          if (type_can_be_null((*f_iter)->get_returntype())) {
+            f_service_ << indent() << "if (result.Success != null) {" << endl << indent()
+                       << "  return result.Success;" << endl << indent() << "}" << endl;
+          } else {
+            f_service_ << indent() << "if (result.Success.HasValue) {" << endl << indent()
+                       << "  return result.Success.Value;" << endl << indent() << "}" << endl;
+          }
+        } else {
+          f_service_ << indent() << "if (result.__isset.success) {" << endl << indent()
+                     << "  return result.Success;" << endl << indent() << "}" << endl;
+        }
+      }
+
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        if (nullable_) {
+          f_service_ << indent() << "if (result." << prop_name(*x_iter) << " != null) {" << endl
+                     << indent() << "  throw result." << prop_name(*x_iter) << ";" << endl
+                     << indent() << "}" << endl;
+        } else {
+          f_service_ << indent() << "if (result.__isset." << normalize_name((*x_iter)->get_name())
+                     << ") {" << endl << indent() << "  throw result." << prop_name(*x_iter) << ";"
+                     << endl << indent() << "}" << endl;
+        }
+      }
+
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << "return;" << endl;
+      } else {
+        f_service_ << indent()
+                   << "throw new "
+                      "TApplicationException(TApplicationException.ExceptionType.MissingResult, \""
+                   << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+      }
+
+      cleanup_member_name_mapping((*f_iter)->get_xceptions());
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl;
+}
+
+void t_csharp_generator::generate_service_server(t_service* tservice) {
+  if (async_) {
+    generate_service_server_async(tservice);
+    generate_service_server_sync(tservice);
+  }
+  else {
+    generate_service_server_sync(tservice);
+  }
+}
+
+void t_csharp_generator::generate_service_server_sync(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_processor = extends + ".Processor, ";
+  }
+
+  indent(f_service_) << "public class Processor : " << extends_processor << "TProcessor {" << endl;
+  indent_up();
+
+  indent(f_service_) << "public Processor(ISync iface)";
+
+  if (!extends.empty()) {
+    f_service_ << " : base(iface)";
+  }
+  f_service_ << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "iface_ = iface;" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << indent() << "processMap_[\"" << (*f_iter)->get_name()
+      << "\"] = " << (*f_iter)->get_name() << "_Process;" << endl;
+  }
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_
+      << indent()
+      << "protected delegate void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);"
+      << endl;
+  }
+
+  f_service_ << indent() << "private ISync iface_;" << endl;
+
+  if (extends.empty()) {
+    f_service_ << indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new "
+      "Dictionary<string, ProcessFunction>();" << endl;
+  }
+
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    indent(f_service_) << "public bool Process(TProtocol iprot, TProtocol oprot)" << endl;
+  }
+  else {
+    indent(f_service_) << "public new bool Process(TProtocol iprot, TProtocol oprot)" << endl;
+  }
+  scope_up(f_service_);
+
+  f_service_ << indent() << "try" << endl;
+  scope_up(f_service_);
+
+  f_service_ << indent() << "TMessage msg = iprot.ReadMessageBegin();" << endl;
+
+  f_service_
+    << indent() << "ProcessFunction fn;" << endl << indent()
+    << "processMap_.TryGetValue(msg.Name, out fn);" << endl << indent() << "if (fn == null) {"
+    << endl << indent() << "  TProtocolUtil.Skip(iprot, TType.Struct);" << endl << indent()
+    << "  iprot.ReadMessageEnd();" << endl << indent()
+    << "  TApplicationException x = new TApplicationException "
+    "(TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + "
+    "msg.Name + \"'\");" << endl << indent()
+    << "  oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID));"
+    << endl << indent() << "  x.Write(oprot);" << endl << indent() << "  oprot.WriteMessageEnd();"
+    << endl << indent() << "  oprot.Transport.Flush();" << endl << indent() << "  return true;"
+    << endl << indent() << "}" << endl << indent() << "fn(msg.SeqID, iprot, oprot);" << endl;
+
+  scope_down(f_service_);
+
+  f_service_ << indent() << "catch (IOException)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "return false;" << endl;
+  scope_down(f_service_);
+
+  f_service_ << indent() << "return true;" << endl;
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_service_server_async(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_processor = extends + ".AsyncProcessor, ";
+  }
+
+  indent(f_service_) << "public class AsyncProcessor : " << extends_processor << "TAsyncProcessor {" << endl;
+  indent_up();
+
+  indent(f_service_) << "public AsyncProcessor(IAsync iface)";
+  if (!extends.empty()) {
+    f_service_ << " : base(iface)";
+  }
+  f_service_ << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "iface_ = iface;" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << indent() << "processMap_[\"" << (*f_iter)->get_name()
+      << "\"] = " << (*f_iter)->get_name() << "_ProcessAsync;" << endl;
+  }
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_
+      << indent()
+      << "protected delegate Task ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);"
+      << endl;
+  }
+
+  f_service_ << indent() << "private IAsync iface_;" << endl;
+
+  if (extends.empty()) {
+    f_service_ << indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new "
+      "Dictionary<string, ProcessFunction>();" << endl;
+  }
+
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    indent(f_service_) << "public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl;
+  }
+  else {
+    indent(f_service_) << "public new async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl;
+  }
+  scope_up(f_service_);
+
+  f_service_ << indent() << "try" << endl;
+  scope_up(f_service_);
+
+  f_service_ << indent() << "TMessage msg = iprot.ReadMessageBegin();" << endl;
+
+  f_service_
+    << indent() << "ProcessFunction fn;" << endl << indent()
+    << "processMap_.TryGetValue(msg.Name, out fn);" << endl << indent() << "if (fn == null) {"
+    << endl << indent() << "  TProtocolUtil.Skip(iprot, TType.Struct);" << endl << indent()
+    << "  iprot.ReadMessageEnd();" << endl << indent()
+    << "  TApplicationException x = new TApplicationException "
+    "(TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + "
+    "msg.Name + \"'\");" << endl << indent()
+    << "  oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID));"
+    << endl << indent() << "  x.Write(oprot);" << endl << indent() << "  oprot.WriteMessageEnd();"
+    << endl << indent() << "  oprot.Transport.Flush();" << endl << indent() << "  return true;"
+    << endl << indent() << "}" << endl << indent() << "await fn(msg.SeqID, iprot, oprot);" << endl;
+
+  scope_down(f_service_);
+
+  f_service_ << indent() << "catch (IOException)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "return false;" << endl;
+  scope_down(f_service_);
+
+  f_service_ << indent() << "return true;" << endl;
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function_async(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_function_helpers(t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  t_struct result(program_, tfunction->get_name() + "_result");
+  t_field success(tfunction->get_returntype(), "success", 0);
+  if (!tfunction->get_returntype()->is_void()) {
+    result.append(&success);
+  }
+
+  t_struct* xs = tfunction->get_xceptions();
+  const vector<t_field*>& fields = xs->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    result.append(*f_iter);
+  }
+
+  generate_csharp_struct_definition(f_service_, &result, false, true, true);
+}
+
+void t_csharp_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  indent(f_service_) << "public void " << tfunction->get_name()
+                     << "_Process(int seqid, TProtocol iprot, TProtocol oprot)" << endl;
+  scope_up(f_service_);
+
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+
+  f_service_ << indent() << argsname << " args = new " << argsname << "();" << endl
+             << indent() << "args.Read(iprot);" << endl
+             << indent() << "iprot.ReadMessageEnd();" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl;
+  }
+
+  f_service_ << indent() << "try" << endl
+             << indent() << "{" << endl;
+  indent_up();
+
+  if (xceptions.size() > 0) {
+    f_service_ << indent() << "try" << endl
+               << indent() << "{" << endl;
+    indent_up();
+  }
+
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  f_service_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result.Success = ";
+  }
+  f_service_ << "iface_." << normalize_name(tfunction->get_name()) << "(";
+  bool first = true;
+  prepare_member_name_mapping(arg_struct);
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_service_ << ", ";
+    }
+    f_service_ << "args." << prop_name(*f_iter);
+    if (nullable_ && !type_can_be_null((*f_iter)->get_type())) {
+      f_service_ << ".Value";
+    }
+  }
+  cleanup_member_name_mapping(arg_struct);
+  f_service_ << ");" << endl;
+
+  prepare_member_name_mapping(xs, xs->get_members(), resultname);
+  if (xceptions.size() > 0) {
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << indent() << "catch (" << type_name((*x_iter)->get_type(), false, false) << " "
+                 << (*x_iter)->get_name() << ")" << endl
+                 << indent() << "{" << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ << indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name()
+                   << ";" << endl;
+        indent_down();
+      }
+      f_service_ << indent() << "}" << endl;
+    }
+  }
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << "oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name()
+               << "\", TMessageType.Reply, seqid)); " << endl;
+    f_service_ << indent() << "result.Write(oprot);" << endl;
+  }
+  indent_down();
+
+  cleanup_member_name_mapping(xs);
+
+  f_service_ << indent() << "}" << endl
+             << indent() << "catch (TTransportException)" << endl
+             << indent() << "{" << endl
+             << indent() << "  throw;" << endl
+             << indent() << "}" << endl
+             << indent() << "catch (Exception ex)" << endl
+             << indent() << "{" << endl
+             << indent() << "  Console.Error.WriteLine(\"Error occurred in processor:\");" << endl
+             << indent() << "  Console.Error.WriteLine(ex.ToString());" << endl;
+
+  if (tfunction->is_oneway()) {
+    f_service_ << indent() << "}" << endl;
+  } else {
+    f_service_ << indent() << "  TApplicationException x = new TApplicationException" << indent()
+               << "(TApplicationException.ExceptionType.InternalError,\" Internal error.\");"
+               << endl
+               << indent() << "  oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name()
+               << "\", TMessageType.Exception, seqid));" << endl
+               << indent() << "  x.Write(oprot);" << endl
+               << indent() << "}" << endl;
+    f_service_ << indent() << "oprot.WriteMessageEnd();" << endl
+               << indent() << "oprot.Transport.Flush();" << endl;
+  }
+
+  scope_down(f_service_);
+
+  f_service_ << endl;
+}
+
+void t_csharp_generator::generate_process_function_async(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  indent(f_service_) << "public async Task " << tfunction->get_name()
+    << "_ProcessAsync(int seqid, TProtocol iprot, TProtocol oprot)" << endl;
+  scope_up(f_service_);
+
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+
+  f_service_ << indent() << argsname << " args = new " << argsname << "();" << endl
+    << indent() << "args.Read(iprot);" << endl
+    << indent() << "iprot.ReadMessageEnd();" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl;
+  }
+
+  f_service_ << indent() << "try" << endl
+    << indent() << "{" << endl;
+  indent_up();
+
+  if (xceptions.size() > 0) {
+    f_service_ << indent() << "try" << endl
+      << indent() << "{" << endl;
+    indent_up();
+  }
+
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  f_service_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result.Success = ";
+  }
+  f_service_ << "await iface_." << normalize_name(tfunction->get_name()) << "Async(";
+  bool first = true;
+  prepare_member_name_mapping(arg_struct);
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    }
+    else {
+      f_service_ << ", ";
+    }
+    f_service_ << "args." << prop_name(*f_iter);
+    if (nullable_ && !type_can_be_null((*f_iter)->get_type())) {
+      f_service_ << ".Value";
+    }
+  }
+  cleanup_member_name_mapping(arg_struct);
+  f_service_ << ");" << endl;
+
+  prepare_member_name_mapping(xs, xs->get_members(), resultname);
+  if (xceptions.size() > 0) {
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << indent() << "catch (" << type_name((*x_iter)->get_type(), false, false) << " "
+        << (*x_iter)->get_name() << ")" << endl
+        << indent() << "{" << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ << indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name()
+          << ";" << endl;
+        indent_down();
+      }
+      f_service_ << indent() << "}" << endl;
+    }
+  }
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << "oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name()
+      << "\", TMessageType.Reply, seqid)); " << endl;
+    f_service_ << indent() << "result.Write(oprot);" << endl;
+  }
+  indent_down();
+
+  cleanup_member_name_mapping(xs);
+
+  f_service_ << indent() << "}" << endl
+    << indent() << "catch (TTransportException)" << endl
+    << indent() << "{" << endl
+    << indent() << "  throw;" << endl
+    << indent() << "}" << endl
+    << indent() << "catch (Exception ex)" << endl
+    << indent() << "{" << endl
+    << indent() << "  Console.Error.WriteLine(\"Error occurred in processor:\");" << endl
+    << indent() << "  Console.Error.WriteLine(ex.ToString());" << endl;
+
+  if (tfunction->is_oneway()) {
+    f_service_ << indent() << "}" << endl;
+  }
+  else {
+    f_service_ << indent() << "  TApplicationException x = new TApplicationException" << indent()
+      << "(TApplicationException.ExceptionType.InternalError,\" Internal error.\");"
+      << endl
+      << indent() << "  oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name()
+      << "\", TMessageType.Exception, seqid));" << endl
+      << indent() << "  x.Write(oprot);" << endl
+      << indent() << "}" << endl;
+    f_service_ << indent() << "oprot.WriteMessageEnd();" << endl
+      << indent() << "oprot.Transport.Flush();" << endl;
+  }
+
+  scope_down(f_service_);
+
+  f_service_ << endl;
+}
+
+void t_csharp_generator::generate_csharp_union_reader(std::ostream& out, t_struct* tunion) {
+  // Thanks to THRIFT-1768, we don't need to check for required fields in the union
+  const vector<t_field*>& fields = tunion->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "public static " << tunion->get_name() << " Read(TProtocol iprot)" << endl;
+  scope_up(out);
+
+  out << indent() << "iprot.IncrementRecursionDepth();" << endl;
+  out << indent() << "try" << endl;
+  scope_up(out);
+
+  indent(out) << tunion->get_name() << " retval;" << endl;
+  indent(out) << "iprot.ReadStructBegin();" << endl;
+  indent(out) << "TField field = iprot.ReadFieldBegin();" << endl;
+  // we cannot have the first field be a stop -- we must have a single field defined
+  indent(out) << "if (field.Type == TType.Stop)" << endl;
+  scope_up(out);
+  indent(out) << "iprot.ReadFieldEnd();" << endl;
+  indent(out) << "retval = new ___undefined();" << endl;
+  scope_down(out);
+  indent(out) << "else" << endl;
+  scope_up(out);
+  indent(out) << "switch (field.ID)" << endl;
+  scope_up(out);
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
+    indent_up();
+    indent(out) << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+    indent_up();
+
+    indent(out) << type_name((*f_iter)->get_type()) << " temp;" << endl;
+    generate_deserialize_field(out, (*f_iter), "temp", true);
+    indent(out) << "retval = new " << (*f_iter)->get_name() << "(temp);" << endl;
+
+    indent_down();
+    out << indent() << "} else { " << endl << indent() << "  TProtocolUtil.Skip(iprot, field.Type);"
+        << endl << indent() << "  retval = new ___undefined();" << endl << indent() << "}" << endl
+        << indent() << "break;" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default: " << endl;
+  indent_up();
+  indent(out) << "TProtocolUtil.Skip(iprot, field.Type);" << endl << indent()
+              << "retval = new ___undefined();" << endl;
+  indent(out) << "break;" << endl;
+  indent_down();
+
+  scope_down(out);
+
+  indent(out) << "iprot.ReadFieldEnd();" << endl;
+
+  indent(out) << "if (iprot.ReadFieldBegin().Type != TType.Stop)" << endl;
+  scope_up(out);
+  indent(out) << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl;
+  scope_down(out);
+
+  // end of else for TStop
+  scope_down(out);
+  indent(out) << "iprot.ReadStructEnd();" << endl;
+  indent(out) << "return retval;" << endl;
+  indent_down();
+
+  scope_down(out);
+  out << indent() << "finally" << endl;
+  scope_up(out);
+  out << indent() << "iprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_deserialize_field(ostream& out,
+                                                    t_field* tfield,
+                                                    string prefix,
+                                                    bool is_propertyless) {
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + (is_propertyless ? "" : prop_name(tfield));
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << name << " = ";
+
+    if (type->is_enum()) {
+      out << "(" << type_name(type, false, true) << ")";
+    }
+
+    out << "iprot.";
+
+    if (type->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot serialize void field in a struct: " + name;
+        break;
+      case t_base_type::TYPE_STRING:
+        if (type->is_binary()) {
+          out << "ReadBinary();";
+        } else {
+          out << "ReadString();";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "ReadBool();";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "ReadByte();";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "ReadI16();";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "ReadI32();";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "ReadI64();";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "ReadDouble();";
+        break;
+      default:
+        throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "ReadI32();";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+void t_csharp_generator::generate_deserialize_struct(ostream& out,
+                                                     t_struct* tstruct,
+                                                     string prefix) {
+  if (union_ && tstruct->is_union()) {
+    out << indent() << prefix << " = " << type_name(tstruct) << ".Read(iprot);" << endl;
+  } else {
+    out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << indent()
+        << prefix << ".Read(iprot);" << endl;
+  }
+}
+
+void t_csharp_generator::generate_deserialize_container(ostream& out,
+                                                        t_type* ttype,
+                                                        string prefix) {
+  scope_up(out);
+
+  string obj;
+
+  if (ttype->is_map()) {
+    obj = tmp("_map");
+  } else if (ttype->is_set()) {
+    obj = tmp("_set");
+  } else if (ttype->is_list()) {
+    obj = tmp("_list");
+  }
+
+  indent(out) << prefix << " = new " << type_name(ttype, false, true) << "();" << endl;
+  if (ttype->is_map()) {
+    out << indent() << "TMap " << obj << " = iprot.ReadMapBegin();" << endl;
+  } else if (ttype->is_set()) {
+    out << indent() << "TSet " << obj << " = iprot.ReadSetBegin();" << endl;
+  } else if (ttype->is_list()) {
+    out << indent() << "TList " << obj << " = iprot.ReadListBegin();" << endl;
+  }
+
+  string i = tmp("_i");
+  indent(out) << "for( int " << i << " = 0; " << i << " < " << obj << ".Count"
+              << "; "
+              << "++" << i << ")" << endl;
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "iprot.ReadMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot.ReadSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "iprot.ReadListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+void t_csharp_generator::generate_deserialize_map_element(ostream& out,
+                                                          t_map* tmap,
+                                                          string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) << declare_field(&fkey) << endl;
+  indent(out) << declare_field(&fval) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) << prefix << "[" << key << "] = " << val << ";" << endl;
+}
+
+void t_csharp_generator::generate_deserialize_set_element(ostream& out,
+                                                          t_set* tset,
+                                                          string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_csharp_generator::generate_deserialize_list_element(ostream& out,
+                                                           t_list* tlist,
+                                                           string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_csharp_generator::generate_serialize_field(ostream& out,
+                                                  t_field* tfield,
+                                                  string prefix,
+                                                  bool is_element,
+                                                  bool is_propertyless) {
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  string name = prefix + (is_propertyless ? "" : prop_name(tfield));
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << "oprot.";
+
+    string nullable_name = nullable_ && !is_element && !field_is_required(tfield) ? name + ".Value"
+                                                                                  : name;
+
+    if (type->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot serialize void field in a struct: " + name;
+        break;
+      case t_base_type::TYPE_STRING:
+        if (type->is_binary()) {
+          out << "WriteBinary(";
+        } else {
+          out << "WriteString(";
+        }
+        out << name << ");";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "WriteBool(" << nullable_name << ");";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "WriteByte(" << nullable_name << ");";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "WriteI16(" << nullable_name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "WriteI32(" << nullable_name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "WriteI64(" << nullable_name << ");";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "WriteDouble(" << nullable_name << ");";
+        break;
+      default:
+        throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "WriteI32((int)" << nullable_name << ");";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+void t_csharp_generator::generate_serialize_struct(ostream& out,
+                                                   t_struct* tstruct,
+                                                   string prefix) {
+  (void)tstruct;
+  out << indent() << prefix << ".Write(oprot);" << endl;
+}
+
+void t_csharp_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot.WriteMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type())
+                << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix
+                << ".Count));" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.WriteSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type())
+                << ", " << prefix << ".Count));" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.WriteListBegin(new TList("
+                << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".Count));"
+                << endl;
+  }
+
+  string iter = tmp("_iter");
+  if (ttype->is_map()) {
+    indent(out) << "foreach (" << type_name(((t_map*)ttype)->get_key_type()) << " " << iter
+                << " in " << prefix << ".Keys)";
+  } else if (ttype->is_set()) {
+    indent(out) << "foreach (" << type_name(((t_set*)ttype)->get_elem_type()) << " " << iter
+                << " in " << prefix << ")";
+  } else if (ttype->is_list()) {
+    indent(out) << "foreach (" << type_name(((t_list*)ttype)->get_elem_type()) << " " << iter
+                << " in " << prefix << ")";
+  }
+
+  out << endl;
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+  }
+
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot.WriteMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.WriteSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.WriteListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+void t_csharp_generator::generate_serialize_map_element(ostream& out,
+                                                        t_map* tmap,
+                                                        string iter,
+                                                        string map) {
+  t_field kfield(tmap->get_key_type(), iter);
+  generate_serialize_field(out, &kfield, "", true);
+  t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
+  generate_serialize_field(out, &vfield, "", true);
+}
+
+void t_csharp_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "", true);
+}
+
+void t_csharp_generator::generate_serialize_list_element(ostream& out,
+                                                         t_list* tlist,
+                                                         string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "", true);
+}
+
+void t_csharp_generator::generate_property(ostream& out,
+                                           t_field* tfield,
+                                           bool isPublic,
+                                           bool generateIsset) {
+  generate_csharp_property(out, tfield, isPublic, generateIsset, "_");
+}
+void t_csharp_generator::generate_csharp_property(ostream& out,
+                                                  t_field* tfield,
+                                                  bool isPublic,
+                                                  bool generateIsset,
+                                                  std::string fieldPrefix) {
+  if ((serialize_ || wcf_) && isPublic) {
+    indent(out) << "[DataMember(Order = 0)]" << endl;
+  }
+  bool has_default = field_has_default(tfield);
+  bool is_required = field_is_required(tfield);
+  if ((nullable_ && !has_default) || (is_required)) {
+    indent(out) << (isPublic ? "public " : "private ")
+                << type_name(tfield->get_type(), false, false, true, is_required) << " "
+                << prop_name(tfield) << " { get; set; }" << endl;
+  } else {
+    indent(out) << (isPublic ? "public " : "private ")
+                << type_name(tfield->get_type(), false, false, true) << " " << prop_name(tfield)
+                << endl;
+    scope_up(out);
+    indent(out) << "get" << endl;
+    scope_up(out);
+    bool use_nullable = false;
+    if (nullable_) {
+      t_type* ttype = tfield->get_type();
+      while (ttype->is_typedef()) {
+        ttype = ((t_typedef*)ttype)->get_type();
+      }
+      if (ttype->is_base_type()) {
+        use_nullable = ((t_base_type*)ttype)->get_base() != t_base_type::TYPE_STRING;
+      } else if (ttype->is_enum()) {
+        use_nullable = true;
+      }
+    }
+    indent(out) << "return " << fieldPrefix + tfield->get_name() << ";" << endl;
+    scope_down(out);
+    indent(out) << "set" << endl;
+    scope_up(out);
+    if (use_nullable) {
+      if (generateIsset) {
+        indent(out) << "__isset." << normalize_name(tfield->get_name()) << " = value.HasValue;"
+                    << endl;
+      }
+      indent(out) << "if (value.HasValue) this." << fieldPrefix + tfield->get_name()
+                  << " = value.Value;" << endl;
+    } else {
+      if (generateIsset) {
+        indent(out) << "__isset." << normalize_name(tfield->get_name()) << " = true;" << endl;
+      }
+      indent(out) << "this." << fieldPrefix + tfield->get_name() << " = value;" << endl;
+    }
+    scope_down(out);
+    scope_down(out);
+  }
+  out << endl;
+}
+
+std::string t_csharp_generator::make_valid_csharp_identifier(std::string const& fromName) {
+  std::string str = fromName;
+  if (str.empty()) {
+    return str;
+  }
+
+  // tests rely on this
+  assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
+
+  // if the first letter is a number, we add an additional underscore in front of it
+  char c = str.at(0);
+  if (('0' <= c) && (c <= '9')) {
+    str = "_" + str;
+  }
+
+  // following chars: letter, number or underscore
+  for (size_t i = 0; i < str.size(); ++i) {
+    c = str.at(i);
+    if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9'))
+        && ('_' != c)) {
+      str.replace(i, 1, "_");
+    }
+  }
+
+  return str;
+}
+
+void t_csharp_generator::cleanup_member_name_mapping(void* scope) {
+  if( member_mapping_scopes.empty()) {
+    throw "internal error: cleanup_member_name_mapping() no scope active";
+  }
+
+  member_mapping_scope& active = member_mapping_scopes.back();
+  if (active.scope_member != scope) {
+    throw "internal error: cleanup_member_name_mapping() called for wrong struct";
+  }
+
+  member_mapping_scopes.pop_back();
+}
+
+string t_csharp_generator::get_mapped_member_name(string name) {
+  if( ! member_mapping_scopes.empty()) {
+    member_mapping_scope& active = member_mapping_scopes.back();
+    map<string, string>::iterator iter = active.mapping_table.find(name);
+    if (active.mapping_table.end() != iter) {
+      return iter->second;
+    }
+  }
+
+  pverbose("no mapping for member %s\n", name.c_str());
+  return name;
+}
+
+void t_csharp_generator::prepare_member_name_mapping(t_struct* tstruct) {
+  prepare_member_name_mapping(tstruct, tstruct->get_members(), tstruct->get_name());
+}
+
+void t_csharp_generator::prepare_member_name_mapping(void* scope,
+                                                     const vector<t_field*>& members,
+                                                     const string& structname) {
+  // begin new scope
+  member_mapping_scope dummy;
+  dummy.scope_member = 0;
+  member_mapping_scopes.push_back(dummy);
+  member_mapping_scope& active = member_mapping_scopes.back();
+  active.scope_member = scope;
+
+  // current C# generator policy:
+  // - prop names are always rendered with an Uppercase first letter
+  // - struct names are used as given
+  std::set<std::string> used_member_names;
+  vector<t_field*>::const_iterator iter;
+
+  // prevent name conflicts with struct (CS0542 error)
+  used_member_names.insert(structname);
+
+  // prevent name conflicts with known methods (THRIFT-2942)
+  used_member_names.insert("Read");
+  used_member_names.insert("Write");
+
+  for (iter = members.begin(); iter != members.end(); ++iter) {
+    string oldname = (*iter)->get_name();
+    string newname = prop_name(*iter, true);
+    while (true) {
+
+      // new name conflicts with another member
+      if (used_member_names.find(newname) != used_member_names.end()) {
+        pverbose("struct %s: member %s conflicts with another member\n",
+                 structname.c_str(),
+                 newname.c_str());
+        newname += '_';
+        continue;
+      }
+
+      // add always, this helps us to detect edge cases like
+      // different spellings ("foo" and "Foo") within the same struct
+      pverbose("struct %s: member mapping %s => %s\n",
+               structname.c_str(),
+               oldname.c_str(),
+               newname.c_str());
+      active.mapping_table[oldname] = newname;
+      used_member_names.insert(newname);
+      break;
+    }
+  }
+}
+
+std::string t_csharp_generator::prop_name(t_field* tfield, bool suppress_mapping) {
+  string name(tfield->get_name());
+  if (suppress_mapping) {
+    name[0] = toupper(name[0]);
+  } else {
+    name = get_mapped_member_name(name);
+  }
+  return name;
+}
+
+string t_csharp_generator::type_name(t_type* ttype,
+                                     bool in_container,
+                                     bool in_init,
+                                     bool in_param,
+                                     bool is_required) {
+  (void)in_init;
+  while (ttype->is_typedef()) {
+    ttype = ((t_typedef*)ttype)->get_type();
+  }
+
+  if (ttype->is_base_type()) {
+    return base_type_name((t_base_type*)ttype, in_container, in_param, is_required);
+  } else if (ttype->is_map()) {
+    t_map* tmap = (t_map*)ttype;
+    return "Dictionary<" + type_name(tmap->get_key_type(), true) + ", "
+           + type_name(tmap->get_val_type(), true) + ">";
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*)ttype;
+    return "THashSet<" + type_name(tset->get_elem_type(), true) + ">";
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*)ttype;
+    return "List<" + type_name(tlist->get_elem_type(), true) + ">";
+  }
+
+  t_program* program = ttype->get_program();
+  string postfix = (!is_required && nullable_ && in_param && ttype->is_enum()) ? "?" : "";
+  if (program != NULL && program != program_) {
+    string ns = program->get_namespace("csharp");
+    if (!ns.empty()) {
+      return ns + "." + normalize_name(ttype->get_name()) + postfix;
+    }
+  }
+
+  return normalize_name(ttype->get_name()) + postfix;
+}
+
+string t_csharp_generator::base_type_name(t_base_type* tbase,
+                                          bool in_container,
+                                          bool in_param,
+                                          bool is_required) {
+  (void)in_container;
+  string postfix = (!is_required && nullable_ && in_param) ? "?" : "";
+  switch (tbase->get_base()) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    if (tbase->is_binary()) {
+      return "byte[]";
+    } else {
+      return "string";
+    }
+  case t_base_type::TYPE_BOOL:
+    return "bool" + postfix;
+  case t_base_type::TYPE_I8:
+    return "sbyte" + postfix;
+  case t_base_type::TYPE_I16:
+    return "short" + postfix;
+  case t_base_type::TYPE_I32:
+    return "int" + postfix;
+  case t_base_type::TYPE_I64:
+    return "long" + postfix;
+  case t_base_type::TYPE_DOUBLE:
+    return "double" + postfix;
+  default:
+    throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase->get_base());
+  }
+}
+
+string t_csharp_generator::declare_field(t_field* tfield, bool init, std::string prefix) {
+  string result = type_name(tfield->get_type()) + " " + prefix + tfield->get_name();
+  if (init) {
+    t_type* ttype = tfield->get_type();
+    while (ttype->is_typedef()) {
+      ttype = ((t_typedef*)ttype)->get_type();
+    }
+    if (ttype->is_base_type() && field_has_default(tfield)) {
+      std::ofstream dummy;
+      result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
+    } else if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "NO T_VOID CONSTRUCT";
+      case t_base_type::TYPE_STRING:
+        result += " = null";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = false";
+        break;
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = (double)0";
+        break;
+      }
+    } else if (ttype->is_enum()) {
+      result += " = (" + type_name(ttype, false, true) + ")0";
+    } else if (ttype->is_container()) {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    } else {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    }
+  }
+  return result + ";";
+}
+
+string t_csharp_generator::function_signature(t_function* tfunction, string prefix) {
+  t_type* ttype = tfunction->get_returntype();
+  return type_name(ttype) + " " + normalize_name(prefix + tfunction->get_name()) + "("
+         + argument_list(tfunction->get_arglist()) + ")";
+}
+
+string t_csharp_generator::function_signature_async_begin(t_function* tfunction, string prefix) {
+  string comma = (tfunction->get_arglist()->get_members().size() > 0 ? ", " : "");
+  return "IAsyncResult " + normalize_name(prefix + tfunction->get_name())
+         + "(AsyncCallback callback, object state" + comma + 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) + " " + normalize_name(prefix + tfunction->get_name())
+         + "(IAsyncResult asyncResult)";
+}
+
+string t_csharp_generator::function_signature_async(t_function* tfunction, string prefix) {
+  t_type* ttype = tfunction->get_returntype();
+  string task = "Task";
+  if (!ttype->is_void())
+    task += "<" + type_name(ttype) + ">";
+  return task + " " + normalize_name(prefix + tfunction->get_name()) + "Async("
+         + argument_list(tfunction->get_arglist()) + ")";
+}
+
+string t_csharp_generator::argument_list(t_struct* tstruct) {
+  string result = "";
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      result += ", ";
+    }
+    result += type_name((*f_iter)->get_type()) + " " + normalize_name((*f_iter)->get_name());
+  }
+  return result;
+}
+
+string t_csharp_generator::type_to_enum(t_type* type) {
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "NO T_VOID CONSTRUCT";
+    case t_base_type::TYPE_STRING:
+      return "TType.String";
+    case t_base_type::TYPE_BOOL:
+      return "TType.Bool";
+    case t_base_type::TYPE_I8:
+      return "TType.Byte";
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.Double";
+    }
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.Struct";
+  } else if (type->is_map()) {
+    return "TType.Map";
+  } else if (type->is_set()) {
+    return "TType.Set";
+  } else if (type->is_list()) {
+    return "TType.List";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+void t_csharp_generator::generate_csharp_docstring_comment(ostream& out, string contents) {
+  generate_docstring_comment(out, "/// <summary>\n", "/// ", contents, "/// </summary>\n");
+}
+
+void t_csharp_generator::generate_csharp_doc(ostream& out, t_field* field) {
+  if (field->get_type()->is_enum()) {
+    string combined_message = field->get_doc() + "\n<seealso cref=\""
+                              + get_enum_class_name(field->get_type()) + "\"/>";
+    generate_csharp_docstring_comment(out, combined_message);
+  } else {
+    generate_csharp_doc(out, (t_doc*)field);
+  }
+}
+
+void t_csharp_generator::generate_csharp_doc(ostream& out, t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_csharp_docstring_comment(out, tdoc->get_doc());
+  }
+}
+
+void t_csharp_generator::generate_csharp_doc(ostream& out, t_function* tfunction) {
+  if (tfunction->has_doc()) {
+    stringstream ps;
+    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+    vector<t_field*>::const_iterator p_iter;
+    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+      t_field* p = *p_iter;
+      ps << "\n<param name=\"" << p->get_name() << "\">";
+      if (p->has_doc()) {
+        std::string str = p->get_doc();
+        str.erase(std::remove(str.begin(), str.end(), '\n'),
+                  str.end()); // remove the newlines that appear from the parser
+        ps << str;
+      }
+      ps << "</param>";
+    }
+    generate_docstring_comment(out,
+                               "",
+                               "/// ",
+                               "<summary>\n" + tfunction->get_doc() + "</summary>" + ps.str(),
+                               "");
+  }
+}
+
+std::string t_csharp_generator::get_enum_class_name(t_type* type) {
+  string package = "";
+  t_program* program = type->get_program();
+  if (program != NULL && program != program_) {
+    package = program->get_namespace("csharp") + ".";
+  }
+  return package + type->get_name();
+}
+
+
+THRIFT_REGISTER_GENERATOR(
+    csharp,
+    "C#",
+    "    async:           Adds Async support using Task.Run.\n"
+    "    wcf:             Adds bindings for WCF to generated classes.\n"
+    "    serial:          Add serialization support to generated classes.\n"
+    "    nullable:        Use nullable types for properties.\n"
+    "    hashcode:        Generate a hashcode and equals implementation for classes.\n"
+    "    union:           Use new union typing, which includes a static read function for union "
+    "types.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_generator.cc b/compiler/cpp/src/thrift/generate/t_generator.cc
index 3059fb1..77afeba 100644
--- a/compiler/cpp/src/thrift/generate/t_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_generator.cc
@@ -234,7 +234,10 @@
   gen_map_t& the_map = get_generator_map();
   gen_map_t::iterator iter = the_map.find(language);
 
-  if ((language == "csharp") || (language == "netcore")) {
+  if (language == "csharp") {
+    pwarning(1, "The '%s' target is deprecated. Consider moving to 'netstd' instead.", language.c_str());
+  }
+  else if (language == "netcore") {
     failure("The '%s' target is no longer available. Use 'netstd' instead.", language.c_str());
   }
   else if (language == "as3") {
diff --git a/compiler/cpp/src/thrift/thriftl.ll b/compiler/cpp/src/thrift/thriftl.ll
index 3773516..bdb4fb0 100644
--- a/compiler/cpp/src/thrift/thriftl.ll
+++ b/compiler/cpp/src/thrift/thriftl.ll
@@ -207,6 +207,7 @@
 "cpp_include"        { return tok_cpp_include;          }
 "cpp_type"           { return tok_cpp_type;             }
 "java_package"       { error_unsupported_namespace_decl("java_package", "java"); /* do nothing */ }
+"csharp_namespace"   { error_unsupported_namespace_decl("csharp"); /* do nothing */ }
 "delphi_namespace"   { error_unsupported_namespace_decl("delphi"); /* do nothing */ }
 "php_namespace"      { error_unsupported_namespace_decl("php"); /* do nothing */ }
 "py_module"          { error_unsupported_namespace_decl("py_module", "py"); /* do nothing */ }
diff --git a/compiler/cpp/tests/CMakeLists.txt b/compiler/cpp/tests/CMakeLists.txt
index 924e167..7798c15 100644
--- a/compiler/cpp/tests/CMakeLists.txt
+++ b/compiler/cpp/tests/CMakeLists.txt
@@ -101,6 +101,7 @@
 THRIFT_ADD_COMPILER(c_glib  "Enable compiler for C with Glib" OFF)
 THRIFT_ADD_COMPILER(cl      "Enable compiler for Common LISP" OFF)
 THRIFT_ADD_COMPILER(cpp     "Enable compiler for C++" OFF)
+THRIFT_ADD_COMPILER(csharp  "Enable compiler for C#" OFF)
 THRIFT_ADD_COMPILER(d       "Enable compiler for D" OFF)
 THRIFT_ADD_COMPILER(dart    "Enable compiler for Dart" OFF)
 THRIFT_ADD_COMPILER(delphi  "Enable compiler for Delphi" OFF)
diff --git a/lib/csharp/Makefile.am b/lib/csharp/Makefile.am
new file mode 100644
index 0000000..cc2bbc9
--- /dev/null
+++ b/lib/csharp/Makefile.am
@@ -0,0 +1,114 @@
+#
+# 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.
+#
+
+SUBDIRS = . test/Multiplex
+
+THRIFTCODE = \
+            src/Collections/THashSet.cs \
+            src/Collections/TCollections.cs \
+            src/Properties/AssemblyInfo.cs \
+            src/Protocol/TAbstractBase.cs \
+            src/Protocol/TBase.cs \
+            src/Protocol/TBase64Utils.cs \
+            src/Protocol/TJSONProtocol.cs \
+            src/Protocol/TProtocolException.cs \
+            src/Protocol/TProtocolFactory.cs \
+            src/Protocol/TList.cs \
+            src/Protocol/TSet.cs \
+            src/Protocol/TMap.cs \
+            src/Protocol/TProtocolUtil.cs \
+            src/Protocol/TMessageType.cs \
+            src/Protocol/TProtocol.cs \
+            src/Protocol/TProtocolDecorator.cs \
+            src/Protocol/TMultiplexedProtocol.cs \
+            src/Protocol/TMultiplexedProcessor.cs \
+            src/Protocol/TType.cs \
+            src/Protocol/TField.cs \
+            src/Protocol/TMessage.cs \
+            src/Protocol/TStruct.cs \
+            src/Protocol/TBinaryProtocol.cs \
+            src/Protocol/TCompactProtocol.cs \
+            src/Server/TThreadedServer.cs \
+            src/Server/TThreadPoolServer.cs \
+            src/Server/TSimpleServer.cs \
+            src/Server/TServer.cs \
+            src/Server/TServerEventHandler.cs \
+            src/Transport/TBufferedTransport.cs \
+            src/Transport/TTransport.cs \
+            src/Transport/TSocket.cs \
+            src/Transport/TSocketVersionizer.cs \
+            src/Transport/TTransportException.cs \
+            src/Transport/TStreamTransport.cs \
+            src/Transport/TFramedTransport.cs \
+            src/Transport/TServerTransport.cs \
+            src/Transport/TServerSocket.cs \
+            src/Transport/TTransportFactory.cs \
+            src/Transport/THttpClient.cs \
+            src/Transport/THttpHandler.cs \
+            src/Transport/TMemoryBuffer.cs \
+            src/Transport/TNamedPipeClientTransport.cs \
+            src/Transport/TNamedPipeServerTransport.cs \
+            src/Transport/TTLSSocket.cs \
+            src/Transport/TTLSServerSocket.cs \
+            src/TProcessor.cs \
+            src/TProcessorFactory.cs \
+            src/TSingletonProcessorFactory.cs \
+            src/TPrototypeProcessorFactory.cs \
+            src/TControllingHandler.cs \
+            src/TException.cs \
+            src/TApplicationException.cs
+
+if MONO_MCS
+export CSC = mcs
+else
+export CSC = gmcs
+endif
+
+if NET_2_0
+export CSC_DEFINES = -d:NET_2_0
+endif
+
+all-local: Thrift.dll Thrift.45.dll
+
+Thrift.dll: $(THRIFTCODE)
+	$(CSC) $(CSC_DEFINES) -out:$@ -target:library -reference:System.Web $(THRIFTCODE)
+
+Thrift.45.dll: $(THRIFTCODE)
+	$(CSC) $(CSC_DEFINES) -out:$@ -target:library -reference:System.Web $(THRIFTCODE)
+
+CLEANFILES = \
+	Thrift.dll \
+	Thrift.45.dll
+
+DISTCLEANFILES = \
+	Makefile.in
+
+EXTRA_DIST = \
+	$(THRIFTCODE) \
+	ThriftMSBuildTask \
+	src/Thrift.csproj \
+	src/Thrift.45.csproj \
+	src/Thrift.sln \
+	src/Net35/ExtensionsNet35.cs \
+	src/Transport/TSilverlightSocket.cs \
+	src/Transport/THttpTaskAsyncHandler.cs \
+	src/TAsyncProcessor.cs \
+	test \
+	coding_standards.md \
+	README.md
diff --git a/lib/csharp/README.md b/lib/csharp/README.md
new file mode 100644
index 0000000..5fc14cb
--- /dev/null
+++ b/lib/csharp/README.md
@@ -0,0 +1,32 @@
+Thrift C# Software Library
+
+Deprecation notice
+=======
+
+Per [THRIFT-4723](https://issues.apache.org/jira/browse/THRIFT-4723), both CSharp and Netcore targets are deprecated 
+and will be removed with the next release. Migrate to the [NetStd language target](../netstd/README.md) instead.
+
+License
+=======
+
+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 Thrift with C#
+====================
+
+Thrift requires Mono >= 1.2.6 or .NET framework >= 3.5
diff --git a/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs b/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f5f0000
--- /dev/null
+++ b/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs
@@ -0,0 +1,60 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+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("ThriftMSBuildTask")]
+[assembly: AssemblyDescription("MSBuild Task to generate csharp from .thrift files, and compile the code into a library: ThriftImpl.dll")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("ThriftMSBuildTask")]
+[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("5095e09d-7b95-4be1-b250-e1c1db1c485e")]
+
+// 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.14.0.*")]
+[assembly: AssemblyFileVersion("0.14.0.*")]
diff --git a/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs b/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs
new file mode 100644
index 0000000..4e6d301
--- /dev/null
+++ b/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs
@@ -0,0 +1,246 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Microsoft.Build.Tasks;
+using System.IO;
+using System.Diagnostics;
+
+namespace ThriftMSBuildTask
+{
+    /// <summary>
+    /// MSBuild Task to generate csharp from .thrift files, and compile the code into a library: ThriftImpl.dll
+    /// </summary>
+    public class ThriftBuild : Task
+    {
+        /// <summary>
+        /// The full path to the thrift.exe compiler
+        /// </summary>
+        [Required]
+        public ITaskItem ThriftExecutable
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// The full path to a thrift.dll C# library
+        /// </summary>
+        [Required]
+        public ITaskItem ThriftLibrary
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// A direcotry containing .thrift files
+        /// </summary>
+        [Required]
+        public ITaskItem ThriftDefinitionDir
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// The name of the auto-gen and compiled thrift library. It will placed in
+        /// the same directory as ThriftLibrary
+        /// </summary>
+        [Required]
+        public ITaskItem OutputName
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// The full path to the compiled ThriftLibrary. This allows msbuild tasks to use this
+        /// output as a variable for use elsewhere.
+        /// </summary>
+        [Output]
+        public ITaskItem ThriftImplementation
+        {
+            get { return thriftImpl; }
+        }
+
+        private ITaskItem thriftImpl;
+        private const string lastCompilationName = "LAST_COMP_TIMESTAMP";
+
+        //use the Message Build Task to write something to build log
+        private void LogMessage(string text, MessageImportance importance)
+        {
+            Message m = new Message();
+            m.Text = text;
+            m.Importance = importance.ToString();
+            m.BuildEngine = this.BuildEngine;
+            m.Execute();
+        }
+
+        //recursively find .cs files in srcDir, paths should initially be non-null and empty
+        private void FindSourcesHelper(string srcDir, List<string> paths)
+        {
+            string[] files = Directory.GetFiles(srcDir, "*.cs");
+            foreach (string f in files)
+            {
+                paths.Add(f);
+            }
+            string[] dirs = Directory.GetDirectories(srcDir);
+            foreach (string dir in dirs)
+            {
+                FindSourcesHelper(dir, paths);
+            }
+        }
+
+        /// <summary>
+        /// Quote paths with spaces
+        /// </summary>
+        private string SafePath(string path)
+        {
+            if (path.Contains(' ') && !path.StartsWith("\""))
+            {
+                return "\"" + path + "\"";
+            }
+            return path;
+        }
+
+        private ITaskItem[] FindSources(string srcDir)
+        {
+            List<string> files = new List<string>();
+            FindSourcesHelper(srcDir, files);
+            ITaskItem[] items = new ITaskItem[files.Count];
+            for (int i = 0; i < items.Length; i++)
+            {
+                items[i] = new TaskItem(files[i]);
+            }
+            return items;
+        }
+
+        private string LastWriteTime(string defDir)
+        {
+            string[] files = Directory.GetFiles(defDir, "*.thrift");
+            DateTime d = (new DirectoryInfo(defDir)).LastWriteTime;
+            foreach(string file in files)
+            {
+                FileInfo f = new FileInfo(file);
+                DateTime curr = f.LastWriteTime;
+                if (DateTime.Compare(curr, d) > 0)
+                {
+                    d = curr;
+                }
+            }
+            return d.ToFileTimeUtc().ToString();
+        }
+
+        public override bool Execute()
+        {
+            string defDir = SafePath(ThriftDefinitionDir.ItemSpec);
+            //look for last compilation timestamp
+            string lastBuildPath = Path.Combine(defDir, lastCompilationName);
+            DirectoryInfo defDirInfo = new DirectoryInfo(defDir);
+            string lastWrite = LastWriteTime(defDir);
+            if (File.Exists(lastBuildPath))
+            {
+                string lastComp = File.ReadAllText(lastBuildPath);
+                //don't recompile if the thrift library has been updated since lastComp
+                FileInfo f = new FileInfo(ThriftLibrary.ItemSpec);
+                string thriftLibTime = f.LastWriteTimeUtc.ToFileTimeUtc().ToString();
+                if (lastComp.CompareTo(thriftLibTime) < 0)
+                {
+                    //new thrift library, do a compile
+                    lastWrite = thriftLibTime;
+                }
+                else if (lastComp == lastWrite || (lastComp == thriftLibTime && lastComp.CompareTo(lastWrite) > 0))
+                {
+                    //the .thrift dir hasn't been written to since last compilation, don't need to do anything
+                    LogMessage("ThriftImpl up-to-date", MessageImportance.High);
+                    return true;
+                }
+            }
+
+            //find the directory of the thriftlibrary (that's where output will go)
+            FileInfo thriftLibInfo = new FileInfo(SafePath(ThriftLibrary.ItemSpec));
+            string thriftDir = thriftLibInfo.Directory.FullName;
+
+            string genDir = Path.Combine(thriftDir, "gen-csharp");
+            if (Directory.Exists(genDir))
+            {
+                try
+                {
+                    Directory.Delete(genDir, true);
+                }
+                catch { /*eh i tried, just over-write now*/}
+            }
+
+            //run the thrift executable to generate C#
+            foreach (string thriftFile in Directory.GetFiles(defDir, "*.thrift"))
+            {
+                LogMessage("Generating code for: " + thriftFile, MessageImportance.Normal);
+                Process p = new Process();
+                p.StartInfo.FileName = SafePath(ThriftExecutable.ItemSpec);
+                p.StartInfo.Arguments = "--gen csharp -o " + SafePath(thriftDir) + " -r " + thriftFile;
+                p.StartInfo.UseShellExecute = false;
+                p.StartInfo.CreateNoWindow = true;
+                p.StartInfo.RedirectStandardOutput = false;
+                p.Start();
+                p.WaitForExit();
+                if (p.ExitCode != 0)
+                {
+                    LogMessage("thrift.exe failed to compile " + thriftFile, MessageImportance.High);
+                    return false;
+                }
+                if (p.ExitCode != 0)
+                {
+                    LogMessage("thrift.exe failed to compile " + thriftFile, MessageImportance.High);
+                    return false;
+                }
+            }
+
+            Csc csc = new Csc();
+            csc.TargetType = "library";
+            csc.References = new ITaskItem[] { new TaskItem(ThriftLibrary.ItemSpec) };
+            csc.EmitDebugInformation = true;
+            string outputPath = Path.Combine(thriftDir, OutputName.ItemSpec);
+            csc.OutputAssembly = new TaskItem(outputPath);
+            csc.Sources = FindSources(Path.Combine(thriftDir, "gen-csharp"));
+            csc.BuildEngine = this.BuildEngine;
+            LogMessage("Compiling generated cs...", MessageImportance.Normal);
+            if (!csc.Execute())
+            {
+                return false;
+            }
+
+            //write file to defDir to indicate a build was successfully completed
+            File.WriteAllText(lastBuildPath, lastWrite);
+
+            thriftImpl = new TaskItem(outputPath);
+
+            return true;
+        }
+    }
+}
diff --git a/lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj b/lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj
new file mode 100644
index 0000000..2589970
--- /dev/null
+++ b/lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{EC0A0231-66EA-4593-A792-C6CA3BB8668E}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ThriftMSBuildTask</RootNamespace>
+    <AssemblyName>ThriftMSBuildTask</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>0.14.0.0</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.Build.Framework" />
+    <Reference Include="Microsoft.Build.Tasks" />
+    <Reference Include="Microsoft.Build.Utilities" />
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ThriftBuild.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
diff --git a/lib/csharp/coding_standards.md b/lib/csharp/coding_standards.md
new file mode 100644
index 0000000..dc87190
--- /dev/null
+++ b/lib/csharp/coding_standards.md
@@ -0,0 +1,6 @@
+## C# Coding Standards
+
+Please follow:
+ * [Thrift General Coding Standards](/doc/coding_standards.md)
+ * [MSDN C# Coding Conventions](http://msdn.microsoft.com/en-us/library/ff926074.aspx)
+ * [C# Coding Guidelines](http://csharpguidelines.codeplex.com/)
diff --git a/lib/csharp/src/Collections/TCollections.cs b/lib/csharp/src/Collections/TCollections.cs
new file mode 100644
index 0000000..84afb6a
--- /dev/null
+++ b/lib/csharp/src/Collections/TCollections.cs
@@ -0,0 +1,94 @@
+/**
+ * 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;
+using System.Collections;
+
+namespace Thrift.Collections
+{
+    public class TCollections
+    {
+        /// <summary>
+        /// This will return true if the two collections are value-wise the same.
+        /// If the collection contains a collection, the collections will be compared using this method.
+        /// </summary>
+        public static bool Equals (IEnumerable first, IEnumerable second)
+        {
+            if (first == null && second == null)
+            {
+                return true;
+            }
+            if (first == null || second == null)
+            {
+                return false;
+            }
+            IEnumerator fiter = first.GetEnumerator ();
+            IEnumerator siter = second.GetEnumerator ();
+
+            bool fnext = fiter.MoveNext ();
+            bool snext = siter.MoveNext ();
+            while (fnext && snext)
+            {
+                IEnumerable fenum = fiter.Current as IEnumerable;
+                IEnumerable senum = siter.Current as IEnumerable;
+                if (fenum != null && senum != null)
+                {
+                    if (!Equals(fenum, senum))
+                    {
+                        return false;
+                    }
+                }
+                else if (fenum == null ^ senum == null)
+                {
+                    return false;
+                }
+                else if (!Equals(fiter.Current, siter.Current))
+                {
+                    return false;
+                }
+                fnext = fiter.MoveNext();
+                snext = siter.MoveNext();
+            }
+
+            return fnext == snext;
+        }
+
+        /// <summary>
+        /// This returns a hashcode based on the value of the enumerable.
+        /// </summary>
+        public static int GetHashCode (IEnumerable enumerable)
+        {
+            if (enumerable == null)
+            {
+                return 0;
+            }
+
+            int hashcode = 0;
+            foreach (object obj in enumerable)
+            {
+                IEnumerable enum2 = obj as IEnumerable;
+                int objHash = enum2 == null ? obj.GetHashCode () : GetHashCode (enum2);
+                unchecked
+                {
+                    hashcode = (hashcode * 397) ^ (objHash);
+                }
+            }
+            return hashcode;
+        }
+    }
+}
diff --git a/lib/csharp/src/Collections/THashSet.cs b/lib/csharp/src/Collections/THashSet.cs
new file mode 100644
index 0000000..e29271a
--- /dev/null
+++ b/lib/csharp/src/Collections/THashSet.cs
@@ -0,0 +1,160 @@
+/**
+ * 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;
+using System.Collections;
+using System.Collections.Generic;
+
+#if SILVERLIGHT
+using System.Runtime.Serialization;
+#endif
+
+namespace Thrift.Collections
+{
+#if SILVERLIGHT
+    [DataContract]
+#else
+    [Serializable]
+#endif
+    public class THashSet<T> : ICollection<T>
+    {
+#if NET_2_0 || SILVERLIGHT
+#if SILVERLIGHT
+        [DataMember]
+#endif
+        TDictSet<T> set = new TDictSet<T>();
+#else
+        HashSet<T> set = new HashSet<T>();
+#endif
+        public int Count
+        {
+            get { return set.Count; }
+        }
+
+        public bool IsReadOnly
+        {
+            get { return false; }
+        }
+
+        public void Add(T item)
+        {
+            set.Add(item);
+        }
+
+        public void Clear()
+        {
+            set.Clear();
+        }
+
+        public bool Contains(T item)
+        {
+            return set.Contains(item);
+        }
+
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            set.CopyTo(array, arrayIndex);
+        }
+
+        public IEnumerator GetEnumerator()
+        {
+            return set.GetEnumerator();
+        }
+
+        IEnumerator<T> IEnumerable<T>.GetEnumerator()
+        {
+            return ((IEnumerable<T>)set).GetEnumerator();
+        }
+
+        public bool Remove(T item)
+        {
+            return set.Remove(item);
+        }
+
+#if NET_2_0 || SILVERLIGHT
+#if SILVERLIGHT
+        [DataContract]
+#endif
+        private class TDictSet<V> : ICollection<V>
+        {
+#if SILVERLIGHT
+            [DataMember]
+#endif
+            Dictionary<V, TDictSet<V>> dict = new Dictionary<V, TDictSet<V>>();
+
+            public int Count
+            {
+                get { return dict.Count; }
+            }
+
+            public bool IsReadOnly
+            {
+                get { return false; }
+            }
+
+            public IEnumerator GetEnumerator()
+            {
+                return ((IEnumerable)dict.Keys).GetEnumerator();
+            }
+
+            IEnumerator<V> IEnumerable<V>.GetEnumerator()
+            {
+                return dict.Keys.GetEnumerator();
+            }
+
+            public bool Add(V item)
+            {
+                if (!dict.ContainsKey(item))
+                {
+                    dict[item] = this;
+                    return true;
+                }
+
+                return false;
+            }
+
+            void ICollection<V>.Add(V item)
+            {
+                Add(item);
+            }
+
+            public void Clear()
+            {
+                dict.Clear();
+            }
+
+            public bool Contains(V item)
+            {
+                return dict.ContainsKey(item);
+            }
+
+            public void CopyTo(V[] array, int arrayIndex)
+            {
+                dict.Keys.CopyTo(array, arrayIndex);
+            }
+
+            public bool Remove(V item)
+            {
+                return dict.Remove(item);
+            }
+        }
+#endif
+    }
+
+}
diff --git a/lib/csharp/src/Net35/ExtensionsNet35.cs b/lib/csharp/src/Net35/ExtensionsNet35.cs
new file mode 100644
index 0000000..73a4232
--- /dev/null
+++ b/lib/csharp/src/Net35/ExtensionsNet35.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+#if (!NET45)
+namespace Thrift
+{
+    static class StreamExtensionsNet35
+    {
+        // CopyTo() has been added in 4.0
+        public static long CopyTo(this Stream source, Stream target)
+        {
+            byte[] buffer = new byte[8192];  // multiple of 4096
+            long nTotal = 0;
+            while (true)
+            {
+                int nRead = source.Read(buffer, 0, buffer.Length);
+                if (nRead <= 0)  // done?
+                    return nTotal;
+
+                target.Write(buffer, 0, nRead);
+                nTotal += nRead;
+            }
+        }
+    }
+
+}
+#endif
+
diff --git a/lib/csharp/src/Properties/AssemblyInfo.cs b/lib/csharp/src/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c8f51b5
--- /dev/null
+++ b/lib/csharp/src/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/**
+ * 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")]
+[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("df3f8ef0-e0a3-4c86-a65b-8ec84e016b1d")]
+
+// 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("0.14.0.0")]
+[assembly: AssemblyFileVersion("0.14.0.0")]
diff --git a/lib/csharp/src/Protocol/TAbstractBase.cs b/lib/csharp/src/Protocol/TAbstractBase.cs
new file mode 100644
index 0000000..f5a61cd
--- /dev/null
+++ b/lib/csharp/src/Protocol/TAbstractBase.cs
@@ -0,0 +1,29 @@
+/**
+ * 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.
+ */
+
+namespace Thrift.Protocol
+{
+    public interface TAbstractBase
+    {
+        /// <summary>
+        /// Writes the objects out to the protocol.
+        /// </summary>
+        void Write(TProtocol tProtocol);
+    }
+}
diff --git a/lib/csharp/src/Protocol/TBase.cs b/lib/csharp/src/Protocol/TBase.cs
new file mode 100644
index 0000000..411e4d9
--- /dev/null
+++ b/lib/csharp/src/Protocol/TBase.cs
@@ -0,0 +1,29 @@
+/**
+ * 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.
+ */
+
+namespace Thrift.Protocol
+{
+    public interface TBase : TAbstractBase
+    {
+        /// <summary>
+        /// Reads the TObject from the given input protocol.
+        /// </summary>
+        void Read(TProtocol tProtocol);
+    }
+}
diff --git a/lib/csharp/src/Protocol/TBase64Utils.cs b/lib/csharp/src/Protocol/TBase64Utils.cs
new file mode 100644
index 0000000..9eaaebd
--- /dev/null
+++ b/lib/csharp/src/Protocol/TBase64Utils.cs
@@ -0,0 +1,100 @@
+/**
+ * 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;
+
+namespace Thrift.Protocol
+{
+    internal static class TBase64Utils
+    {
+        internal const string ENCODE_TABLE =
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+        internal static void encode(byte[] src, int srcOff, int len, byte[] dst,
+                                int dstOff)
+        {
+            dst[dstOff] = (byte)ENCODE_TABLE[(src[srcOff] >> 2) & 0x3F];
+            if (len == 3)
+            {
+                dst[dstOff + 1] =
+                    (byte)ENCODE_TABLE[
+                        ((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+                dst[dstOff + 2] =
+                    (byte)ENCODE_TABLE[
+                        ((src[srcOff + 1] << 2) & 0x3C) | ((src[srcOff + 2] >> 6) & 0x03)];
+                dst[dstOff + 3] =
+                    (byte)ENCODE_TABLE[src[srcOff + 2] & 0x3F];
+            }
+            else if (len == 2)
+            {
+                dst[dstOff + 1] =
+                    (byte)ENCODE_TABLE[
+                        ((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+                dst[dstOff + 2] =
+                    (byte)ENCODE_TABLE[(src[srcOff + 1] << 2) & 0x3C];
+
+            }
+            else
+            { // len == 1) {
+                dst[dstOff + 1] =
+                    (byte)ENCODE_TABLE[(src[srcOff] << 4) & 0x30];
+            }
+        }
+
+        private static int[] DECODE_TABLE = {
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
+            52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
+            -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
+            15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
+            -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
+            41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+        };
+
+        internal static void decode(byte[] src, int srcOff, int len, byte[] dst,
+                                 int dstOff)
+        {
+            dst[dstOff] = (byte)
+                ((DECODE_TABLE[src[srcOff] & 0x0FF] << 2) |
+                (DECODE_TABLE[src[srcOff + 1] & 0x0FF] >> 4));
+            if (len > 2)
+            {
+                dst[dstOff + 1] = (byte)
+                    (((DECODE_TABLE[src[srcOff + 1] & 0x0FF] << 4) & 0xF0) |
+                    (DECODE_TABLE[src[srcOff + 2] & 0x0FF] >> 2));
+                if (len > 3)
+                {
+                    dst[dstOff + 2] = (byte)
+                        (((DECODE_TABLE[src[srcOff + 2] & 0x0FF] << 6) & 0xC0) |
+                        DECODE_TABLE[src[srcOff + 3] & 0x0FF]);
+                }
+            }
+        }
+
+    }
+}
diff --git a/lib/csharp/src/Protocol/TBinaryProtocol.cs b/lib/csharp/src/Protocol/TBinaryProtocol.cs
new file mode 100644
index 0000000..a4faa94
--- /dev/null
+++ b/lib/csharp/src/Protocol/TBinaryProtocol.cs
@@ -0,0 +1,395 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Text;
+using Thrift.Transport;
+
+namespace Thrift.Protocol
+{
+    public class TBinaryProtocol : TProtocol
+    {
+        protected const uint VERSION_MASK = 0xffff0000;
+        protected const uint VERSION_1 = 0x80010000;
+
+        protected bool strictRead_ = false;
+        protected bool strictWrite_ = true;
+
+        #region BinaryProtocol Factory
+
+        public class Factory : TProtocolFactory
+        {
+            protected bool strictRead_ = false;
+            protected bool strictWrite_ = true;
+
+            public Factory()
+                : this(false, true)
+            {
+            }
+
+            public Factory(bool strictRead, bool strictWrite)
+            {
+                strictRead_ = strictRead;
+                strictWrite_ = strictWrite;
+            }
+
+            public TProtocol GetProtocol(TTransport trans)
+            {
+                return new TBinaryProtocol(trans, strictRead_, strictWrite_);
+            }
+        }
+
+        #endregion
+
+        public TBinaryProtocol(TTransport trans)
+            : this(trans, false, true)
+        {
+        }
+
+        public TBinaryProtocol(TTransport trans, bool strictRead, bool strictWrite)
+            : base(trans)
+        {
+            strictRead_ = strictRead;
+            strictWrite_ = strictWrite;
+        }
+
+        #region Write Methods
+
+        public override void WriteMessageBegin(TMessage message)
+        {
+            if (strictWrite_)
+            {
+                uint version = VERSION_1 | (uint)(message.Type);
+                WriteI32((int)version);
+                WriteString(message.Name);
+                WriteI32(message.SeqID);
+            }
+            else
+            {
+                WriteString(message.Name);
+                WriteByte((sbyte)message.Type);
+                WriteI32(message.SeqID);
+            }
+        }
+
+        public override void WriteMessageEnd()
+        {
+        }
+
+        public override void WriteStructBegin(TStruct struc)
+        {
+        }
+
+        public override void WriteStructEnd()
+        {
+        }
+
+        public override void WriteFieldBegin(TField field)
+        {
+            WriteByte((sbyte)field.Type);
+            WriteI16(field.ID);
+        }
+
+        public override void WriteFieldEnd()
+        {
+        }
+
+        public override void WriteFieldStop()
+        {
+            WriteByte((sbyte)TType.Stop);
+        }
+
+        public override void WriteMapBegin(TMap map)
+        {
+            WriteByte((sbyte)map.KeyType);
+            WriteByte((sbyte)map.ValueType);
+            WriteI32(map.Count);
+        }
+
+        public override void WriteMapEnd()
+        {
+        }
+
+        public override void WriteListBegin(TList list)
+        {
+            WriteByte((sbyte)list.ElementType);
+            WriteI32(list.Count);
+        }
+
+        public override void WriteListEnd()
+        {
+        }
+
+        public override void WriteSetBegin(TSet set)
+        {
+            WriteByte((sbyte)set.ElementType);
+            WriteI32(set.Count);
+        }
+
+        public override void WriteSetEnd()
+        {
+        }
+
+        public override void WriteBool(bool b)
+        {
+            WriteByte(b ? (sbyte)1 : (sbyte)0);
+        }
+
+        private byte[] bout = new byte[1];
+        public override void WriteByte(sbyte b)
+        {
+            bout[0] = (byte)b;
+            trans.Write(bout, 0, 1);
+        }
+
+        private byte[] i16out = new byte[2];
+        public override void WriteI16(short s)
+        {
+            i16out[0] = (byte)(0xff & (s >> 8));
+            i16out[1] = (byte)(0xff & s);
+            trans.Write(i16out, 0, 2);
+        }
+
+        private byte[] i32out = new byte[4];
+        public override void WriteI32(int i32)
+        {
+            i32out[0] = (byte)(0xff & (i32 >> 24));
+            i32out[1] = (byte)(0xff & (i32 >> 16));
+            i32out[2] = (byte)(0xff & (i32 >> 8));
+            i32out[3] = (byte)(0xff & i32);
+            trans.Write(i32out, 0, 4);
+        }
+
+        private byte[] i64out = new byte[8];
+        public override void WriteI64(long i64)
+        {
+            i64out[0] = (byte)(0xff & (i64 >> 56));
+            i64out[1] = (byte)(0xff & (i64 >> 48));
+            i64out[2] = (byte)(0xff & (i64 >> 40));
+            i64out[3] = (byte)(0xff & (i64 >> 32));
+            i64out[4] = (byte)(0xff & (i64 >> 24));
+            i64out[5] = (byte)(0xff & (i64 >> 16));
+            i64out[6] = (byte)(0xff & (i64 >> 8));
+            i64out[7] = (byte)(0xff & i64);
+            trans.Write(i64out, 0, 8);
+        }
+
+        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)
+        {
+            WriteI32(b.Length);
+            trans.Write(b, 0, b.Length);
+        }
+
+        #endregion
+
+        #region ReadMethods
+
+        public override TMessage ReadMessageBegin()
+        {
+            TMessage message = new TMessage();
+            int size = ReadI32();
+            if (size < 0)
+            {
+                uint version = (uint)size & VERSION_MASK;
+                if (version != VERSION_1)
+                {
+                    throw new TProtocolException(TProtocolException.BAD_VERSION, "Bad version in ReadMessageBegin: " + version);
+                }
+                message.Type = (TMessageType)(size & 0x000000ff);
+                message.Name = ReadString();
+                message.SeqID = ReadI32();
+            }
+            else
+            {
+                if (strictRead_)
+                {
+                    throw new TProtocolException(TProtocolException.BAD_VERSION, "Missing version in readMessageBegin, old client?");
+                }
+                message.Name = ReadStringBody(size);
+                message.Type = (TMessageType)ReadByte();
+                message.SeqID = ReadI32();
+            }
+            return message;
+        }
+
+        public override void ReadMessageEnd()
+        {
+        }
+
+        public override TStruct ReadStructBegin()
+        {
+            return new TStruct();
+        }
+
+        public override void ReadStructEnd()
+        {
+        }
+
+        public override TField ReadFieldBegin()
+        {
+            TField field = new TField();
+            field.Type = (TType)ReadByte();
+
+            if (field.Type != TType.Stop)
+            {
+                field.ID = ReadI16();
+            }
+
+            return field;
+        }
+
+        public override void ReadFieldEnd()
+        {
+        }
+
+        public override TMap ReadMapBegin()
+        {
+            TMap map = new TMap();
+            map.KeyType = (TType)ReadByte();
+            map.ValueType = (TType)ReadByte();
+            map.Count = ReadI32();
+
+            return map;
+        }
+
+        public override void ReadMapEnd()
+        {
+        }
+
+        public override TList ReadListBegin()
+        {
+            TList list = new TList();
+            list.ElementType = (TType)ReadByte();
+            list.Count = ReadI32();
+
+            return list;
+        }
+
+        public override void ReadListEnd()
+        {
+        }
+
+        public override TSet ReadSetBegin()
+        {
+            TSet set = new TSet();
+            set.ElementType = (TType)ReadByte();
+            set.Count = ReadI32();
+
+            return set;
+        }
+
+        public override void ReadSetEnd()
+        {
+        }
+
+        public override bool ReadBool()
+        {
+            return ReadByte() == 1;
+        }
+
+        private byte[] bin = new byte[1];
+        public override sbyte ReadByte()
+        {
+            ReadAll(bin, 0, 1);
+            return (sbyte)bin[0];
+        }
+
+        private byte[] i16in = new byte[2];
+        public override short ReadI16()
+        {
+            ReadAll(i16in, 0, 2);
+            return (short)(((i16in[0] & 0xff) << 8) | ((i16in[1] & 0xff)));
+        }
+
+        private byte[] i32in = new byte[4];
+        public override int ReadI32()
+        {
+            ReadAll(i32in, 0, 4);
+            return (int)(((i32in[0] & 0xff) << 24) | ((i32in[1] & 0xff) << 16) | ((i32in[2] & 0xff) << 8) | ((i32in[3] & 0xff)));
+        }
+
+#pragma warning disable 675
+
+        private byte[] i64in = new byte[8];
+        public override long ReadI64()
+        {
+            ReadAll(i64in, 0, 8);
+            unchecked
+            {
+                return (long)(
+                    ((long)(i64in[0] & 0xff) << 56) |
+                    ((long)(i64in[1] & 0xff) << 48) |
+                    ((long)(i64in[2] & 0xff) << 40) |
+                    ((long)(i64in[3] & 0xff) << 32) |
+                    ((long)(i64in[4] & 0xff) << 24) |
+                    ((long)(i64in[5] & 0xff) << 16) |
+                    ((long)(i64in[6] & 0xff) << 8) |
+                    ((long)(i64in[7] & 0xff)));
+            }
+        }
+
+#pragma warning restore 675
+
+        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 override byte[] ReadBinary()
+        {
+            int size = ReadI32();
+            byte[] buf = new byte[size];
+            trans.ReadAll(buf, 0, size);
+            return buf;
+        }
+        private string ReadStringBody(int size)
+        {
+            byte[] buf = new byte[size];
+            trans.ReadAll(buf, 0, size);
+            return Encoding.UTF8.GetString(buf, 0, buf.Length);
+        }
+
+        private int ReadAll(byte[] buf, int off, int len)
+        {
+            return trans.ReadAll(buf, off, len);
+        }
+
+        #endregion
+    }
+}
diff --git a/lib/csharp/src/Protocol/TCompactProtocol.cs b/lib/csharp/src/Protocol/TCompactProtocol.cs
new file mode 100644
index 0000000..ff67397
--- /dev/null
+++ b/lib/csharp/src/Protocol/TCompactProtocol.cs
@@ -0,0 +1,849 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Text;
+using Thrift.Transport;
+using System.Collections;
+using System.IO;
+using System.Collections.Generic;
+
+namespace Thrift.Protocol
+{
+    public class TCompactProtocol : TProtocol
+    {
+        private static TStruct ANONYMOUS_STRUCT = new TStruct("");
+        private static TField TSTOP = new TField("", TType.Stop, (short)0);
+
+        private static byte[] ttypeToCompactType = new byte[16];
+
+        private const byte PROTOCOL_ID = 0x82;
+        private const byte VERSION = 1;
+        private const byte VERSION_MASK = 0x1f; // 0001 1111
+        private const byte TYPE_MASK = 0xE0; // 1110 0000
+        private const byte TYPE_BITS = 0x07; // 0000 0111
+        private const int TYPE_SHIFT_AMOUNT = 5;
+
+        /// <summary>
+        /// All of the on-wire type codes.
+        /// </summary>
+        private static class Types
+        {
+            public const byte STOP = 0x00;
+            public const byte BOOLEAN_TRUE = 0x01;
+            public const byte BOOLEAN_FALSE = 0x02;
+            public const byte BYTE = 0x03;
+            public const byte I16 = 0x04;
+            public const byte I32 = 0x05;
+            public const byte I64 = 0x06;
+            public const byte DOUBLE = 0x07;
+            public const byte BINARY = 0x08;
+            public const byte LIST = 0x09;
+            public const byte SET = 0x0A;
+            public const byte MAP = 0x0B;
+            public const byte STRUCT = 0x0C;
+        }
+
+        /// <summary>
+        /// Used to keep track of the last field for the current and previous structs,
+        /// so we can do the delta stuff.
+        /// </summary>
+        private Stack<short> lastField_ = new Stack<short>(15);
+
+        private short lastFieldId_ = 0;
+
+        /// <summary>
+        /// If we encounter a boolean field begin, save the TField here so it can
+        /// have the value incorporated.
+        /// </summary>
+        private Nullable<TField> booleanField_;
+
+        /// <summary>
+        /// If we Read a field header, and it's a boolean field, save the boolean
+        /// value here so that ReadBool can use it.
+        /// </summary>
+        private Nullable<Boolean> boolValue_;
+
+
+        #region CompactProtocol Factory
+
+        public class Factory : TProtocolFactory
+        {
+            public Factory() { }
+
+            public TProtocol GetProtocol(TTransport trans)
+            {
+                return new TCompactProtocol(trans);
+            }
+        }
+
+        #endregion
+
+        public TCompactProtocol(TTransport trans)
+            : base(trans)
+        {
+            ttypeToCompactType[(int)TType.Stop] = Types.STOP;
+            ttypeToCompactType[(int)TType.Bool] = Types.BOOLEAN_TRUE;
+            ttypeToCompactType[(int)TType.Byte] = Types.BYTE;
+            ttypeToCompactType[(int)TType.I16] = Types.I16;
+            ttypeToCompactType[(int)TType.I32] = Types.I32;
+            ttypeToCompactType[(int)TType.I64] = Types.I64;
+            ttypeToCompactType[(int)TType.Double] = Types.DOUBLE;
+            ttypeToCompactType[(int)TType.String] = Types.BINARY;
+            ttypeToCompactType[(int)TType.List] = Types.LIST;
+            ttypeToCompactType[(int)TType.Set] = Types.SET;
+            ttypeToCompactType[(int)TType.Map] = Types.MAP;
+            ttypeToCompactType[(int)TType.Struct] = Types.STRUCT;
+        }
+
+        public void reset()
+        {
+            lastField_.Clear();
+            lastFieldId_ = 0;
+        }
+
+        #region Write Methods
+
+        /// <summary>
+        /// Writes a byte without any possibility of all that field header nonsense.
+        /// Used internally by other writing methods that know they need to Write a byte.
+        /// </summary>
+        private byte[] byteDirectBuffer = new byte[1];
+
+        private void WriteByteDirect(byte b)
+        {
+            byteDirectBuffer[0] = b;
+            trans.Write(byteDirectBuffer);
+        }
+
+        /// <summary>
+        /// Writes a byte without any possibility of all that field header nonsense.
+        /// </summary>
+        private void WriteByteDirect(int n)
+        {
+            WriteByteDirect((byte)n);
+        }
+
+        /// <summary>
+        /// Write an i32 as a varint. Results in 1-5 bytes on the wire.
+        /// TODO: make a permanent buffer like WriteVarint64?
+        /// </summary>
+        byte[] i32buf = new byte[5];
+
+        private void WriteVarint32(uint n)
+        {
+            int idx = 0;
+            while (true)
+            {
+                if ((n & ~0x7F) == 0)
+                {
+                    i32buf[idx++] = (byte)n;
+                    // WriteByteDirect((byte)n);
+                    break;
+                    // return;
+                }
+                else
+                {
+                    i32buf[idx++] = (byte)((n & 0x7F) | 0x80);
+                    // WriteByteDirect((byte)((n & 0x7F) | 0x80));
+                    n >>= 7;
+                }
+            }
+            trans.Write(i32buf, 0, idx);
+        }
+
+        /// <summary>
+        /// Write a message header to the wire. Compact Protocol messages contain the
+        /// protocol version so we can migrate forwards in the future if need be.
+        /// </summary>
+        public override void WriteMessageBegin(TMessage message)
+        {
+            WriteByteDirect(PROTOCOL_ID);
+            WriteByteDirect((byte)((VERSION & VERSION_MASK) | ((((uint)message.Type) << TYPE_SHIFT_AMOUNT) & TYPE_MASK)));
+            WriteVarint32((uint)message.SeqID);
+            WriteString(message.Name);
+        }
+
+        /// <summary>
+        /// Write a struct begin. This doesn't actually put anything on the wire. We
+        /// use it as an opportunity to put special placeholder markers on the field
+        /// stack so we can get the field id deltas correct.
+        /// </summary>
+        public override void WriteStructBegin(TStruct strct)
+        {
+            lastField_.Push(lastFieldId_);
+            lastFieldId_ = 0;
+        }
+
+        /// <summary>
+        /// Write a struct end. This doesn't actually put anything on the wire. We use
+        /// this as an opportunity to pop the last field from the current struct off
+        /// of the field stack.
+        /// </summary>
+        public override void WriteStructEnd()
+        {
+            lastFieldId_ = lastField_.Pop();
+        }
+
+        /// <summary>
+        /// Write a field header containing the field id and field type. If the
+        /// difference between the current field id and the last one is small (&lt; 15),
+        /// then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
+        /// field id will follow the type header as a zigzag varint.
+        /// </summary>
+        public override void WriteFieldBegin(TField field)
+        {
+            if (field.Type == TType.Bool)
+            {
+                // we want to possibly include the value, so we'll wait.
+                booleanField_ = field;
+            }
+            else
+            {
+                WriteFieldBeginInternal(field, 0xFF);
+            }
+        }
+
+        /// <summary>
+        /// The workhorse of WriteFieldBegin. It has the option of doing a
+        /// 'type override' of the type header. This is used specifically in the
+        /// boolean field case.
+        /// </summary>
+        private void WriteFieldBeginInternal(TField field, byte typeOverride)
+        {
+            // short lastField = lastField_.Pop();
+
+            // if there's a type override, use that.
+            byte typeToWrite = typeOverride == 0xFF ? getCompactType(field.Type) : typeOverride;
+
+            // check if we can use delta encoding for the field id
+            if (field.ID > lastFieldId_ && field.ID - lastFieldId_ <= 15)
+            {
+                // Write them together
+                WriteByteDirect((field.ID - lastFieldId_) << 4 | typeToWrite);
+            }
+            else
+            {
+                // Write them separate
+                WriteByteDirect(typeToWrite);
+                WriteI16(field.ID);
+            }
+
+            lastFieldId_ = field.ID;
+            // lastField_.push(field.id);
+        }
+
+        /// <summary>
+        /// Write the STOP symbol so we know there are no more fields in this struct.
+        /// </summary>
+        public override void WriteFieldStop()
+        {
+            WriteByteDirect(Types.STOP);
+        }
+
+        /// <summary>
+        /// Write a map header. If the map is empty, omit the key and value type
+        /// headers, as we don't need any additional information to skip it.
+        /// </summary>
+        public override void WriteMapBegin(TMap map)
+        {
+            if (map.Count == 0)
+            {
+                WriteByteDirect(0);
+            }
+            else
+            {
+                WriteVarint32((uint)map.Count);
+                WriteByteDirect(getCompactType(map.KeyType) << 4 | getCompactType(map.ValueType));
+            }
+        }
+
+        /// <summary>
+        /// Write a list header.
+        /// </summary>
+        public override void WriteListBegin(TList list)
+        {
+            WriteCollectionBegin(list.ElementType, list.Count);
+        }
+
+        /// <summary>
+        /// Write a set header.
+        /// </summary>
+        public override void WriteSetBegin(TSet set)
+        {
+            WriteCollectionBegin(set.ElementType, set.Count);
+        }
+
+        /// <summary>
+        /// Write a boolean value. Potentially, this could be a boolean field, in
+        /// which case the field header info isn't written yet. If so, decide what the
+        /// right type header is for the value and then Write the field header.
+        /// Otherwise, Write a single byte.
+        /// </summary>
+        public override void WriteBool(Boolean b)
+        {
+            if (booleanField_ != null)
+            {
+                // we haven't written the field header yet
+                WriteFieldBeginInternal(booleanField_.Value, b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE);
+                booleanField_ = null;
+            }
+            else
+            {
+                // we're not part of a field, so just Write the value.
+                WriteByteDirect(b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE);
+            }
+        }
+
+        /// <summary>
+        /// Write a byte. Nothing to see here!
+        /// </summary>
+        public override void WriteByte(sbyte b)
+        {
+            WriteByteDirect((byte)b);
+        }
+
+        /// <summary>
+        /// Write an I16 as a zigzag varint.
+        /// </summary>
+        public override void WriteI16(short i16)
+        {
+            WriteVarint32(intToZigZag(i16));
+        }
+
+        /// <summary>
+        /// Write an i32 as a zigzag varint.
+        /// </summary>
+        public override void WriteI32(int i32)
+        {
+            WriteVarint32(intToZigZag(i32));
+        }
+
+        /// <summary>
+        /// Write an i64 as a zigzag varint.
+        /// </summary>
+        public override void WriteI64(long i64)
+        {
+            WriteVarint64(longToZigzag(i64));
+        }
+
+        /// <summary>
+        /// Write a double to the wire as 8 bytes.
+        /// </summary>
+        public override void WriteDouble(double dub)
+        {
+            byte[] data = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
+            fixedLongToBytes(BitConverter.DoubleToInt64Bits(dub), data, 0);
+            trans.Write(data);
+        }
+
+        /// <summary>
+        /// Write a string to the wire with a varint size preceding.
+        /// </summary>
+        public override void WriteString(string str)
+        {
+            byte[] bytes = UTF8Encoding.UTF8.GetBytes(str);
+            WriteBinary(bytes, 0, bytes.Length);
+        }
+
+        /// <summary>
+        /// Write a byte array, using a varint for the size.
+        /// </summary>
+        public override void WriteBinary(byte[] bin)
+        {
+            WriteBinary(bin, 0, bin.Length);
+        }
+
+        private void WriteBinary(byte[] buf, int offset, int length)
+        {
+            WriteVarint32((uint)length);
+            trans.Write(buf, offset, length);
+        }
+
+        //
+        // These methods are called by structs, but don't actually have any wire
+        // output or purpose.
+        //
+
+        public override void WriteMessageEnd() { }
+        public override void WriteMapEnd() { }
+        public override void WriteListEnd() { }
+        public override void WriteSetEnd() { }
+        public override void WriteFieldEnd() { }
+
+        //
+        // Internal writing methods
+        //
+
+        /// <summary>
+        /// Abstract method for writing the start of lists and sets. List and sets on
+        /// the wire differ only by the type indicator.
+        /// </summary>
+        protected void WriteCollectionBegin(TType elemType, int size)
+        {
+            if (size <= 14)
+            {
+                WriteByteDirect(size << 4 | getCompactType(elemType));
+            }
+            else
+            {
+                WriteByteDirect(0xf0 | getCompactType(elemType));
+                WriteVarint32((uint)size);
+            }
+        }
+
+        /// <summary>
+        /// Write an i64 as a varint. Results in 1-10 bytes on the wire.
+        /// </summary>
+        byte[] varint64out = new byte[10];
+        private void WriteVarint64(ulong n)
+        {
+            int idx = 0;
+            while (true)
+            {
+                if ((n & ~(ulong)0x7FL) == 0)
+                {
+                    varint64out[idx++] = (byte)n;
+                    break;
+                }
+                else
+                {
+                    varint64out[idx++] = ((byte)((n & 0x7F) | 0x80));
+                    n >>= 7;
+                }
+            }
+            trans.Write(varint64out, 0, idx);
+        }
+
+        /// <summary>
+        /// Convert l into a zigzag long. This allows negative numbers to be
+        /// represented compactly as a varint.
+        /// </summary>
+        private ulong longToZigzag(long n)
+        {
+            return (ulong)(n << 1) ^ (ulong)(n >> 63);
+        }
+
+        /// <summary>
+        /// Convert n into a zigzag int. This allows negative numbers to be
+        /// represented compactly as a varint.
+        /// </summary>
+        private uint intToZigZag(int n)
+        {
+            return (uint)(n << 1) ^ (uint)(n >> 31);
+        }
+
+        /// <summary>
+        /// Convert a long into little-endian bytes in buf starting at off and going
+        /// until off+7.
+        /// </summary>
+        private void fixedLongToBytes(long n, byte[] buf, int off)
+        {
+            buf[off + 0] = (byte)(n & 0xff);
+            buf[off + 1] = (byte)((n >> 8) & 0xff);
+            buf[off + 2] = (byte)((n >> 16) & 0xff);
+            buf[off + 3] = (byte)((n >> 24) & 0xff);
+            buf[off + 4] = (byte)((n >> 32) & 0xff);
+            buf[off + 5] = (byte)((n >> 40) & 0xff);
+            buf[off + 6] = (byte)((n >> 48) & 0xff);
+            buf[off + 7] = (byte)((n >> 56) & 0xff);
+        }
+
+        #endregion
+
+        #region ReadMethods
+
+        /// <summary>
+        /// Read a message header.
+        /// </summary>
+        public override TMessage ReadMessageBegin()
+        {
+            byte protocolId = (byte)ReadByte();
+            if (protocolId != PROTOCOL_ID)
+            {
+                throw new TProtocolException("Expected protocol id " + PROTOCOL_ID.ToString("X") + " but got " + protocolId.ToString("X"));
+            }
+            byte versionAndType = (byte)ReadByte();
+            byte version = (byte)(versionAndType & VERSION_MASK);
+            if (version != VERSION)
+            {
+                throw new TProtocolException("Expected version " + VERSION + " but got " + version);
+            }
+            byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
+            int seqid = (int)ReadVarint32();
+            string messageName = ReadString();
+            return new TMessage(messageName, (TMessageType)type, seqid);
+        }
+
+        /// <summary>
+        /// Read a struct begin. There's nothing on the wire for this, but it is our
+        /// opportunity to push a new struct begin marker onto the field stack.
+        /// </summary>
+        public override TStruct ReadStructBegin()
+        {
+            lastField_.Push(lastFieldId_);
+            lastFieldId_ = 0;
+            return ANONYMOUS_STRUCT;
+        }
+
+        /// <summary>
+        /// Doesn't actually consume any wire data, just removes the last field for
+        /// this struct from the field stack.
+        /// </summary>
+        public override void ReadStructEnd()
+        {
+            // consume the last field we Read off the wire.
+            lastFieldId_ = lastField_.Pop();
+        }
+
+        /// <summary>
+        /// Read a field header off the wire.
+        /// </summary>
+        public override TField ReadFieldBegin()
+        {
+            byte type = (byte)ReadByte();
+
+            // if it's a stop, then we can return immediately, as the struct is over.
+            if (type == Types.STOP)
+            {
+                return TSTOP;
+            }
+
+            short fieldId;
+
+            // mask off the 4 MSB of the type header. it could contain a field id delta.
+            short modifier = (short)((type & 0xf0) >> 4);
+            if (modifier == 0)
+            {
+                // not a delta. look ahead for the zigzag varint field id.
+                fieldId = ReadI16();
+            }
+            else
+            {
+                // has a delta. add the delta to the last Read field id.
+                fieldId = (short)(lastFieldId_ + modifier);
+            }
+
+            TField field = new TField("", getTType((byte)(type & 0x0f)), fieldId);
+
+            // if this happens to be a boolean field, the value is encoded in the type
+            if (isBoolType(type))
+            {
+                // save the boolean value in a special instance variable.
+                boolValue_ = (byte)(type & 0x0f) == Types.BOOLEAN_TRUE ? true : false;
+            }
+
+            // push the new field onto the field stack so we can keep the deltas going.
+            lastFieldId_ = field.ID;
+            return field;
+        }
+
+        /// <summary>
+        /// Read a map header off the wire. If the size is zero, skip Reading the key
+        /// and value type. This means that 0-length maps will yield TMaps without the
+        /// "correct" types.
+        /// </summary>
+        public override TMap ReadMapBegin()
+        {
+            int size = (int)ReadVarint32();
+            byte keyAndValueType = size == 0 ? (byte)0 : (byte)ReadByte();
+            return new TMap(getTType((byte)(keyAndValueType >> 4)), getTType((byte)(keyAndValueType & 0xf)), size);
+        }
+
+        /// <summary>
+        /// Read a list header off the wire. If the list size is 0-14, the size will
+        /// be packed into the element type header. If it's a longer list, the 4 MSB
+        /// of the element type header will be 0xF, and a varint will follow with the
+        /// true size.
+        /// </summary>
+        public override TList ReadListBegin()
+        {
+            byte size_and_type = (byte)ReadByte();
+            int size = (size_and_type >> 4) & 0x0f;
+            if (size == 15)
+            {
+                size = (int)ReadVarint32();
+            }
+            TType type = getTType(size_and_type);
+            return new TList(type, size);
+        }
+
+        /// <summary>
+        /// Read a set header off the wire. If the set size is 0-14, the size will
+        /// be packed into the element type header. If it's a longer set, the 4 MSB
+        /// of the element type header will be 0xF, and a varint will follow with the
+        /// true size.
+        /// </summary>
+        public override TSet ReadSetBegin()
+        {
+            return new TSet(ReadListBegin());
+        }
+
+        /// <summary>
+        /// Read a boolean off the wire. If this is a boolean field, the value should
+        /// already have been Read during ReadFieldBegin, so we'll just consume the
+        /// pre-stored value. Otherwise, Read a byte.
+        /// </summary>
+        public override Boolean ReadBool()
+        {
+            if (boolValue_ != null)
+            {
+                bool result = boolValue_.Value;
+                boolValue_ = null;
+                return result;
+            }
+            return ReadByte() == Types.BOOLEAN_TRUE;
+        }
+
+        byte[] byteRawBuf = new byte[1];
+        /// <summary>
+        /// Read a single byte off the wire. Nothing interesting here.
+        /// </summary>
+        public override sbyte ReadByte()
+        {
+            trans.ReadAll(byteRawBuf, 0, 1);
+            return (sbyte)byteRawBuf[0];
+        }
+
+        /// <summary>
+        /// Read an i16 from the wire as a zigzag varint.
+        /// </summary>
+        public override short ReadI16()
+        {
+            return (short)zigzagToInt(ReadVarint32());
+        }
+
+        /// <summary>
+        /// Read an i32 from the wire as a zigzag varint.
+        /// </summary>
+        public override int ReadI32()
+        {
+            return zigzagToInt(ReadVarint32());
+        }
+
+        /// <summary>
+        /// Read an i64 from the wire as a zigzag varint.
+        /// </summary>
+        public override long ReadI64()
+        {
+            return zigzagToLong(ReadVarint64());
+        }
+
+        /// <summary>
+        /// No magic here - just Read a double off the wire.
+        /// </summary>
+        public override double ReadDouble()
+        {
+            byte[] longBits = new byte[8];
+            trans.ReadAll(longBits, 0, 8);
+            return BitConverter.Int64BitsToDouble(bytesToLong(longBits));
+        }
+
+        /// <summary>
+        /// Reads a byte[] (via ReadBinary), and then UTF-8 decodes it.
+        /// </summary>
+        public override string ReadString()
+        {
+            int length = (int)ReadVarint32();
+
+            if (length == 0)
+            {
+                return "";
+            }
+
+            return Encoding.UTF8.GetString(ReadBinary(length));
+        }
+
+        /// <summary>
+        /// Read a byte[] from the wire.
+        /// </summary>
+        public override byte[] ReadBinary()
+        {
+            int length = (int)ReadVarint32();
+            if (length == 0) return new byte[0];
+
+            byte[] buf = new byte[length];
+            trans.ReadAll(buf, 0, length);
+            return buf;
+        }
+
+        /// <summary>
+        /// Read a byte[] of a known length from the wire.
+        /// </summary>
+        private byte[] ReadBinary(int length)
+        {
+            if (length == 0) return new byte[0];
+
+            byte[] buf = new byte[length];
+            trans.ReadAll(buf, 0, length);
+            return buf;
+        }
+
+        //
+        // These methods are here for the struct to call, but don't have any wire
+        // encoding.
+        //
+        public override void ReadMessageEnd() { }
+        public override void ReadFieldEnd() { }
+        public override void ReadMapEnd() { }
+        public override void ReadListEnd() { }
+        public override void ReadSetEnd() { }
+
+        //
+        // Internal Reading methods
+        //
+
+        /// <summary>
+        /// Read an i32 from the wire as a varint. The MSB of each byte is set
+        /// if there is another byte to follow. This can Read up to 5 bytes.
+        /// </summary>
+        private uint ReadVarint32()
+        {
+            uint result = 0;
+            int shift = 0;
+            while (true)
+            {
+                byte b = (byte)ReadByte();
+                result |= (uint)(b & 0x7f) << shift;
+                if ((b & 0x80) != 0x80) break;
+                shift += 7;
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Read an i64 from the wire as a proper varint. The MSB of each byte is set
+        /// if there is another byte to follow. This can Read up to 10 bytes.
+        /// </summary>
+        private ulong ReadVarint64()
+        {
+            int shift = 0;
+            ulong result = 0;
+            while (true)
+            {
+                byte b = (byte)ReadByte();
+                result |= (ulong)(b & 0x7f) << shift;
+                if ((b & 0x80) != 0x80) break;
+                shift += 7;
+            }
+
+            return result;
+        }
+
+        #endregion
+
+        //
+        // encoding helpers
+        //
+
+        /// <summary>
+        /// Convert from zigzag int to int.
+        /// </summary>
+        private int zigzagToInt(uint n)
+        {
+            return (int)(n >> 1) ^ (-(int)(n & 1));
+        }
+
+        /// <summary>
+        /// Convert from zigzag long to long.
+        /// </summary>
+        private long zigzagToLong(ulong n)
+        {
+            return (long)(n >> 1) ^ (-(long)(n & 1));
+        }
+
+        /// <summary>
+        /// Note that it's important that the mask bytes are long literals,
+        /// otherwise they'll default to ints, and when you shift an int left 56 bits,
+        /// you just get a messed up int.
+        /// </summary>
+        private long bytesToLong(byte[] bytes)
+        {
+            return
+              ((bytes[7] & 0xffL) << 56) |
+              ((bytes[6] & 0xffL) << 48) |
+              ((bytes[5] & 0xffL) << 40) |
+              ((bytes[4] & 0xffL) << 32) |
+              ((bytes[3] & 0xffL) << 24) |
+              ((bytes[2] & 0xffL) << 16) |
+              ((bytes[1] & 0xffL) << 8) |
+              ((bytes[0] & 0xffL));
+        }
+
+        //
+        // type testing and converting
+        //
+
+        private Boolean isBoolType(byte b)
+        {
+            int lowerNibble = b & 0x0f;
+            return lowerNibble == Types.BOOLEAN_TRUE || lowerNibble == Types.BOOLEAN_FALSE;
+        }
+
+        /// <summary>
+        /// Given a TCompactProtocol.Types constant, convert it to its corresponding
+        /// TType value.
+        /// </summary>
+        private TType getTType(byte type)
+        {
+            switch ((byte)(type & 0x0f))
+            {
+                case Types.STOP:
+                    return TType.Stop;
+                case Types.BOOLEAN_FALSE:
+                case Types.BOOLEAN_TRUE:
+                    return TType.Bool;
+                case Types.BYTE:
+                    return TType.Byte;
+                case Types.I16:
+                    return TType.I16;
+                case Types.I32:
+                    return TType.I32;
+                case Types.I64:
+                    return TType.I64;
+                case Types.DOUBLE:
+                    return TType.Double;
+                case Types.BINARY:
+                    return TType.String;
+                case Types.LIST:
+                    return TType.List;
+                case Types.SET:
+                    return TType.Set;
+                case Types.MAP:
+                    return TType.Map;
+                case Types.STRUCT:
+                    return TType.Struct;
+                default:
+                    throw new TProtocolException("don't know what type: " + (byte)(type & 0x0f));
+            }
+        }
+
+        /// <summary>
+        /// Given a TType value, find the appropriate TCompactProtocol.Types constant.
+        /// </summary>
+        private byte getCompactType(TType ttype)
+        {
+            return ttypeToCompactType[(int)ttype];
+        }
+    }
+}
diff --git a/lib/csharp/src/Protocol/TField.cs b/lib/csharp/src/Protocol/TField.cs
new file mode 100644
index 0000000..8179557
--- /dev/null
+++ b/lib/csharp/src/Protocol/TField.cs
@@ -0,0 +1,62 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+    public struct TField
+    {
+        private string name;
+        private TType type;
+        private short id;
+
+        public TField(string name, TType type, short id)
+            :this()
+        {
+            this.name = name;
+            this.type = type;
+            this.id = id;
+        }
+
+        public string Name
+        {
+            get { return name; }
+            set { name = value; }
+        }
+
+        public TType Type
+        {
+            get { return type; }
+            set { type = value; }
+        }
+
+        public short ID
+        {
+            get { return id; }
+            set { id = value; }
+        }
+    }
+}
diff --git a/lib/csharp/src/Protocol/TJSONProtocol.cs b/lib/csharp/src/Protocol/TJSONProtocol.cs
new file mode 100644
index 0000000..9dbdea9
--- /dev/null
+++ b/lib/csharp/src/Protocol/TJSONProtocol.cs
@@ -0,0 +1,1124 @@
+/**
+ * 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;
+using System.IO;
+using System.Text;
+using System.Collections.Generic;
+
+using Thrift.Transport;
+using System.Globalization;
+
+namespace Thrift.Protocol
+{
+    /// <summary>
+    /// JSON protocol implementation for thrift.
+    /// <para/>
+    /// This is a full-featured protocol supporting Write and Read.
+    /// <para/>
+    /// Please see the C++ class header for a detailed description of the
+    /// protocol's wire format.
+    /// <para/>
+    /// Adapted from the Java version.
+    /// </summary>
+    public class TJSONProtocol : TProtocol
+    {
+        /// <summary>
+        /// Factory for JSON protocol objects.
+        /// </summary>
+        public class Factory : TProtocolFactory
+        {
+            public TProtocol GetProtocol(TTransport trans)
+            {
+                return new TJSONProtocol(trans);
+            }
+        }
+
+        private static byte[] COMMA = new byte[] { (byte)',' };
+        private static byte[] COLON = new byte[] { (byte)':' };
+        private static byte[] LBRACE = new byte[] { (byte)'{' };
+        private static byte[] RBRACE = new byte[] { (byte)'}' };
+        private static byte[] LBRACKET = new byte[] { (byte)'[' };
+        private static byte[] RBRACKET = new byte[] { (byte)']' };
+        private static byte[] QUOTE = new byte[] { (byte)'"' };
+        private static byte[] BACKSLASH = new byte[] { (byte)'\\' };
+
+        private byte[] ESCSEQ = new byte[] { (byte)'\\', (byte)'u', (byte)'0', (byte)'0' };
+
+        private const long VERSION = 1;
+        private byte[] JSON_CHAR_TABLE = {
+    0,  0,  0,  0,  0,  0,  0,  0,(byte)'b',(byte)'t',(byte)'n',  0,(byte)'f',(byte)'r',  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    1,  1,(byte)'"',  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+  };
+
+        private char[] ESCAPE_CHARS = "\"\\/bfnrt".ToCharArray();
+
+        private byte[] ESCAPE_CHAR_VALS = {
+    (byte)'"', (byte)'\\', (byte)'/', (byte)'\b', (byte)'\f', (byte)'\n', (byte)'\r', (byte)'\t',
+  };
+
+        private const int DEF_STRING_SIZE = 16;
+
+        private static byte[] NAME_BOOL = new byte[] { (byte)'t', (byte)'f' };
+        private static byte[] NAME_BYTE = new byte[] { (byte)'i', (byte)'8' };
+        private static byte[] NAME_I16 = new byte[] { (byte)'i', (byte)'1', (byte)'6' };
+        private static byte[] NAME_I32 = new byte[] { (byte)'i', (byte)'3', (byte)'2' };
+        private static byte[] NAME_I64 = new byte[] { (byte)'i', (byte)'6', (byte)'4' };
+        private static byte[] NAME_DOUBLE = new byte[] { (byte)'d', (byte)'b', (byte)'l' };
+        private static byte[] NAME_STRUCT = new byte[] { (byte)'r', (byte)'e', (byte)'c' };
+        private static byte[] NAME_STRING = new byte[] { (byte)'s', (byte)'t', (byte)'r' };
+        private static byte[] NAME_MAP = new byte[] { (byte)'m', (byte)'a', (byte)'p' };
+        private static byte[] NAME_LIST = new byte[] { (byte)'l', (byte)'s', (byte)'t' };
+        private static byte[] NAME_SET = new byte[] { (byte)'s', (byte)'e', (byte)'t' };
+
+        private static byte[] GetTypeNameForTypeID(TType typeID)
+        {
+            switch (typeID)
+            {
+                case TType.Bool:
+                    return NAME_BOOL;
+                case TType.Byte:
+                    return NAME_BYTE;
+                case TType.I16:
+                    return NAME_I16;
+                case TType.I32:
+                    return NAME_I32;
+                case TType.I64:
+                    return NAME_I64;
+                case TType.Double:
+                    return NAME_DOUBLE;
+                case TType.String:
+                    return NAME_STRING;
+                case TType.Struct:
+                    return NAME_STRUCT;
+                case TType.Map:
+                    return NAME_MAP;
+                case TType.Set:
+                    return NAME_SET;
+                case TType.List:
+                    return NAME_LIST;
+                default:
+                    throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+                                                 "Unrecognized type");
+            }
+        }
+
+        private static TType GetTypeIDForTypeName(byte[] name)
+        {
+            TType result = TType.Stop;
+            if (name.Length > 1)
+            {
+                switch (name[0])
+                {
+                    case (byte)'d':
+                        result = TType.Double;
+                        break;
+                    case (byte)'i':
+                        switch (name[1])
+                        {
+                            case (byte)'8':
+                                result = TType.Byte;
+                                break;
+                            case (byte)'1':
+                                result = TType.I16;
+                                break;
+                            case (byte)'3':
+                                result = TType.I32;
+                                break;
+                            case (byte)'6':
+                                result = TType.I64;
+                                break;
+                        }
+                        break;
+                    case (byte)'l':
+                        result = TType.List;
+                        break;
+                    case (byte)'m':
+                        result = TType.Map;
+                        break;
+                    case (byte)'r':
+                        result = TType.Struct;
+                        break;
+                    case (byte)'s':
+                        if (name[1] == (byte)'t')
+                        {
+                            result = TType.String;
+                        }
+                        else if (name[1] == (byte)'e')
+                        {
+                            result = TType.Set;
+                        }
+                        break;
+                    case (byte)'t':
+                        result = TType.Bool;
+                        break;
+                }
+            }
+            if (result == TType.Stop)
+            {
+                throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+                                             "Unrecognized type");
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Base class for tracking JSON contexts that may require
+        /// inserting/Reading additional JSON syntax characters
+        /// This base context does nothing.
+        /// </summary>
+        protected class JSONBaseContext
+        {
+            protected TJSONProtocol proto;
+
+            public JSONBaseContext(TJSONProtocol proto)
+            {
+                this.proto = proto;
+            }
+
+            public virtual void Write() { }
+
+            public virtual void Read() { }
+
+            public virtual bool EscapeNumbers() { return false; }
+        }
+
+        /// <summary>
+        /// Context for JSON lists. Will insert/Read commas before each item except
+        /// for the first one
+        /// </summary>
+        protected class JSONListContext : JSONBaseContext
+        {
+            public JSONListContext(TJSONProtocol protocol)
+                : base(protocol)
+            {
+
+            }
+
+            private bool first = true;
+
+            public override void Write()
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    proto.trans.Write(COMMA);
+                }
+            }
+
+            public override void Read()
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    proto.ReadJSONSyntaxChar(COMMA);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Context for JSON records. Will insert/Read colons before the value portion
+        /// of each record pair, and commas before each key except the first. In
+        /// addition, will indicate that numbers in the key position need to be
+        /// escaped in quotes (since JSON keys must be strings).
+        /// </summary>
+        protected class JSONPairContext : JSONBaseContext
+        {
+            public JSONPairContext(TJSONProtocol proto)
+                : base(proto)
+            {
+
+            }
+
+            private bool first = true;
+            private bool colon = true;
+
+            public override void Write()
+            {
+                if (first)
+                {
+                    first = false;
+                    colon = true;
+                }
+                else
+                {
+                    proto.trans.Write(colon ? COLON : COMMA);
+                    colon = !colon;
+                }
+            }
+
+            public override void Read()
+            {
+                if (first)
+                {
+                    first = false;
+                    colon = true;
+                }
+                else
+                {
+                    proto.ReadJSONSyntaxChar(colon ? COLON : COMMA);
+                    colon = !colon;
+                }
+            }
+
+            public override bool EscapeNumbers()
+            {
+                return colon;
+            }
+        }
+
+        /// <summary>
+        /// Holds up to one byte from the transport
+        /// </summary>
+        protected class LookaheadReader
+        {
+            protected TJSONProtocol proto;
+
+            public LookaheadReader(TJSONProtocol proto)
+            {
+                this.proto = proto;
+            }
+
+            private bool hasData;
+            private byte[] data = new byte[1];
+
+            /// <summary>
+            /// Return and consume the next byte to be Read, either taking it from the
+            /// data buffer if present or getting it from the transport otherwise.
+            /// </summary>
+            public byte Read()
+            {
+                if (hasData)
+                {
+                    hasData = false;
+                }
+                else
+                {
+                    proto.trans.ReadAll(data, 0, 1);
+                }
+                return data[0];
+            }
+
+            /// <summary>
+            /// Return the next byte to be Read without consuming, filling the data
+            /// buffer if it has not been filled alReady.
+            /// </summary>
+            public byte Peek()
+            {
+                if (!hasData)
+                {
+                    proto.trans.ReadAll(data, 0, 1);
+                }
+                hasData = true;
+                return data[0];
+            }
+        }
+
+        // Default encoding
+        protected Encoding utf8Encoding = UTF8Encoding.UTF8;
+
+        // Stack of nested contexts that we may be in
+        protected Stack<JSONBaseContext> contextStack = new Stack<JSONBaseContext>();
+
+        // Current context that we are in
+        protected JSONBaseContext context;
+
+        // Reader that manages a 1-byte buffer
+        protected LookaheadReader reader;
+
+        /// <summary>
+        /// Push a new JSON context onto the stack.
+        /// </summary>
+        protected void PushContext(JSONBaseContext c)
+        {
+            contextStack.Push(context);
+            context = c;
+        }
+
+        /// <summary>
+        /// Pop the last JSON context off the stack
+        /// </summary>
+        protected void PopContext()
+        {
+            context = contextStack.Pop();
+        }
+
+        /// <summary>
+        /// TJSONProtocol Constructor
+        /// </summary>
+        public TJSONProtocol(TTransport trans)
+            : base(trans)
+        {
+            context = new JSONBaseContext(this);
+            reader = new LookaheadReader(this);
+        }
+
+        // Temporary buffer used by several methods
+        private byte[] tempBuffer = new byte[4];
+
+        /// <summary>
+        /// Read a byte that must match b[0]; otherwise an exception is thrown.
+        /// Marked protected to avoid synthetic accessor in JSONListContext.Read
+        /// and JSONPairContext.Read
+        /// </summary>
+        protected void ReadJSONSyntaxChar(byte[] b)
+        {
+            byte ch = reader.Read();
+            if (ch != b[0])
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                             "Unexpected character:" + (char)ch);
+            }
+        }
+
+        /// <summary>
+        /// Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its
+        /// corresponding hex value
+        /// </summary>
+        private static byte HexVal(byte ch)
+        {
+            if ((ch >= '0') && (ch <= '9'))
+            {
+                return (byte)((char)ch - '0');
+            }
+            else if ((ch >= 'a') && (ch <= 'f'))
+            {
+                ch += 10;
+                return (byte)((char)ch - 'a');
+            }
+            else
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                             "Expected hex character");
+            }
+        }
+
+        /// <summary>
+        /// Convert a byte containing a hex value to its corresponding hex character
+        /// </summary>
+        private static byte HexChar(byte val)
+        {
+            val &= 0x0F;
+            if (val < 10)
+            {
+                return (byte)((char)val + '0');
+            }
+            else
+            {
+                val -= 10;
+                return (byte)((char)val + 'a');
+            }
+        }
+
+        /// <summary>
+        /// Write the bytes in array buf as a JSON characters, escaping as needed
+        /// </summary>
+        private void WriteJSONString(byte[] b)
+        {
+            context.Write();
+            trans.Write(QUOTE);
+            int len = b.Length;
+            for (int i = 0; i < len; i++)
+            {
+                if ((b[i] & 0x00FF) >= 0x30)
+                {
+                    if (b[i] == BACKSLASH[0])
+                    {
+                        trans.Write(BACKSLASH);
+                        trans.Write(BACKSLASH);
+                    }
+                    else
+                    {
+                        trans.Write(b, i, 1);
+                    }
+                }
+                else
+                {
+                    tempBuffer[0] = JSON_CHAR_TABLE[b[i]];
+                    if (tempBuffer[0] == 1)
+                    {
+                        trans.Write(b, i, 1);
+                    }
+                    else if (tempBuffer[0] > 1)
+                    {
+                        trans.Write(BACKSLASH);
+                        trans.Write(tempBuffer, 0, 1);
+                    }
+                    else
+                    {
+                        trans.Write(ESCSEQ);
+                        tempBuffer[0] = HexChar((byte)(b[i] >> 4));
+                        tempBuffer[1] = HexChar(b[i]);
+                        trans.Write(tempBuffer, 0, 2);
+                    }
+                }
+            }
+            trans.Write(QUOTE);
+        }
+
+        /// <summary>
+        /// Write out number as a JSON value. If the context dictates so, it will be
+        /// wrapped in quotes to output as a JSON string.
+        /// </summary>
+        private void WriteJSONInteger(long num)
+        {
+            context.Write();
+            string str = num.ToString();
+
+            bool escapeNum = context.EscapeNumbers();
+            if (escapeNum)
+                trans.Write(QUOTE);
+
+            trans.Write(utf8Encoding.GetBytes(str));
+
+            if (escapeNum)
+                trans.Write(QUOTE);
+        }
+
+        /// <summary>
+        /// Write out a double as a JSON value. If it is NaN or infinity or if the
+        /// context dictates escaping, Write out as JSON string.
+        /// </summary>
+        private void WriteJSONDouble(double num)
+        {
+            context.Write();
+            string str = num.ToString("G17", CultureInfo.InvariantCulture);
+            bool special = false;
+
+            switch (str[0])
+            {
+                case 'N': // NaN
+                case 'I': // Infinity
+                    special = true;
+                    break;
+                case '-':
+                    if (str[1] == 'I')
+                    { // -Infinity
+                        special = true;
+                    }
+                    break;
+            }
+
+            bool escapeNum = special || context.EscapeNumbers();
+
+            if (escapeNum)
+                trans.Write(QUOTE);
+
+            trans.Write(utf8Encoding.GetBytes(str));
+
+            if (escapeNum)
+                trans.Write(QUOTE);
+        }
+        /// <summary>
+        /// Write out contents of byte array b as a JSON string with base-64 encoded
+        /// data
+        /// </summary>
+        private void WriteJSONBase64(byte[] b)
+        {
+            context.Write();
+            trans.Write(QUOTE);
+
+            int len = b.Length;
+            int off = 0;
+
+            while (len >= 3)
+            {
+                // Encode 3 bytes at a time
+                TBase64Utils.encode(b, off, 3, tempBuffer, 0);
+                trans.Write(tempBuffer, 0, 4);
+                off += 3;
+                len -= 3;
+            }
+            if (len > 0)
+            {
+                // Encode remainder
+                TBase64Utils.encode(b, off, len, tempBuffer, 0);
+                trans.Write(tempBuffer, 0, len + 1);
+            }
+
+            trans.Write(QUOTE);
+        }
+
+        private void WriteJSONObjectStart()
+        {
+            context.Write();
+            trans.Write(LBRACE);
+            PushContext(new JSONPairContext(this));
+        }
+
+        private void WriteJSONObjectEnd()
+        {
+            PopContext();
+            trans.Write(RBRACE);
+        }
+
+        private void WriteJSONArrayStart()
+        {
+            context.Write();
+            trans.Write(LBRACKET);
+            PushContext(new JSONListContext(this));
+        }
+
+        private void WriteJSONArrayEnd()
+        {
+            PopContext();
+            trans.Write(RBRACKET);
+        }
+
+        public override void WriteMessageBegin(TMessage message)
+        {
+            WriteJSONArrayStart();
+            WriteJSONInteger(VERSION);
+
+            byte[] b = utf8Encoding.GetBytes(message.Name);
+            WriteJSONString(b);
+
+            WriteJSONInteger((long)message.Type);
+            WriteJSONInteger(message.SeqID);
+        }
+
+        public override void WriteMessageEnd()
+        {
+            WriteJSONArrayEnd();
+        }
+
+        public override void WriteStructBegin(TStruct str)
+        {
+            WriteJSONObjectStart();
+        }
+
+        public override void WriteStructEnd()
+        {
+            WriteJSONObjectEnd();
+        }
+
+        public override void WriteFieldBegin(TField field)
+        {
+            WriteJSONInteger(field.ID);
+            WriteJSONObjectStart();
+            WriteJSONString(GetTypeNameForTypeID(field.Type));
+        }
+
+        public override void WriteFieldEnd()
+        {
+            WriteJSONObjectEnd();
+        }
+
+        public override void WriteFieldStop() { }
+
+        public override void WriteMapBegin(TMap map)
+        {
+            WriteJSONArrayStart();
+            WriteJSONString(GetTypeNameForTypeID(map.KeyType));
+            WriteJSONString(GetTypeNameForTypeID(map.ValueType));
+            WriteJSONInteger(map.Count);
+            WriteJSONObjectStart();
+        }
+
+        public override void WriteMapEnd()
+        {
+            WriteJSONObjectEnd();
+            WriteJSONArrayEnd();
+        }
+
+        public override void WriteListBegin(TList list)
+        {
+            WriteJSONArrayStart();
+            WriteJSONString(GetTypeNameForTypeID(list.ElementType));
+            WriteJSONInteger(list.Count);
+        }
+
+        public override void WriteListEnd()
+        {
+            WriteJSONArrayEnd();
+        }
+
+        public override void WriteSetBegin(TSet set)
+        {
+            WriteJSONArrayStart();
+            WriteJSONString(GetTypeNameForTypeID(set.ElementType));
+            WriteJSONInteger(set.Count);
+        }
+
+        public override void WriteSetEnd()
+        {
+            WriteJSONArrayEnd();
+        }
+
+        public override void WriteBool(bool b)
+        {
+            WriteJSONInteger(b ? (long)1 : (long)0);
+        }
+
+        public override void WriteByte(sbyte b)
+        {
+            WriteJSONInteger((long)b);
+        }
+
+        public override void WriteI16(short i16)
+        {
+            WriteJSONInteger((long)i16);
+        }
+
+        public override void WriteI32(int i32)
+        {
+            WriteJSONInteger((long)i32);
+        }
+
+        public override void WriteI64(long i64)
+        {
+            WriteJSONInteger(i64);
+        }
+
+        public override void WriteDouble(double dub)
+        {
+            WriteJSONDouble(dub);
+        }
+
+        public override void WriteString(string str)
+        {
+            byte[] b = utf8Encoding.GetBytes(str);
+            WriteJSONString(b);
+        }
+
+        public override void WriteBinary(byte[] bin)
+        {
+            WriteJSONBase64(bin);
+        }
+
+        /**
+         * Reading methods.
+         */
+
+        /// <summary>
+        /// Read in a JSON string, unescaping as appropriate.. Skip Reading from the
+        /// context if skipContext is true.
+        /// </summary>
+        private byte[] ReadJSONString(bool skipContext)
+        {
+            MemoryStream buffer = new MemoryStream();
+            List<char> codeunits = new List<char>();
+
+
+            if (!skipContext)
+            {
+                context.Read();
+            }
+            ReadJSONSyntaxChar(QUOTE);
+            while (true)
+            {
+                byte ch = reader.Read();
+                if (ch == QUOTE[0])
+                {
+                    break;
+                }
+
+                // escaped?
+                if (ch != ESCSEQ[0])
+                {
+                    buffer.Write(new byte[] { (byte)ch }, 0, 1);
+                    continue;
+                }
+
+                // distinguish between \uXXXX and \?
+                ch = reader.Read();
+                if (ch != ESCSEQ[1])  // control chars like \n
+                {
+                    int off = Array.IndexOf(ESCAPE_CHARS, (char)ch);
+                    if (off == -1)
+                    {
+                        throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                                        "Expected control char");
+                    }
+                    ch = ESCAPE_CHAR_VALS[off];
+                    buffer.Write(new byte[] { (byte)ch }, 0, 1);
+                    continue;
+                }
+
+
+                // it's \uXXXX
+                trans.ReadAll(tempBuffer, 0, 4);
+                var wch = (short)((HexVal((byte)tempBuffer[0]) << 12) +
+                                  (HexVal((byte)tempBuffer[1]) << 8) +
+                                  (HexVal((byte)tempBuffer[2]) << 4) +
+                                   HexVal(tempBuffer[3]));
+                if (Char.IsHighSurrogate((char)wch))
+                {
+                    if (codeunits.Count > 0)
+                    {
+                        throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                                        "Expected low surrogate char");
+                    }
+                    codeunits.Add((char)wch);
+                }
+                else if (Char.IsLowSurrogate((char)wch))
+                {
+                    if (codeunits.Count == 0)
+                    {
+                        throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                                        "Expected high surrogate char");
+                    }
+                    codeunits.Add((char)wch);
+                    var tmp = utf8Encoding.GetBytes(codeunits.ToArray());
+                    buffer.Write(tmp, 0, tmp.Length);
+                    codeunits.Clear();
+                }
+                else
+                {
+                    var tmp = utf8Encoding.GetBytes(new char[] { (char)wch });
+                    buffer.Write(tmp, 0, tmp.Length);
+                }
+            }
+
+
+            if (codeunits.Count > 0)
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                                "Expected low surrogate char");
+            }
+
+            return buffer.ToArray();
+        }
+
+        /// <summary>
+        /// Return true if the given byte could be a valid part of a JSON number.
+        /// </summary>
+        private bool IsJSONNumeric(byte b)
+        {
+            switch (b)
+            {
+                case (byte)'+':
+                case (byte)'-':
+                case (byte)'.':
+                case (byte)'0':
+                case (byte)'1':
+                case (byte)'2':
+                case (byte)'3':
+                case (byte)'4':
+                case (byte)'5':
+                case (byte)'6':
+                case (byte)'7':
+                case (byte)'8':
+                case (byte)'9':
+                case (byte)'E':
+                case (byte)'e':
+                    return true;
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// Read in a sequence of characters that are all valid in JSON numbers. Does
+        /// not do a complete regex check to validate that this is actually a number.
+        /// </summary>
+        private string ReadJSONNumericChars()
+        {
+            StringBuilder strbld = new StringBuilder();
+            while (true)
+            {
+                byte ch = reader.Peek();
+                if (!IsJSONNumeric(ch))
+                {
+                    break;
+                }
+                strbld.Append((char)reader.Read());
+            }
+            return strbld.ToString();
+        }
+
+        /// <summary>
+        /// Read in a JSON number. If the context dictates, Read in enclosing quotes.
+        /// </summary>
+        private long ReadJSONInteger()
+        {
+            context.Read();
+            if (context.EscapeNumbers())
+            {
+                ReadJSONSyntaxChar(QUOTE);
+            }
+
+            string str = ReadJSONNumericChars();
+            if (context.EscapeNumbers())
+            {
+                ReadJSONSyntaxChar(QUOTE);
+            }
+
+            try
+            {
+                return Int64.Parse(str);
+            }
+            catch (FormatException fex)
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                             "Bad data encounted in numeric data", fex);
+            }
+        }
+
+        /// <summary>
+        /// Read in a JSON double value. Throw if the value is not wrapped in quotes
+        /// when expected or if wrapped in quotes when not expected.
+        /// </summary>
+        private double ReadJSONDouble()
+        {
+            context.Read();
+            if (reader.Peek() == QUOTE[0])
+            {
+                byte[] arr = ReadJSONString(true);
+                double dub = Double.Parse(utf8Encoding.GetString(arr, 0, arr.Length), CultureInfo.InvariantCulture);
+
+                if (!context.EscapeNumbers() && !Double.IsNaN(dub) && !Double.IsInfinity(dub))
+                {
+                    // Throw exception -- we should not be in a string in this case
+                    throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                                 "Numeric data unexpectedly quoted");
+                }
+                return dub;
+            }
+            else
+            {
+                if (context.EscapeNumbers())
+                {
+                    // This will throw - we should have had a quote if escapeNum == true
+                    ReadJSONSyntaxChar(QUOTE);
+                }
+                try
+                {
+                    return Double.Parse(ReadJSONNumericChars(), CultureInfo.InvariantCulture);
+                }
+                catch (FormatException fex)
+                {
+                    throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                                 "Bad data encounted in numeric data", fex);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Read in a JSON string containing base-64 encoded data and decode it.
+        /// </summary>
+        private byte[] ReadJSONBase64()
+        {
+            byte[] b = ReadJSONString(false);
+            int len = b.Length;
+            int off = 0;
+            int size = 0;
+            // reduce len to ignore fill bytes
+            while ((len > 0) && (b[len - 1] == '='))
+            {
+                --len;
+            }
+            // read & decode full byte triplets = 4 source bytes
+            while (len > 4)
+            {
+                // Decode 4 bytes at a time
+                TBase64Utils.decode(b, off, 4, b, size); // NB: decoded in place
+                off += 4;
+                len -= 4;
+                size += 3;
+            }
+            // Don't decode if we hit the end or got a single leftover byte (invalid
+            // base64 but legal for skip of regular string type)
+            if (len > 1)
+            {
+                // Decode remainder
+                TBase64Utils.decode(b, off, len, b, size); // NB: decoded in place
+                size += len - 1;
+            }
+            // Sadly we must copy the byte[] (any way around this?)
+            byte[] result = new byte[size];
+            Array.Copy(b, 0, result, 0, size);
+            return result;
+        }
+
+        private void ReadJSONObjectStart()
+        {
+            context.Read();
+            ReadJSONSyntaxChar(LBRACE);
+            PushContext(new JSONPairContext(this));
+        }
+
+        private void ReadJSONObjectEnd()
+        {
+            ReadJSONSyntaxChar(RBRACE);
+            PopContext();
+        }
+
+        private void ReadJSONArrayStart()
+        {
+            context.Read();
+            ReadJSONSyntaxChar(LBRACKET);
+            PushContext(new JSONListContext(this));
+        }
+
+        private void ReadJSONArrayEnd()
+        {
+            ReadJSONSyntaxChar(RBRACKET);
+            PopContext();
+        }
+
+        public override TMessage ReadMessageBegin()
+        {
+            TMessage message = new TMessage();
+            ReadJSONArrayStart();
+            if (ReadJSONInteger() != VERSION)
+            {
+                throw new TProtocolException(TProtocolException.BAD_VERSION,
+                                             "Message contained bad version.");
+            }
+
+            var buf = ReadJSONString(false);
+            message.Name = utf8Encoding.GetString(buf, 0, buf.Length);
+            message.Type = (TMessageType)ReadJSONInteger();
+            message.SeqID = (int)ReadJSONInteger();
+            return message;
+        }
+
+        public override void ReadMessageEnd()
+        {
+            ReadJSONArrayEnd();
+        }
+
+        public override TStruct ReadStructBegin()
+        {
+            ReadJSONObjectStart();
+            return new TStruct();
+        }
+
+        public override void ReadStructEnd()
+        {
+            ReadJSONObjectEnd();
+        }
+
+        public override TField ReadFieldBegin()
+        {
+            TField field = new TField();
+            byte ch = reader.Peek();
+            if (ch == RBRACE[0])
+            {
+                field.Type = TType.Stop;
+            }
+            else
+            {
+                field.ID = (short)ReadJSONInteger();
+                ReadJSONObjectStart();
+                field.Type = GetTypeIDForTypeName(ReadJSONString(false));
+            }
+            return field;
+        }
+
+        public override void ReadFieldEnd()
+        {
+            ReadJSONObjectEnd();
+        }
+
+        public override TMap ReadMapBegin()
+        {
+            TMap map = new TMap();
+            ReadJSONArrayStart();
+            map.KeyType = GetTypeIDForTypeName(ReadJSONString(false));
+            map.ValueType = GetTypeIDForTypeName(ReadJSONString(false));
+            map.Count = (int)ReadJSONInteger();
+            ReadJSONObjectStart();
+            return map;
+        }
+
+        public override void ReadMapEnd()
+        {
+            ReadJSONObjectEnd();
+            ReadJSONArrayEnd();
+        }
+
+        public override TList ReadListBegin()
+        {
+            TList list = new TList();
+            ReadJSONArrayStart();
+            list.ElementType = GetTypeIDForTypeName(ReadJSONString(false));
+            list.Count = (int)ReadJSONInteger();
+            return list;
+        }
+
+        public override void ReadListEnd()
+        {
+            ReadJSONArrayEnd();
+        }
+
+        public override TSet ReadSetBegin()
+        {
+            TSet set = new TSet();
+            ReadJSONArrayStart();
+            set.ElementType = GetTypeIDForTypeName(ReadJSONString(false));
+            set.Count = (int)ReadJSONInteger();
+            return set;
+        }
+
+        public override void ReadSetEnd()
+        {
+            ReadJSONArrayEnd();
+        }
+
+        public override bool ReadBool()
+        {
+            return (ReadJSONInteger() == 0 ? false : true);
+        }
+
+        public override sbyte ReadByte()
+        {
+            return (sbyte)ReadJSONInteger();
+        }
+
+        public override short ReadI16()
+        {
+            return (short)ReadJSONInteger();
+        }
+
+        public override int ReadI32()
+        {
+            return (int)ReadJSONInteger();
+        }
+
+        public override long ReadI64()
+        {
+            return (long)ReadJSONInteger();
+        }
+
+        public override double ReadDouble()
+        {
+            return ReadJSONDouble();
+        }
+
+        public override string ReadString()
+        {
+            var buf = ReadJSONString(false);
+            return utf8Encoding.GetString(buf, 0, buf.Length);
+        }
+
+        public override byte[] ReadBinary()
+        {
+            return ReadJSONBase64();
+        }
+
+    }
+}
diff --git a/lib/csharp/src/Protocol/TList.cs b/lib/csharp/src/Protocol/TList.cs
new file mode 100644
index 0000000..0c8f214
--- /dev/null
+++ b/lib/csharp/src/Protocol/TList.cs
@@ -0,0 +1,54 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+    public struct TList
+    {
+        private TType elementType;
+        private int count;
+
+        public TList(TType elementType, int count)
+            :this()
+        {
+            this.elementType = elementType;
+            this.count = count;
+        }
+
+        public TType ElementType
+        {
+            get { return elementType; }
+            set { elementType = value; }
+        }
+
+        public int Count
+        {
+            get { return count; }
+            set { count = value; }
+        }
+    }
+}
diff --git a/lib/csharp/src/Protocol/TMap.cs b/lib/csharp/src/Protocol/TMap.cs
new file mode 100644
index 0000000..aba9d3a
--- /dev/null
+++ b/lib/csharp/src/Protocol/TMap.cs
@@ -0,0 +1,62 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+    public struct TMap
+    {
+        private TType keyType;
+        private TType valueType;
+        private int count;
+
+        public TMap(TType keyType, TType valueType, int count)
+            :this()
+        {
+            this.keyType = keyType;
+            this.valueType = valueType;
+            this.count = count;
+        }
+
+        public TType KeyType
+        {
+            get { return keyType; }
+            set { keyType = value; }
+        }
+
+        public TType ValueType
+        {
+            get { return valueType; }
+            set { valueType = value; }
+        }
+
+        public int Count
+        {
+            get { return count; }
+            set { count = value; }
+        }
+    }
+}
diff --git a/lib/csharp/src/Protocol/TMessage.cs b/lib/csharp/src/Protocol/TMessage.cs
new file mode 100644
index 0000000..348263c
--- /dev/null
+++ b/lib/csharp/src/Protocol/TMessage.cs
@@ -0,0 +1,62 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+    public struct TMessage
+    {
+        private string name;
+        private TMessageType type;
+        private int seqID;
+
+        public TMessage(string name, TMessageType type, int seqid)
+            :this()
+        {
+            this.name = name;
+            this.type = type;
+            this.seqID = seqid;
+        }
+
+        public string Name
+        {
+            get { return name; }
+            set { name = value; }
+        }
+
+        public TMessageType Type
+        {
+            get { return type; }
+            set { type = value; }
+        }
+
+        public int SeqID
+        {
+            get { return seqID; }
+            set { seqID = value; }
+        }
+    }
+}
diff --git a/lib/csharp/src/Protocol/TMessageType.cs b/lib/csharp/src/Protocol/TMessageType.cs
new file mode 100644
index 0000000..c7091fe
--- /dev/null
+++ b/lib/csharp/src/Protocol/TMessageType.cs
@@ -0,0 +1,31 @@
+/**
+ * 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;
+
+namespace Thrift.Protocol
+{
+    public enum TMessageType
+    {
+        Call = 1,
+        Reply = 2,
+        Exception = 3,
+        Oneway = 4
+    }
+}
diff --git a/lib/csharp/src/Protocol/TMultiplexedProcessor.cs b/lib/csharp/src/Protocol/TMultiplexedProcessor.cs
new file mode 100644
index 0000000..aa91c52
--- /dev/null
+++ b/lib/csharp/src/Protocol/TMultiplexedProcessor.cs
@@ -0,0 +1,183 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Text;
+using Thrift.Transport;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Thrift.Protocol
+{
+    /// <summary>
+    /// <see cref="TMultiplexedProcessor"/> is a <see cref="TProcessor"/> allowing a single <see cref="Thrift.Server.TServer"/>
+    /// to provide multiple services.
+    /// <para/>
+    /// To do so, you instantiate the processor and then register additional processors with it,
+    /// as shown in the following example:
+    /// <para/>
+    /// <code>
+    ///     TMultiplexedProcessor processor = new TMultiplexedProcessor();
+    ///
+    ///     processor.registerProcessor(
+    ///         "Calculator",
+    ///         new Calculator.Processor(new CalculatorHandler()));
+    ///
+    ///     processor.registerProcessor(
+    ///         "WeatherReport",
+    ///         new WeatherReport.Processor(new WeatherReportHandler()));
+    ///
+    ///     TServerTransport t = new TServerSocket(9090);
+    ///     TSimpleServer server = new TSimpleServer(processor, t);
+    ///
+    ///     server.serve();
+    /// </code>
+    /// </summary>
+    public class TMultiplexedProcessor : TProcessor
+    {
+        private Dictionary<string, TProcessor> ServiceProcessorMap = new Dictionary<string, TProcessor>();
+
+        /// <summary>
+        /// 'Register' a service with this TMultiplexedProcessor. This allows us to broker
+        /// requests to individual services by using the service name to select them at request time.
+        ///
+        /// Args:
+        /// - serviceName    Name of a service, has to be identical to the name
+        ///                  declared in the Thrift IDL, e.g. "WeatherReport".
+        /// - processor      Implementation of a service, usually referred to as "handlers",
+        ///                  e.g. WeatherReportHandler implementing WeatherReport.Iface.
+        /// </summary>
+        public void RegisterProcessor(string serviceName, TProcessor processor)
+        {
+            ServiceProcessorMap.Add(serviceName, processor);
+        }
+
+
+        private void Fail(TProtocol oprot, TMessage message, TApplicationException.ExceptionType extype, string etxt)
+        {
+            TApplicationException appex = new TApplicationException(extype, etxt);
+
+            TMessage newMessage = new TMessage(message.Name, TMessageType.Exception, message.SeqID);
+
+            oprot.WriteMessageBegin(newMessage);
+            appex.Write(oprot);
+            oprot.WriteMessageEnd();
+            oprot.Transport.Flush();
+        }
+
+
+        /// <summary>
+        /// This implementation of process performs the following steps:
+        ///
+        /// - Read the beginning of the message.
+        /// - Extract the service name from the message.
+        /// - Using the service name to locate the appropriate processor.
+        /// - Dispatch to the processor, with a decorated instance of TProtocol
+        ///    that allows readMessageBegin() to return the original TMessage.
+        /// <para/>
+        /// Throws an exception if
+        /// - the message type is not CALL or ONEWAY,
+        /// - the service name was not found in the message, or
+        /// - the service name has not been RegisterProcessor()ed.
+        /// </summary>
+        public bool Process(TProtocol iprot, TProtocol oprot)
+        {
+            /*  Use the actual underlying protocol (e.g. TBinaryProtocol) to read the
+                message header.  This pulls the message "off the wire", which we'll
+                deal with at the end of this method. */
+
+            try
+            {
+                TMessage message = iprot.ReadMessageBegin();
+
+                if ((message.Type != TMessageType.Call) && (message.Type != TMessageType.Oneway))
+                {
+                    Fail(oprot, message,
+                          TApplicationException.ExceptionType.InvalidMessageType,
+                          "Message type CALL or ONEWAY expected");
+                    return false;
+                }
+
+                // Extract the service name
+                int index = message.Name.IndexOf(TMultiplexedProtocol.SEPARATOR);
+                if (index < 0)
+                {
+                    Fail(oprot, message,
+                          TApplicationException.ExceptionType.InvalidProtocol,
+                          "Service name not found in message name: " + message.Name + ". " +
+                          "Did you forget to use a TMultiplexProtocol in your client?");
+                    return false;
+                }
+
+                // Create a new TMessage, something that can be consumed by any TProtocol
+                string serviceName = message.Name.Substring(0, index);
+                TProcessor actualProcessor;
+                if (!ServiceProcessorMap.TryGetValue(serviceName, out actualProcessor))
+                {
+                    Fail(oprot, message,
+                          TApplicationException.ExceptionType.InternalError,
+                          "Service name not found: " + serviceName + ". " +
+                          "Did you forget to call RegisterProcessor()?");
+                    return false;
+                }
+
+                // Create a new TMessage, removing the service name
+                TMessage newMessage = new TMessage(
+                        message.Name.Substring(serviceName.Length + TMultiplexedProtocol.SEPARATOR.Length),
+                        message.Type,
+                        message.SeqID);
+
+                // Dispatch processing to the stored processor
+                return actualProcessor.Process(new StoredMessageProtocol(iprot, newMessage), oprot);
+
+            }
+            catch (IOException)
+            {
+                return false;  // similar to all other processors
+            }
+
+        }
+
+        /// <summary>
+        ///  Our goal was to work with any protocol.  In order to do that, we needed
+        ///  to allow them to call readMessageBegin() and get a TMessage in exactly
+        ///  the standard format, without the service name prepended to TMessage.name.
+        /// </summary>
+        private class StoredMessageProtocol : TProtocolDecorator
+        {
+            TMessage MsgBegin;
+
+            public StoredMessageProtocol(TProtocol protocol, TMessage messageBegin)
+                : base(protocol)
+            {
+                this.MsgBegin = messageBegin;
+            }
+
+            public override TMessage ReadMessageBegin()
+            {
+                return MsgBegin;
+            }
+        }
+
+    }
+}
diff --git a/lib/csharp/src/Protocol/TMultiplexedProtocol.cs b/lib/csharp/src/Protocol/TMultiplexedProtocol.cs
new file mode 100644
index 0000000..1bd420f
--- /dev/null
+++ b/lib/csharp/src/Protocol/TMultiplexedProtocol.cs
@@ -0,0 +1,103 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Text;
+using Thrift.Transport;
+using System.Collections.Generic;
+
+namespace Thrift.Protocol
+{
+
+    /// <summary>
+    /// TMultiplexedProtocol is a protocol-independent concrete decorator that allows a Thrift
+    /// client to communicate with a multiplexing Thrift server, by prepending the service name
+    /// to the function name during function calls.
+    /// <para/>
+    /// NOTE: THIS IS NOT TO BE USED BY SERVERS.
+    /// On the server, use TMultiplexedProcessor to handle requests from a multiplexing client.
+    /// <para/>
+    /// This example uses a single socket transport to invoke two services:
+    /// <code>
+    ///     TSocket transport = new TSocket("localhost", 9090);
+    ///     transport.open();
+    ///
+    ///     TBinaryProtocol protocol = new TBinaryProtocol(transport);
+    ///
+    ///     TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "Calculator");
+    ///     Calculator.Client service = new Calculator.Client(mp);
+    ///
+    ///     TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "WeatherReport");
+    ///     WeatherReport.Client service2 = new WeatherReport.Client(mp2);
+    ///
+    ///     System.out.println(service.add(2,2));
+    ///     System.out.println(service2.getTemperature());
+    /// </code>
+    /// </summary>
+    public class TMultiplexedProtocol : TProtocolDecorator
+    {
+
+        /// <summary>
+        /// Used to delimit the service name from the function name.
+        /// </summary>
+        public static string SEPARATOR = ":";
+
+        private string ServiceName;
+
+        /// <summary>
+        /// Wrap the specified protocol, allowing it to be used to communicate with a
+        /// multiplexing server.  The <paramref name="serviceName"/> is required as it is
+        /// prepended to the message header so that the multiplexing server can broker
+        /// the function call to the proper service.
+        /// </summary>
+        /// <param name="protocol">Your communication protocol of choice, e.g. <see cref="TBinaryProtocol"/>.</param>
+        /// <param name="serviceName">The service name of the service communicating via this protocol.</param>
+        public TMultiplexedProtocol(TProtocol protocol, string serviceName)
+            : base(protocol)
+        {
+            ServiceName = serviceName;
+        }
+
+        /// <summary>
+        /// Prepends the service name to the function name, separated by TMultiplexedProtocol.SEPARATOR.
+        /// </summary>
+        /// <param name="tMessage">The original message.</param>
+        public override void WriteMessageBegin(TMessage tMessage)
+        {
+            switch (tMessage.Type)
+            {
+                case TMessageType.Call:
+                case TMessageType.Oneway:
+                    base.WriteMessageBegin(new TMessage(
+                        ServiceName + SEPARATOR + tMessage.Name,
+                        tMessage.Type,
+                        tMessage.SeqID));
+                    break;
+
+                default:
+                    base.WriteMessageBegin(tMessage);
+                    break;
+            }
+        }
+    }
+}
diff --git a/lib/csharp/src/Protocol/TProtocol.cs b/lib/csharp/src/Protocol/TProtocol.cs
new file mode 100644
index 0000000..dd7a6e0
--- /dev/null
+++ b/lib/csharp/src/Protocol/TProtocol.cs
@@ -0,0 +1,142 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Text;
+using Thrift.Transport;
+
+namespace Thrift.Protocol
+{
+    public abstract class TProtocol : IDisposable
+    {
+        private const int DEFAULT_RECURSION_DEPTH = 64;
+
+        protected TTransport trans;
+        protected int recursionLimit;
+        protected int recursionDepth;
+
+        protected TProtocol(TTransport trans)
+        {
+            this.trans = trans;
+            this.recursionLimit = DEFAULT_RECURSION_DEPTH;
+            this.recursionDepth = 0;
+        }
+
+        public TTransport Transport
+        {
+            get { return trans; }
+        }
+
+        public int RecursionLimit
+        {
+            get { return recursionLimit; }
+            set { recursionLimit = value; }
+        }
+
+        public void IncrementRecursionDepth()
+        {
+            if (recursionDepth < recursionLimit)
+                ++recursionDepth;
+            else
+                throw new TProtocolException(TProtocolException.DEPTH_LIMIT, "Depth limit exceeded");
+        }
+
+        public void DecrementRecursionDepth()
+        {
+            --recursionDepth;
+        }
+
+        #region " IDisposable Support "
+        private bool _IsDisposed;
+
+        // IDisposable
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (trans is IDisposable)
+                        (trans as IDisposable).Dispose();
+                }
+            }
+            _IsDisposed = true;
+        }
+        #endregion
+
+        public abstract void WriteMessageBegin(TMessage message);
+        public abstract void WriteMessageEnd();
+        public abstract void WriteStructBegin(TStruct struc);
+        public abstract void WriteStructEnd();
+        public abstract void WriteFieldBegin(TField field);
+        public abstract void WriteFieldEnd();
+        public abstract void WriteFieldStop();
+        public abstract void WriteMapBegin(TMap map);
+        public abstract void WriteMapEnd();
+        public abstract void WriteListBegin(TList list);
+        public abstract void WriteListEnd();
+        public abstract void WriteSetBegin(TSet set);
+        public abstract void WriteSetEnd();
+        public abstract void WriteBool(bool b);
+        public abstract void WriteByte(sbyte b);
+        public abstract void WriteI16(short i16);
+        public abstract void WriteI32(int i32);
+        public abstract void WriteI64(long i64);
+        public abstract void WriteDouble(double d);
+        public virtual void WriteString(string s)
+        {
+            WriteBinary(Encoding.UTF8.GetBytes(s));
+        }
+        public abstract void WriteBinary(byte[] b);
+
+        public abstract TMessage ReadMessageBegin();
+        public abstract void ReadMessageEnd();
+        public abstract TStruct ReadStructBegin();
+        public abstract void ReadStructEnd();
+        public abstract TField ReadFieldBegin();
+        public abstract void ReadFieldEnd();
+        public abstract TMap ReadMapBegin();
+        public abstract void ReadMapEnd();
+        public abstract TList ReadListBegin();
+        public abstract void ReadListEnd();
+        public abstract TSet ReadSetBegin();
+        public abstract void ReadSetEnd();
+        public abstract bool ReadBool();
+        public abstract sbyte ReadByte();
+        public abstract short ReadI16();
+        public abstract int ReadI32();
+        public abstract long ReadI64();
+        public abstract double ReadDouble();
+        public virtual string ReadString()
+        {
+            var buf = ReadBinary();
+            return Encoding.UTF8.GetString(buf, 0, buf.Length);
+        }
+        public abstract byte[] ReadBinary();
+    }
+}
diff --git a/lib/csharp/src/Protocol/TProtocolDecorator.cs b/lib/csharp/src/Protocol/TProtocolDecorator.cs
new file mode 100644
index 0000000..8600002
--- /dev/null
+++ b/lib/csharp/src/Protocol/TProtocolDecorator.cs
@@ -0,0 +1,261 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Text;
+using Thrift.Transport;
+using System.Collections.Generic;
+
+namespace Thrift.Protocol
+{
+    /// <summary>
+    /// <see cref="TProtocolDecorator"/> forwards all requests to an enclosed <see cref="TProtocol"/> instance,
+    /// providing a way to author concise concrete decorator subclasses. While it has
+    /// no abstract methods, it is marked abstract as a reminder that by itself,
+    /// it does not modify the behaviour of the enclosed <see cref="TProtocol"/>.
+    /// <para/>
+    /// See p.175 of Design Patterns (by Gamma et al.)
+    /// </summary>
+    /// <seealso cref="TMultiplexedProtocol"/>
+    public abstract class TProtocolDecorator : TProtocol
+    {
+        private TProtocol WrappedProtocol;
+
+        /// <summary>
+        /// Encloses the specified protocol.
+        /// </summary>
+        /// <param name="protocol">All operations will be forward to this protocol.  Must be non-null.</param>
+        public TProtocolDecorator(TProtocol protocol)
+            : base(protocol.Transport)
+        {
+
+            WrappedProtocol = protocol;
+        }
+
+        public override void WriteMessageBegin(TMessage tMessage)
+        {
+            WrappedProtocol.WriteMessageBegin(tMessage);
+        }
+
+        public override void WriteMessageEnd()
+        {
+            WrappedProtocol.WriteMessageEnd();
+        }
+
+        public override void WriteStructBegin(TStruct tStruct)
+        {
+            WrappedProtocol.WriteStructBegin(tStruct);
+        }
+
+        public override void WriteStructEnd()
+        {
+            WrappedProtocol.WriteStructEnd();
+        }
+
+        public override void WriteFieldBegin(TField tField)
+        {
+            WrappedProtocol.WriteFieldBegin(tField);
+        }
+
+        public override void WriteFieldEnd()
+        {
+            WrappedProtocol.WriteFieldEnd();
+        }
+
+        public override void WriteFieldStop()
+        {
+            WrappedProtocol.WriteFieldStop();
+        }
+
+        public override void WriteMapBegin(TMap tMap)
+        {
+            WrappedProtocol.WriteMapBegin(tMap);
+        }
+
+        public override void WriteMapEnd()
+        {
+            WrappedProtocol.WriteMapEnd();
+        }
+
+        public override void WriteListBegin(TList tList)
+        {
+            WrappedProtocol.WriteListBegin(tList);
+        }
+
+        public override void WriteListEnd()
+        {
+            WrappedProtocol.WriteListEnd();
+        }
+
+        public override void WriteSetBegin(TSet tSet)
+        {
+            WrappedProtocol.WriteSetBegin(tSet);
+        }
+
+        public override void WriteSetEnd()
+        {
+            WrappedProtocol.WriteSetEnd();
+        }
+
+        public override void WriteBool(bool b)
+        {
+            WrappedProtocol.WriteBool(b);
+        }
+
+        public override void WriteByte(sbyte b)
+        {
+            WrappedProtocol.WriteByte(b);
+        }
+
+        public override void WriteI16(short i)
+        {
+            WrappedProtocol.WriteI16(i);
+        }
+
+        public override void WriteI32(int i)
+        {
+            WrappedProtocol.WriteI32(i);
+        }
+
+        public override void WriteI64(long l)
+        {
+            WrappedProtocol.WriteI64(l);
+        }
+
+        public override void WriteDouble(double v)
+        {
+            WrappedProtocol.WriteDouble(v);
+        }
+
+        public override void WriteString(string s)
+        {
+            WrappedProtocol.WriteString(s);
+        }
+
+        public override void WriteBinary(byte[] bytes)
+        {
+            WrappedProtocol.WriteBinary(bytes);
+        }
+
+        public override TMessage ReadMessageBegin()
+        {
+            return WrappedProtocol.ReadMessageBegin();
+        }
+
+        public override void ReadMessageEnd()
+        {
+            WrappedProtocol.ReadMessageEnd();
+        }
+
+        public override TStruct ReadStructBegin()
+        {
+            return WrappedProtocol.ReadStructBegin();
+        }
+
+        public override void ReadStructEnd()
+        {
+            WrappedProtocol.ReadStructEnd();
+        }
+
+        public override TField ReadFieldBegin()
+        {
+            return WrappedProtocol.ReadFieldBegin();
+        }
+
+        public override void ReadFieldEnd()
+        {
+            WrappedProtocol.ReadFieldEnd();
+        }
+
+        public override TMap ReadMapBegin()
+        {
+            return WrappedProtocol.ReadMapBegin();
+        }
+
+        public override void ReadMapEnd()
+        {
+            WrappedProtocol.ReadMapEnd();
+        }
+
+        public override TList ReadListBegin()
+        {
+            return WrappedProtocol.ReadListBegin();
+        }
+
+        public override void ReadListEnd()
+        {
+            WrappedProtocol.ReadListEnd();
+        }
+
+        public override TSet ReadSetBegin()
+        {
+            return WrappedProtocol.ReadSetBegin();
+        }
+
+        public override void ReadSetEnd()
+        {
+            WrappedProtocol.ReadSetEnd();
+        }
+
+        public override bool ReadBool()
+        {
+            return WrappedProtocol.ReadBool();
+        }
+
+        public override sbyte ReadByte()
+        {
+            return WrappedProtocol.ReadByte();
+        }
+
+        public override short ReadI16()
+        {
+            return WrappedProtocol.ReadI16();
+        }
+
+        public override int ReadI32()
+        {
+            return WrappedProtocol.ReadI32();
+        }
+
+        public override long ReadI64()
+        {
+            return WrappedProtocol.ReadI64();
+        }
+
+        public override double ReadDouble()
+        {
+            return WrappedProtocol.ReadDouble();
+        }
+
+        public override string ReadString()
+        {
+            return WrappedProtocol.ReadString();
+        }
+
+        public override byte[] ReadBinary()
+        {
+            return WrappedProtocol.ReadBinary();
+        }
+    }
+
+}
diff --git a/lib/csharp/src/Protocol/TProtocolException.cs b/lib/csharp/src/Protocol/TProtocolException.cs
new file mode 100644
index 0000000..7bef236
--- /dev/null
+++ b/lib/csharp/src/Protocol/TProtocolException.cs
@@ -0,0 +1,67 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift.Protocol
+{
+    public class TProtocolException : TException
+    {
+        public const int UNKNOWN = 0;
+        public const int INVALID_DATA = 1;
+        public const int NEGATIVE_SIZE = 2;
+        public const int SIZE_LIMIT = 3;
+        public const int BAD_VERSION = 4;
+        public const int NOT_IMPLEMENTED = 5;
+        public const int DEPTH_LIMIT = 6;
+
+        protected int type_ = UNKNOWN;
+
+        public TProtocolException()
+            : base()
+        {
+        }
+
+        public TProtocolException(int type, Exception inner = null)
+            : base(string.Empty, inner)
+        {
+            type_ = type;
+        }
+
+        public TProtocolException(int type, string message, Exception inner = null)
+            : base(message, inner)
+        {
+            type_ = type;
+        }
+
+        public TProtocolException(string message, Exception inner = null)
+            : base(message, inner)
+        {
+        }
+
+        public int getType()
+        {
+            return type_;
+        }
+    }
+}
diff --git a/lib/csharp/src/Protocol/TProtocolFactory.cs b/lib/csharp/src/Protocol/TProtocolFactory.cs
new file mode 100644
index 0000000..71360a1
--- /dev/null
+++ b/lib/csharp/src/Protocol/TProtocolFactory.cs
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using Thrift.Transport;
+
+namespace Thrift.Protocol
+{
+    public interface TProtocolFactory
+    {
+        TProtocol GetProtocol(TTransport trans);
+    }
+}
diff --git a/lib/csharp/src/Protocol/TProtocolUtil.cs b/lib/csharp/src/Protocol/TProtocolUtil.cs
new file mode 100644
index 0000000..d995c6c
--- /dev/null
+++ b/lib/csharp/src/Protocol/TProtocolUtil.cs
@@ -0,0 +1,108 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift.Protocol
+{
+    public static class TProtocolUtil
+    {
+        public static void Skip(TProtocol prot, TType type)
+        {
+            prot.IncrementRecursionDepth();
+            try
+            {
+                switch (type)
+                {
+                    case TType.Bool:
+                        prot.ReadBool();
+                        break;
+                    case TType.Byte:
+                        prot.ReadByte();
+                        break;
+                    case TType.I16:
+                        prot.ReadI16();
+                        break;
+                    case TType.I32:
+                        prot.ReadI32();
+                        break;
+                    case TType.I64:
+                        prot.ReadI64();
+                        break;
+                    case TType.Double:
+                        prot.ReadDouble();
+                        break;
+                    case TType.String:
+                        // Don't try to decode the string, just skip it.
+                        prot.ReadBinary();
+                        break;
+                    case TType.Struct:
+                        prot.ReadStructBegin();
+                        while (true)
+                        {
+                            TField field = prot.ReadFieldBegin();
+                            if (field.Type == TType.Stop)
+                            {
+                                break;
+                            }
+                            Skip(prot, field.Type);
+                            prot.ReadFieldEnd();
+                        }
+                        prot.ReadStructEnd();
+                        break;
+                    case TType.Map:
+                        TMap map = prot.ReadMapBegin();
+                        for (int i = 0; i < map.Count; i++)
+                        {
+                            Skip(prot, map.KeyType);
+                            Skip(prot, map.ValueType);
+                        }
+                        prot.ReadMapEnd();
+                        break;
+                    case TType.Set:
+                        TSet set = prot.ReadSetBegin();
+                        for (int i = 0; i < set.Count; i++)
+                        {
+                            Skip(prot, set.ElementType);
+                        }
+                        prot.ReadSetEnd();
+                        break;
+                    case TType.List:
+                        TList list = prot.ReadListBegin();
+                        for (int i = 0; i < list.Count; i++)
+                        {
+                            Skip(prot, list.ElementType);
+                        }
+                        prot.ReadListEnd();
+                        break;
+                    default:
+                        throw new TProtocolException(TProtocolException.INVALID_DATA, "Unknown data type " + type.ToString("d"));
+                }
+            }
+            finally
+            {
+                prot.DecrementRecursionDepth();
+            }
+        }
+    }
+}
diff --git a/lib/csharp/src/Protocol/TSet.cs b/lib/csharp/src/Protocol/TSet.cs
new file mode 100644
index 0000000..a918ab5
--- /dev/null
+++ b/lib/csharp/src/Protocol/TSet.cs
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+    public struct TSet
+    {
+        private TType elementType;
+        private int count;
+
+        public TSet(TType elementType, int count)
+            :this()
+        {
+            this.elementType = elementType;
+            this.count = count;
+        }
+
+        public TSet(TList list)
+            : this(list.ElementType, list.Count)
+        {
+        }
+
+        public TType ElementType
+        {
+            get { return elementType; }
+            set { elementType = value; }
+        }
+
+        public int Count
+        {
+            get { return count; }
+            set { count = value; }
+        }
+    }
+}
diff --git a/lib/csharp/src/Protocol/TStruct.cs b/lib/csharp/src/Protocol/TStruct.cs
new file mode 100644
index 0000000..f4844a4
--- /dev/null
+++ b/lib/csharp/src/Protocol/TStruct.cs
@@ -0,0 +1,46 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Thrift.Protocol
+{
+    public struct TStruct
+    {
+        private string name;
+
+        public TStruct(string name)
+            :this()
+        {
+            this.name = name;
+        }
+
+        public string Name
+        {
+            get { return name; }
+            set { name = value; }
+        }
+    }
+}
diff --git a/lib/csharp/src/Protocol/TType.cs b/lib/csharp/src/Protocol/TType.cs
new file mode 100644
index 0000000..9ce915e
--- /dev/null
+++ b/lib/csharp/src/Protocol/TType.cs
@@ -0,0 +1,44 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift.Protocol
+{
+    public enum TType : byte
+    {
+        Stop = 0,
+        Void = 1,
+        Bool = 2,
+        Byte = 3,
+        Double = 4,
+        I16 = 6,
+        I32 = 8,
+        I64 = 10,
+        String = 11,
+        Struct = 12,
+        Map = 13,
+        Set = 14,
+        List = 15
+    }
+}
diff --git a/lib/csharp/src/Server/TServer.cs b/lib/csharp/src/Server/TServer.cs
new file mode 100644
index 0000000..2bc04f3
--- /dev/null
+++ b/lib/csharp/src/Server/TServer.cs
@@ -0,0 +1,155 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using Thrift.Protocol;
+using Thrift.Transport;
+using System.IO;
+
+namespace Thrift.Server
+{
+    public abstract class TServer
+    {
+        //Attributes
+        protected TProcessorFactory processorFactory;
+        protected TServerTransport serverTransport;
+        protected TTransportFactory inputTransportFactory;
+        protected TTransportFactory outputTransportFactory;
+        protected TProtocolFactory inputProtocolFactory;
+        protected TProtocolFactory outputProtocolFactory;
+        protected TServerEventHandler serverEventHandler = null;
+
+        //Methods
+        public void setEventHandler(TServerEventHandler seh)
+        {
+            serverEventHandler = seh;
+        }
+        public TServerEventHandler getEventHandler()
+        {
+            return serverEventHandler;
+        }
+
+        //Log delegation
+        public delegate void LogDelegate(string str);
+        private LogDelegate _logDelegate;
+        protected LogDelegate logDelegate
+        {
+            get { return _logDelegate; }
+            set { _logDelegate = (value != null) ? value : DefaultLogDelegate; }
+        }
+        protected static void DefaultLogDelegate(string s)
+        {
+            Console.Error.WriteLine(s);
+        }
+
+        //Construction
+        public TServer(TProcessor processor,
+                  TServerTransport serverTransport)
+          : this(processor, serverTransport,
+             new TTransportFactory(),
+             new TTransportFactory(),
+             new TBinaryProtocol.Factory(),
+             new TBinaryProtocol.Factory(),
+             DefaultLogDelegate)
+        {
+        }
+
+        public TServer(TProcessor processor,
+                TServerTransport serverTransport,
+                LogDelegate logDelegate)
+          : this(processor,
+             serverTransport,
+             new TTransportFactory(),
+             new TTransportFactory(),
+             new TBinaryProtocol.Factory(),
+             new TBinaryProtocol.Factory(),
+             logDelegate)
+        {
+        }
+
+        public TServer(TProcessor processor,
+                  TServerTransport serverTransport,
+                  TTransportFactory transportFactory)
+          : this(processor,
+             serverTransport,
+             transportFactory,
+             transportFactory,
+             new TBinaryProtocol.Factory(),
+             new TBinaryProtocol.Factory(),
+             DefaultLogDelegate)
+        {
+        }
+
+        public TServer(TProcessor processor,
+                  TServerTransport serverTransport,
+                  TTransportFactory transportFactory,
+                  TProtocolFactory protocolFactory)
+          : this(processor,
+             serverTransport,
+             transportFactory,
+             transportFactory,
+             protocolFactory,
+             protocolFactory,
+               DefaultLogDelegate)
+        {
+        }
+
+        public TServer(TProcessor processor,
+            TServerTransport serverTransport,
+            TTransportFactory inputTransportFactory,
+            TTransportFactory outputTransportFactory,
+            TProtocolFactory inputProtocolFactory,
+            TProtocolFactory outputProtocolFactory,
+            LogDelegate logDelegate)
+        {
+            this.processorFactory = new TSingletonProcessorFactory(processor);
+            this.serverTransport = serverTransport;
+            this.inputTransportFactory = inputTransportFactory;
+            this.outputTransportFactory = outputTransportFactory;
+            this.inputProtocolFactory = inputProtocolFactory;
+            this.outputProtocolFactory = outputProtocolFactory;
+            this.logDelegate = (logDelegate != null) ? logDelegate : DefaultLogDelegate;
+        }
+
+        public TServer(TProcessorFactory processorFactory,
+                  TServerTransport serverTransport,
+                  TTransportFactory inputTransportFactory,
+                  TTransportFactory outputTransportFactory,
+                  TProtocolFactory inputProtocolFactory,
+                  TProtocolFactory outputProtocolFactory,
+                  LogDelegate logDelegate)
+        {
+            this.processorFactory = processorFactory;
+            this.serverTransport = serverTransport;
+            this.inputTransportFactory = inputTransportFactory;
+            this.outputTransportFactory = outputTransportFactory;
+            this.inputProtocolFactory = inputProtocolFactory;
+            this.outputProtocolFactory = outputProtocolFactory;
+            this.logDelegate = (logDelegate != null) ? logDelegate : DefaultLogDelegate;
+        }
+
+        //Abstract Interface
+        public abstract void Serve();
+        public abstract void Stop();
+    }
+}
diff --git a/lib/csharp/src/Server/TServerEventHandler.cs b/lib/csharp/src/Server/TServerEventHandler.cs
new file mode 100644
index 0000000..e81efc6
--- /dev/null
+++ b/lib/csharp/src/Server/TServerEventHandler.cs
@@ -0,0 +1,53 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift.Server
+{
+    /// <summary>
+    /// Interface implemented by server users to handle events from the server.
+    /// </summary>
+    public interface TServerEventHandler
+    {
+        /// <summary>
+        /// Called before the server begins.
+        /// </summary>
+        void preServe();
+
+        /// <summary>
+        /// Called when a new client has connected and is about to being processing.
+        /// </summary>
+        object createContext(Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output);
+
+        /// <summary>
+        /// Called when a client has finished request-handling to delete server context.
+        /// </summary>
+        void deleteContext(object serverContext, Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output);
+
+        /// <summary>
+        /// Called when a client is about to call the processor.
+        /// </summary>
+        void processContext(object serverContext, Thrift.Transport.TTransport transport);
+    };
+}
diff --git a/lib/csharp/src/Server/TSimpleServer.cs b/lib/csharp/src/Server/TSimpleServer.cs
new file mode 100644
index 0000000..4e7ea96
--- /dev/null
+++ b/lib/csharp/src/Server/TSimpleServer.cs
@@ -0,0 +1,180 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using Thrift.Transport;
+using Thrift.Protocol;
+
+namespace Thrift.Server
+{
+    /// <summary>
+    /// Simple single-threaded server for testing.
+    /// </summary>
+    public class TSimpleServer : TServer
+    {
+        private bool stop = false;
+
+        public TSimpleServer(TProcessor processor,
+                  TServerTransport serverTransport)
+          : base(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), DefaultLogDelegate)
+        {
+        }
+
+        public TSimpleServer(TProcessor processor,
+                  TServerTransport serverTransport,
+                  LogDelegate logDel)
+          : base(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), logDel)
+        {
+        }
+
+        public TSimpleServer(TProcessor processor,
+                  TServerTransport serverTransport,
+                  TTransportFactory transportFactory)
+          : base(processor,
+             serverTransport,
+             transportFactory,
+             transportFactory,
+             new TBinaryProtocol.Factory(),
+             new TBinaryProtocol.Factory(),
+               DefaultLogDelegate)
+        {
+        }
+
+        public TSimpleServer(TProcessor processor,
+            TServerTransport serverTransport,
+            TTransportFactory transportFactory,
+            TProtocolFactory protocolFactory)
+            : base(processor,
+               serverTransport,
+               transportFactory,
+               transportFactory,
+               protocolFactory,
+               protocolFactory,
+               DefaultLogDelegate)
+        {
+        }
+
+        public TSimpleServer(TProcessorFactory processorFactory,
+                  TServerTransport serverTransport,
+                  TTransportFactory transportFactory,
+                  TProtocolFactory protocolFactory)
+          : base(processorFactory,
+             serverTransport,
+             transportFactory,
+             transportFactory,
+             protocolFactory,
+             protocolFactory,
+             DefaultLogDelegate)
+        {
+        }
+
+        public override void Serve()
+        {
+            try
+            {
+                serverTransport.Listen();
+            }
+            catch (TTransportException ttx)
+            {
+                logDelegate(ttx.ToString());
+                return;
+            }
+
+            //Fire the preServe server event when server is up but before any client connections
+            if (serverEventHandler != null)
+                serverEventHandler.preServe();
+
+            while (!stop)
+            {
+                TProcessor processor = null;
+                TTransport client = null;
+                TTransport inputTransport = null;
+                TTransport outputTransport = null;
+                TProtocol inputProtocol = null;
+                TProtocol outputProtocol = null;
+                object connectionContext = null;
+                try
+                {
+                    using (client = serverTransport.Accept())
+                    {
+                        processor = processorFactory.GetProcessor(client);
+                        if (client != null)
+                        {
+                            using (inputTransport = inputTransportFactory.GetTransport(client))
+                            {
+                                using (outputTransport = outputTransportFactory.GetTransport(client))
+                                {
+                                    inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+                                    outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
+
+                                    //Recover event handler (if any) and fire createContext server event when a client connects
+                                    if (serverEventHandler != null)
+                                        connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
+
+                                    //Process client requests until client disconnects
+                                    while (!stop)
+                                    {
+                                        if (!inputTransport.Peek())
+                                            break;
+
+                                        //Fire processContext server event
+                                        //N.B. This is the pattern implemented in C++ and the event fires provisionally.
+                                        //That is to say it may be many minutes between the event firing and the client request
+                                        //actually arriving or the client may hang up without ever makeing a request.
+                                        if (serverEventHandler != null)
+                                            serverEventHandler.processContext(connectionContext, inputTransport);
+                                        //Process client request (blocks until transport is readable)
+                                        if (!processor.Process(inputProtocol, outputProtocol))
+                                            break;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                catch (TTransportException ttx)
+                {
+                    if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted)
+                    {
+                        logDelegate(ttx.ToString());
+                    }
+                }
+                catch (Exception x)
+                {
+                    //Unexpected
+                    logDelegate(x.ToString());
+                }
+
+                //Fire deleteContext server event after client disconnects
+                if (serverEventHandler != null)
+                    serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+            }
+        }
+
+        public override void Stop()
+        {
+            stop = true;
+            serverTransport.Close();
+        }
+    }
+}
diff --git a/lib/csharp/src/Server/TThreadPoolServer.cs b/lib/csharp/src/Server/TThreadPoolServer.cs
new file mode 100644
index 0000000..a494ce7
--- /dev/null
+++ b/lib/csharp/src/Server/TThreadPoolServer.cs
@@ -0,0 +1,295 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Threading;
+using Thrift.Protocol;
+using Thrift.Transport;
+
+namespace Thrift.Server
+{
+    /// <summary>
+    /// Server that uses C# built-in ThreadPool to spawn threads when handling requests.
+    /// </summary>
+    public class TThreadPoolServer : TServer
+    {
+        private const int DEFAULT_MIN_THREADS = -1;  // use .NET ThreadPool defaults
+        private const int DEFAULT_MAX_THREADS = -1;  // use .NET ThreadPool defaults
+        private volatile bool stop = false;
+
+        public struct Configuration
+        {
+            public int MinWorkerThreads;
+            public int MaxWorkerThreads;
+            public int MinIOThreads;
+            public int MaxIOThreads;
+
+            public Configuration(int min = DEFAULT_MIN_THREADS, int max = DEFAULT_MAX_THREADS)
+            {
+                MinWorkerThreads = min;
+                MaxWorkerThreads = max;
+                MinIOThreads = min;
+                MaxIOThreads = max;
+            }
+
+            public Configuration(int minWork, int maxWork, int minIO, int maxIO)
+            {
+                MinWorkerThreads = minWork;
+                MaxWorkerThreads = maxWork;
+                MinIOThreads = minIO;
+                MaxIOThreads = maxIO;
+            }
+        }
+
+        public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport)
+            : this(new TSingletonProcessorFactory(processor), serverTransport,
+             new TTransportFactory(), new TTransportFactory(),
+             new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+             new Configuration(), DefaultLogDelegate)
+        {
+        }
+
+        public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport, LogDelegate logDelegate)
+            : this(new TSingletonProcessorFactory(processor), serverTransport,
+             new TTransportFactory(), new TTransportFactory(),
+             new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+             new Configuration(), logDelegate)
+        {
+        }
+
+        public TThreadPoolServer(TProcessor processor,
+         TServerTransport serverTransport,
+         TTransportFactory transportFactory,
+         TProtocolFactory protocolFactory)
+            : this(new TSingletonProcessorFactory(processor), serverTransport,
+               transportFactory, transportFactory,
+               protocolFactory, protocolFactory,
+               new Configuration(), DefaultLogDelegate)
+        {
+        }
+
+        public TThreadPoolServer(TProcessorFactory processorFactory,
+                     TServerTransport serverTransport,
+                     TTransportFactory transportFactory,
+                     TProtocolFactory protocolFactory)
+            : this(processorFactory, serverTransport,
+             transportFactory, transportFactory,
+             protocolFactory, protocolFactory,
+             new Configuration(), DefaultLogDelegate)
+        {
+        }
+
+        public TThreadPoolServer(TProcessorFactory processorFactory,
+                     TServerTransport serverTransport,
+                     TTransportFactory inputTransportFactory,
+                     TTransportFactory outputTransportFactory,
+                     TProtocolFactory inputProtocolFactory,
+                     TProtocolFactory outputProtocolFactory,
+                     int minThreadPoolThreads, int maxThreadPoolThreads, LogDelegate logDel)
+            : this(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
+             inputProtocolFactory, outputProtocolFactory,
+             new Configuration(minThreadPoolThreads, maxThreadPoolThreads),
+             logDel)
+        {
+        }
+
+        public TThreadPoolServer(TProcessorFactory processorFactory,
+                     TServerTransport serverTransport,
+                     TTransportFactory inputTransportFactory,
+                     TTransportFactory outputTransportFactory,
+                     TProtocolFactory inputProtocolFactory,
+                     TProtocolFactory outputProtocolFactory,
+                     Configuration threadConfig,
+                     LogDelegate logDel)
+            : base(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
+            inputProtocolFactory, outputProtocolFactory, logDel)
+        {
+            lock (typeof(TThreadPoolServer))
+            {
+                if ((threadConfig.MaxWorkerThreads > 0) || (threadConfig.MaxIOThreads > 0))
+                {
+                    int work, comm;
+                    ThreadPool.GetMaxThreads(out work, out comm);
+                    if (threadConfig.MaxWorkerThreads > 0)
+                        work = threadConfig.MaxWorkerThreads;
+                    if (threadConfig.MaxIOThreads > 0)
+                        comm = threadConfig.MaxIOThreads;
+                    if (!ThreadPool.SetMaxThreads(work, comm))
+                        throw new Exception("Error: could not SetMaxThreads in ThreadPool");
+                }
+
+                if ((threadConfig.MinWorkerThreads > 0) || (threadConfig.MinIOThreads > 0))
+                {
+                    int work, comm;
+                    ThreadPool.GetMinThreads(out work, out comm);
+                    if (threadConfig.MinWorkerThreads > 0)
+                        work = threadConfig.MinWorkerThreads;
+                    if (threadConfig.MinIOThreads > 0)
+                        comm = threadConfig.MinIOThreads;
+                    if (!ThreadPool.SetMinThreads(work, comm))
+                        throw new Exception("Error: could not SetMinThreads in ThreadPool");
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Use new ThreadPool thread for each new client connection.
+        /// </summary>
+        public override void Serve()
+        {
+            try
+            {
+                serverTransport.Listen();
+            }
+            catch (TTransportException ttx)
+            {
+                logDelegate("Error, could not listen on ServerTransport: " + ttx);
+                return;
+            }
+
+            //Fire the preServe server event when server is up but before any client connections
+            if (serverEventHandler != null)
+                serverEventHandler.preServe();
+
+            while (!stop)
+            {
+                int failureCount = 0;
+                try
+                {
+                    TTransport client = serverTransport.Accept();
+                    ThreadPool.QueueUserWorkItem(this.Execute, client);
+                }
+                catch (TTransportException ttx)
+                {
+                    if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted)
+                    {
+                        ++failureCount;
+                        logDelegate(ttx.ToString());
+                    }
+
+                }
+            }
+
+            if (stop)
+            {
+                try
+                {
+                    serverTransport.Close();
+                }
+                catch (TTransportException ttx)
+                {
+                    logDelegate("TServerTransport failed on close: " + ttx.Message);
+                }
+                stop = false;
+            }
+        }
+
+        /// <summary>
+        /// Loops on processing a client forever
+        /// threadContext will be a TTransport instance
+        /// </summary>
+        /// <param name="threadContext"></param>
+        private void Execute(object threadContext)
+        {
+            using (TTransport client = (TTransport)threadContext)
+            {
+                TProcessor processor = processorFactory.GetProcessor(client, this);
+                TTransport inputTransport = null;
+                TTransport outputTransport = null;
+                TProtocol inputProtocol = null;
+                TProtocol outputProtocol = null;
+                object connectionContext = null;
+                try
+                {
+                    try
+                    {
+                        inputTransport = inputTransportFactory.GetTransport(client);
+                        outputTransport = outputTransportFactory.GetTransport(client);
+                        inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+                        outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
+
+                        //Recover event handler (if any) and fire createContext server event when a client connects
+                        if (serverEventHandler != null)
+                            connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
+
+                        //Process client requests until client disconnects
+                        while (!stop)
+                        {
+                            if (!inputTransport.Peek())
+                                break;
+
+                            //Fire processContext server event
+                            //N.B. This is the pattern implemented in C++ and the event fires provisionally.
+                            //That is to say it may be many minutes between the event firing and the client request
+                            //actually arriving or the client may hang up without ever makeing a request.
+                            if (serverEventHandler != null)
+                                serverEventHandler.processContext(connectionContext, inputTransport);
+                            //Process client request (blocks until transport is readable)
+                            if (!processor.Process(inputProtocol, outputProtocol))
+                                break;
+                        }
+                    }
+                    catch (TTransportException)
+                    {
+                        //Usually a client disconnect, expected
+                    }
+                    catch (Exception x)
+                    {
+                        //Unexpected
+                        logDelegate("Error: " + x);
+                    }
+
+                    //Fire deleteContext server event after client disconnects
+                    if (serverEventHandler != null)
+                        serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+
+                }
+                finally
+                {
+                    //Close transports
+                    if (inputTransport != null)
+                        inputTransport.Close();
+                    if (outputTransport != null)
+                        outputTransport.Close();
+
+                    // disposable stuff should be disposed
+                    if (inputProtocol != null)
+                        inputProtocol.Dispose();
+                    if (outputProtocol != null)
+                        outputProtocol.Dispose();
+                    if (inputTransport != null)
+                        inputTransport.Dispose();
+                    if (outputTransport != null)
+                        outputTransport.Dispose();
+                }
+            }
+        }
+
+        public override void Stop()
+        {
+            stop = true;
+            serverTransport.Close();
+        }
+    }
+}
diff --git a/lib/csharp/src/Server/TThreadedServer.cs b/lib/csharp/src/Server/TThreadedServer.cs
new file mode 100644
index 0000000..cc051a3
--- /dev/null
+++ b/lib/csharp/src/Server/TThreadedServer.cs
@@ -0,0 +1,282 @@
+/**
+ * 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;
+using System.Collections.Generic;
+using System.Threading;
+using Thrift.Collections;
+using Thrift.Protocol;
+using Thrift.Transport;
+
+namespace Thrift.Server
+{
+    /// <summary>
+    /// Server that uses C# threads (as opposed to the ThreadPool) when handling requests.
+    /// </summary>
+    public class TThreadedServer : TServer
+    {
+        private const int DEFAULT_MAX_THREADS = 100;
+        private volatile bool stop = false;
+        private readonly int maxThreads;
+
+        private Queue<TTransport> clientQueue;
+        private THashSet<Thread> clientThreads;
+        private object clientLock;
+        private Thread workerThread;
+
+        public int ClientThreadsCount
+        {
+            get { return clientThreads.Count; }
+        }
+
+        public TThreadedServer(TProcessor processor, TServerTransport serverTransport)
+            : this(new TSingletonProcessorFactory(processor), serverTransport,
+             new TTransportFactory(), new TTransportFactory(),
+             new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+             DEFAULT_MAX_THREADS, DefaultLogDelegate)
+        {
+        }
+
+        public TThreadedServer(TProcessor processor, TServerTransport serverTransport, LogDelegate logDelegate)
+            : this(new TSingletonProcessorFactory(processor), serverTransport,
+             new TTransportFactory(), new TTransportFactory(),
+             new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+             DEFAULT_MAX_THREADS, logDelegate)
+        {
+        }
+
+
+        public TThreadedServer(TProcessor processor,
+                     TServerTransport serverTransport,
+                     TTransportFactory transportFactory,
+                     TProtocolFactory protocolFactory)
+            : this(new TSingletonProcessorFactory(processor), serverTransport,
+             transportFactory, transportFactory,
+             protocolFactory, protocolFactory,
+             DEFAULT_MAX_THREADS, DefaultLogDelegate)
+        {
+        }
+
+        public TThreadedServer(TProcessorFactory processorFactory,
+               TServerTransport serverTransport,
+               TTransportFactory transportFactory,
+               TProtocolFactory protocolFactory)
+            : this(processorFactory, serverTransport,
+             transportFactory, transportFactory,
+             protocolFactory, protocolFactory,
+             DEFAULT_MAX_THREADS, DefaultLogDelegate)
+        {
+        }
+        public TThreadedServer(TProcessorFactory processorFactory,
+                     TServerTransport serverTransport,
+                     TTransportFactory inputTransportFactory,
+                     TTransportFactory outputTransportFactory,
+                     TProtocolFactory inputProtocolFactory,
+                     TProtocolFactory outputProtocolFactory,
+                     int maxThreads, LogDelegate logDel)
+          : base(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
+              inputProtocolFactory, outputProtocolFactory, logDel)
+        {
+            this.maxThreads = maxThreads;
+            clientQueue = new Queue<TTransport>();
+            clientLock = new object();
+            clientThreads = new THashSet<Thread>();
+        }
+
+        /// <summary>
+        /// Use new Thread for each new client connection. block until numConnections &lt; maxThreads.
+        /// </summary>
+        public override void Serve()
+        {
+            try
+            {
+                //start worker thread
+                workerThread = new Thread(new ThreadStart(Execute));
+                workerThread.Start();
+                serverTransport.Listen();
+            }
+            catch (TTransportException ttx)
+            {
+                logDelegate("Error, could not listen on ServerTransport: " + ttx);
+                return;
+            }
+
+            //Fire the preServe server event when server is up but before any client connections
+            if (serverEventHandler != null)
+                serverEventHandler.preServe();
+
+            while (!stop)
+            {
+                int failureCount = 0;
+                try
+                {
+                    TTransport client = serverTransport.Accept();
+                    lock (clientLock)
+                    {
+                        clientQueue.Enqueue(client);
+                        Monitor.Pulse(clientLock);
+                    }
+                }
+                catch (TTransportException ttx)
+                {
+                    if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted)
+                    {
+                        ++failureCount;
+                        logDelegate(ttx.ToString());
+                    }
+
+                }
+            }
+
+            if (stop)
+            {
+                try
+                {
+                    serverTransport.Close();
+                }
+                catch (TTransportException ttx)
+                {
+                    logDelegate("TServeTransport failed on close: " + ttx.Message);
+                }
+                stop = false;
+            }
+        }
+
+        /// <summary>
+        /// Loops on processing a client forever
+        /// </summary>
+        private void Execute()
+        {
+            while (!stop)
+            {
+                TTransport client;
+                Thread t;
+                lock (clientLock)
+                {
+                    //don't dequeue if too many connections
+                    while (clientThreads.Count >= maxThreads)
+                    {
+                        Monitor.Wait(clientLock);
+                    }
+
+                    while (clientQueue.Count == 0)
+                    {
+                        Monitor.Wait(clientLock);
+                    }
+
+                    client = clientQueue.Dequeue();
+                    t = new Thread(new ParameterizedThreadStart(ClientWorker));
+                    clientThreads.Add(t);
+                }
+                //start processing requests from client on new thread
+                t.Start(client);
+            }
+        }
+
+        private void ClientWorker(object context)
+        {
+            using (TTransport client = (TTransport)context)
+            {
+                TProcessor processor = processorFactory.GetProcessor(client);
+                TTransport inputTransport = null;
+                TTransport outputTransport = null;
+                TProtocol inputProtocol = null;
+                TProtocol outputProtocol = null;
+                object connectionContext = null;
+                try
+                {
+                    try
+                    {
+                        inputTransport = inputTransportFactory.GetTransport(client);
+                        outputTransport = outputTransportFactory.GetTransport(client);
+                        inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+                        outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
+
+                        //Recover event handler (if any) and fire createContext server event when a client connects
+                        if (serverEventHandler != null)
+                            connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
+
+                        //Process client requests until client disconnects
+                        while (!stop)
+                        {
+                            if (!inputTransport.Peek())
+                                break;
+
+                            //Fire processContext server event
+                            //N.B. This is the pattern implemented in C++ and the event fires provisionally.
+                            //That is to say it may be many minutes between the event firing and the client request
+                            //actually arriving or the client may hang up without ever makeing a request.
+                            if (serverEventHandler != null)
+                                serverEventHandler.processContext(connectionContext, inputTransport);
+                            //Process client request (blocks until transport is readable)
+                            if (!processor.Process(inputProtocol, outputProtocol))
+                                break;
+                        }
+                    }
+                    catch (TTransportException)
+                    {
+                        //Usually a client disconnect, expected
+                    }
+                    catch (Exception x)
+                    {
+                        //Unexpected
+                        logDelegate("Error: " + x);
+                    }
+
+                    //Fire deleteContext server event after client disconnects
+                    if (serverEventHandler != null)
+                        serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+
+                    lock (clientLock)
+                    {
+                        clientThreads.Remove(Thread.CurrentThread);
+                        Monitor.Pulse(clientLock);
+                    }
+
+                }
+                finally
+                {
+                    //Close transports
+                    if (inputTransport != null)
+                        inputTransport.Close();
+                    if (outputTransport != null)
+                        outputTransport.Close();
+
+                    // disposable stuff should be disposed
+                    if (inputProtocol != null)
+                        inputProtocol.Dispose();
+                    if (outputProtocol != null)
+                        outputProtocol.Dispose();
+                }
+            }
+        }
+
+        public override void Stop()
+        {
+            stop = true;
+            serverTransport.Close();
+            //clean up all the threads myself
+            workerThread.Abort();
+            foreach (Thread t in clientThreads)
+            {
+                t.Abort();
+            }
+        }
+    }
+}
diff --git a/lib/csharp/src/TApplicationException.cs b/lib/csharp/src/TApplicationException.cs
new file mode 100644
index 0000000..8dd7ae5
--- /dev/null
+++ b/lib/csharp/src/TApplicationException.cs
@@ -0,0 +1,146 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using Thrift.Protocol;
+
+namespace Thrift
+{
+    public class TApplicationException : TException
+    {
+        protected ExceptionType type;
+
+        public TApplicationException()
+        {
+        }
+
+        public TApplicationException(ExceptionType type)
+        {
+            this.type = type;
+        }
+
+        public TApplicationException(ExceptionType type, string message)
+            : base(message, null) // TApplicationException is serializable, but we never serialize InnerException
+        {
+            this.type = type;
+        }
+
+        public static TApplicationException Read(TProtocol iprot)
+        {
+            TField field;
+
+            string message = null;
+            ExceptionType type = ExceptionType.Unknown;
+
+            iprot.ReadStructBegin();
+            while (true)
+            {
+                field = iprot.ReadFieldBegin();
+                if (field.Type == TType.Stop)
+                {
+                    break;
+                }
+
+                switch (field.ID)
+                {
+                    case 1:
+                        if (field.Type == TType.String)
+                        {
+                            message = iprot.ReadString();
+                        }
+                        else
+                        {
+                            TProtocolUtil.Skip(iprot, field.Type);
+                        }
+                        break;
+                    case 2:
+                        if (field.Type == TType.I32)
+                        {
+                            type = (ExceptionType)iprot.ReadI32();
+                        }
+                        else
+                        {
+                            TProtocolUtil.Skip(iprot, field.Type);
+                        }
+                        break;
+                    default:
+                        TProtocolUtil.Skip(iprot, field.Type);
+                        break;
+                }
+
+                iprot.ReadFieldEnd();
+            }
+
+            iprot.ReadStructEnd();
+
+            return new TApplicationException(type, message);
+        }
+
+        public void Write(TProtocol oprot)
+        {
+            TStruct struc = new TStruct("TApplicationException");
+            TField field = new TField();
+
+            oprot.WriteStructBegin(struc);
+
+            if (!string.IsNullOrEmpty(Message))
+            {
+                field.Name = "message";
+                field.Type = TType.String;
+                field.ID = 1;
+                oprot.WriteFieldBegin(field);
+                oprot.WriteString(Message);
+                oprot.WriteFieldEnd();
+            }
+
+            field.Name = "type";
+            field.Type = TType.I32;
+            field.ID = 2;
+            oprot.WriteFieldBegin(field);
+            oprot.WriteI32((int)type);
+            oprot.WriteFieldEnd();
+            oprot.WriteFieldStop();
+            oprot.WriteStructEnd();
+        }
+
+        public enum ExceptionType
+        {
+            Unknown,
+            UnknownMethod,
+            InvalidMessageType,
+            WrongMethodName,
+            BadSequenceID,
+            MissingResult,
+            InternalError,
+            ProtocolError,
+            InvalidTransform,
+            InvalidProtocol,
+            UnsupportedClientType
+        }
+
+        public ExceptionType Type
+        {
+            get { return type; }
+        }
+    }
+}
diff --git a/lib/csharp/src/TAsyncProcessor.cs b/lib/csharp/src/TAsyncProcessor.cs
new file mode 100644
index 0000000..ab43225
--- /dev/null
+++ b/lib/csharp/src/TAsyncProcessor.cs
@@ -0,0 +1,38 @@
+/**
+ * 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.Threading.Tasks;
+using Thrift.Protocol;
+
+namespace Thrift
+{
+    /// <summary>
+    /// Processes a message asynchronously.
+    /// </summary>
+    public interface TAsyncProcessor
+    {
+        /// <summary>
+        /// Processes the next part of the message.
+        /// </summary>
+        /// <param name="iprot">The input protocol.</param>
+        /// <param name="oprot">The output protocol.</param>
+        /// <returns>true if there's more to process, false otherwise.</returns>
+        Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot);
+    }
+}
diff --git a/lib/csharp/src/TControllingHandler.cs b/lib/csharp/src/TControllingHandler.cs
new file mode 100644
index 0000000..7b5203a
--- /dev/null
+++ b/lib/csharp/src/TControllingHandler.cs
@@ -0,0 +1,29 @@
+/*
+ * 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;
+using Thrift.Server;
+
+namespace Thrift
+{
+    public interface TControllingHandler
+    {
+        TServer server { get; set; }
+    }
+}
diff --git a/lib/csharp/src/TException.cs b/lib/csharp/src/TException.cs
new file mode 100644
index 0000000..b9fae6e
--- /dev/null
+++ b/lib/csharp/src/TException.cs
@@ -0,0 +1,40 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift
+{
+    public class TException : Exception
+    {
+        public TException()
+        {
+        }
+
+        public TException(string message, Exception inner = null)
+            : base(message, inner)
+        {
+        }
+
+    }
+}
diff --git a/lib/csharp/src/TProcessor.cs b/lib/csharp/src/TProcessor.cs
new file mode 100644
index 0000000..71ce755
--- /dev/null
+++ b/lib/csharp/src/TProcessor.cs
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using Thrift.Protocol;
+
+namespace Thrift
+{
+    public interface TProcessor
+    {
+        bool Process(TProtocol iprot, TProtocol oprot);
+    }
+}
diff --git a/lib/csharp/src/TProcessorFactory.cs b/lib/csharp/src/TProcessorFactory.cs
new file mode 100644
index 0000000..fdf631b
--- /dev/null
+++ b/lib/csharp/src/TProcessorFactory.cs
@@ -0,0 +1,30 @@
+/*
+ * 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;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace Thrift
+{
+    public interface TProcessorFactory
+    {
+        TProcessor GetProcessor(TTransport trans, TServer server = null);
+    }
+}
diff --git a/lib/csharp/src/TPrototypeProcessorFactory.cs b/lib/csharp/src/TPrototypeProcessorFactory.cs
new file mode 100644
index 0000000..0b47261
--- /dev/null
+++ b/lib/csharp/src/TPrototypeProcessorFactory.cs
@@ -0,0 +1,55 @@
+/*
+ * 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;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace Thrift
+{
+    public class TPrototypeProcessorFactory<P, H> : TProcessorFactory where P : TProcessor
+    {
+        object[] handlerArgs = null;
+
+        public TPrototypeProcessorFactory()
+        {
+            handlerArgs = new object[0];
+        }
+
+        public TPrototypeProcessorFactory(params object[] handlerArgs)
+        {
+            this.handlerArgs = handlerArgs;
+        }
+
+        public TProcessor GetProcessor(TTransport trans, TServer server = null)
+        {
+            H handler = (H)Activator.CreateInstance(typeof(H), handlerArgs);
+
+            TControllingHandler handlerServerRef = handler as TControllingHandler;
+            if (handlerServerRef != null)
+            {
+                handlerServerRef.server = server;
+            }
+            return Activator.CreateInstance(typeof(P), new object[] { handler }) as TProcessor;
+        }
+    }
+}
diff --git a/lib/csharp/src/TSingletonProcessorFactory.cs b/lib/csharp/src/TSingletonProcessorFactory.cs
new file mode 100644
index 0000000..ed2897b
--- /dev/null
+++ b/lib/csharp/src/TSingletonProcessorFactory.cs
@@ -0,0 +1,43 @@
+/*
+ * 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;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace Thrift
+{
+    public class TSingletonProcessorFactory : TProcessorFactory
+    {
+        private readonly TProcessor processor_;
+
+        public TSingletonProcessorFactory(TProcessor processor)
+        {
+            processor_ = processor;
+        }
+
+        public TProcessor GetProcessor(TTransport trans, TServer server = null)
+        {
+            return processor_;
+        }
+    }
+}
diff --git a/lib/csharp/src/Thrift.45.csproj b/lib/csharp/src/Thrift.45.csproj
new file mode 100644
index 0000000..146e7f8
--- /dev/null
+++ b/lib/csharp/src/Thrift.45.csproj
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{EBCE35DA-CF6A-42BC-A357-A9C09B534299}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Thrift</RootNamespace>
+    <AssemblyName>Thrift45</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>portable</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;NET45</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>portable</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE;NET45</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>thrift.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Web" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Collections\TCollections.cs" />
+    <Compile Include="Collections\THashSet.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Protocol\TAbstractBase.cs" />
+    <Compile Include="Protocol\TBase.cs" />
+    <Compile Include="Protocol\TBase64Utils.cs" />
+    <Compile Include="Protocol\TBinaryProtocol.cs" />
+    <Compile Include="Protocol\TCompactProtocol.cs" />
+    <Compile Include="Protocol\TField.cs" />
+    <Compile Include="Protocol\TJSONProtocol.cs" />
+    <Compile Include="Protocol\TList.cs" />
+    <Compile Include="Protocol\TMap.cs" />
+    <Compile Include="Protocol\TMessage.cs" />
+    <Compile Include="Protocol\TMessageType.cs" />
+    <Compile Include="Protocol\TMultiplexedProcessor.cs" />
+    <Compile Include="Protocol\TMultiplexedProtocol.cs" />
+    <Compile Include="Protocol\TProtocol.cs" />
+    <Compile Include="Protocol\TProtocolDecorator.cs" />
+    <Compile Include="Protocol\TProtocolException.cs" />
+    <Compile Include="Protocol\TProtocolFactory.cs" />
+    <Compile Include="Protocol\TProtocolUtil.cs" />
+    <Compile Include="Protocol\TSet.cs" />
+    <Compile Include="Protocol\TStruct.cs" />
+    <Compile Include="Protocol\TType.cs" />
+    <Compile Include="Server\TServer.cs" />
+    <Compile Include="Server\TServerEventHandler.cs" />
+    <Compile Include="Server\TSimpleServer.cs" />
+    <Compile Include="Server\TThreadedServer.cs" />
+    <Compile Include="Server\TThreadPoolServer.cs" />
+    <Compile Include="TApplicationException.cs" />
+    <Compile Include="TAsyncProcessor.cs" />
+    <Compile Include="TControllingHandler.cs" />
+    <Compile Include="TException.cs" />
+    <Compile Include="TProcessor.cs" />
+    <Compile Include="TProcessorFactory.cs" />
+    <Compile Include="TPrototypeProcessorFactory.cs" />
+    <Compile Include="Transport\TBufferedTransport.cs" />
+    <Compile Include="Transport\TFramedTransport.cs" />
+    <Compile Include="Transport\THttpClient.cs" />
+    <Compile Include="Transport\THttpHandler.cs" />
+    <Compile Include="Transport\THttpTaskAsyncHandler.cs" />
+    <Compile Include="Transport\TMemoryBuffer.cs" />
+    <Compile Include="Transport\TNamedPipeClientTransport.cs" />
+    <Compile Include="Transport\TNamedPipeServerTransport.cs" />
+    <Compile Include="Transport\TServerSocket.cs" />
+    <Compile Include="Transport\TServerTransport.cs" />
+    <Compile Include="Transport\TSilverlightSocket.cs" />
+    <Compile Include="Transport\TSocket.cs" />
+    <Compile Include="Transport\TSocketVersionizer.cs" />
+    <Compile Include="Transport\TStreamTransport.cs" />
+    <Compile Include="Transport\TTLSServerSocket.cs" />
+    <Compile Include="Transport\TTLSSocket.cs" />
+    <Compile Include="Transport\TTransport.cs" />
+    <Compile Include="Transport\TTransportException.cs" />
+    <Compile Include="Transport\TTransportFactory.cs" />
+    <Compile Include="TSingletonProcessorFactory.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Server\Collections\" />
+    <Folder Include="Server\Protocol\" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="thrift.snk" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/lib/csharp/src/Thrift.csproj b/lib/csharp/src/Thrift.csproj
new file mode 100644
index 0000000..1305482
--- /dev/null
+++ b/lib/csharp/src/Thrift.csproj
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</ProjectGuid>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <OutputType>Library</OutputType>
+    <NoStandardLibraries>false</NoStandardLibraries>
+    <AssemblyName>Thrift</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <RootNamespace>Thrift</RootNamespace>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>0.14.0.0</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>portable</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>portable</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>
+    </DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>thrift.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Web" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Collections\TCollections.cs" />
+    <Compile Include="Collections\THashSet.cs" />
+    <Compile Include="Net35\ExtensionsNet35.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Protocol\TAbstractBase.cs" />
+    <Compile Include="Protocol\TBase.cs" />
+    <Compile Include="Protocol\TBase64Utils.cs" />
+    <Compile Include="Protocol\TBinaryProtocol.cs" />
+    <Compile Include="Protocol\TCompactProtocol.cs" />
+    <Compile Include="Protocol\TField.cs" />
+    <Compile Include="Protocol\TJSONProtocol.cs" />
+    <Compile Include="Protocol\TList.cs" />
+    <Compile Include="Protocol\TMap.cs" />
+    <Compile Include="Protocol\TMessage.cs" />
+    <Compile Include="Protocol\TMessageType.cs" />
+    <Compile Include="Protocol\TMultiplexedProcessor.cs" />
+    <Compile Include="Protocol\TMultiplexedProtocol.cs" />
+    <Compile Include="Protocol\TProtocol.cs" />
+    <Compile Include="Protocol\TProtocolDecorator.cs" />
+    <Compile Include="Protocol\TProtocolException.cs" />
+    <Compile Include="Protocol\TProtocolFactory.cs" />
+    <Compile Include="Protocol\TProtocolUtil.cs" />
+    <Compile Include="Protocol\TSet.cs" />
+    <Compile Include="Protocol\TStruct.cs" />
+    <Compile Include="Protocol\TType.cs" />
+    <Compile Include="Server\TServer.cs" />
+    <Compile Include="Server\TServerEventHandler.cs" />
+    <Compile Include="Server\TSimpleServer.cs" />
+    <Compile Include="Server\TThreadedServer.cs" />
+    <Compile Include="Server\TThreadPoolServer.cs" />
+    <Compile Include="TApplicationException.cs" />
+    <Compile Include="TControllingHandler.cs" />
+    <Compile Include="TException.cs" />
+    <Compile Include="TProcessor.cs" />
+    <Compile Include="TProcessorFactory.cs" />
+    <Compile Include="TPrototypeProcessorFactory.cs" />
+    <Compile Include="Transport\TBufferedTransport.cs" />
+    <Compile Include="Transport\TFramedTransport.cs" />
+    <Compile Include="Transport\THttpClient.cs" />
+    <Compile Include="Transport\THttpHandler.cs" />
+    <Compile Include="Transport\TMemoryBuffer.cs" />
+    <Compile Include="Transport\TNamedPipeClientTransport.cs" />
+    <Compile Include="Transport\TNamedPipeServerTransport.cs" />
+    <Compile Include="Transport\TServerSocket.cs" />
+    <Compile Include="Transport\TServerTransport.cs" />
+    <Compile Include="Transport\TSocket.cs" />
+    <Compile Include="Transport\TSocketVersionizer.cs" />
+    <Compile Include="Transport\TStreamTransport.cs" />
+    <Compile Include="Transport\TTLSServerSocket.cs" />
+    <Compile Include="Transport\TTLSSocket.cs" />
+    <Compile Include="Transport\TTransport.cs" />
+    <Compile Include="Transport\TTransportException.cs" />
+    <Compile Include="Transport\TTransportFactory.cs" />
+    <Compile Include="TSingletonProcessorFactory.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="thrift.snk" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
+  <ProjectExtensions>
+    <VisualStudio AllowExistingFolder="true" />
+  </ProjectExtensions>
+</Project>
\ No newline at end of file
diff --git a/lib/csharp/src/Thrift.sln b/lib/csharp/src/Thrift.sln
new file mode 100644
index 0000000..a29e468
--- /dev/null
+++ b/lib/csharp/src/Thrift.sln
@@ -0,0 +1,47 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftTest", "..\test\ThriftTest\ThriftTest.csproj", "{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftMSBuildTask", "..\ThriftMSBuildTask\ThriftMSBuildTask.csproj", "{EC0A0231-66EA-4593-A792-C6CA3BB8668E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift.45", "Thrift.45.csproj", "{EBCE35DA-CF6A-42BC-A357-A9C09B534299}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftMVCTest", "..\test\ThriftMVCTest\ThriftMVCTest.csproj", "{891B4487-C7BA-427E-BBC8-4C596C229A10}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{EC0A0231-66EA-4593-A792-C6CA3BB8668E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EC0A0231-66EA-4593-A792-C6CA3BB8668E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EC0A0231-66EA-4593-A792-C6CA3BB8668E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EC0A0231-66EA-4593-A792-C6CA3BB8668E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{EBCE35DA-CF6A-42BC-A357-A9C09B534299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EBCE35DA-CF6A-42BC-A357-A9C09B534299}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EBCE35DA-CF6A-42BC-A357-A9C09B534299}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EBCE35DA-CF6A-42BC-A357-A9C09B534299}.Release|Any CPU.Build.0 = Release|Any CPU
+		{891B4487-C7BA-427E-BBC8-4C596C229A10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{891B4487-C7BA-427E-BBC8-4C596C229A10}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{891B4487-C7BA-427E-BBC8-4C596C229A10}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{891B4487-C7BA-427E-BBC8-4C596C229A10}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(MonoDevelopProperties) = preSolution
+		        StartupItem = Thrift.csproj
+	EndGlobalSection
+EndGlobal
diff --git a/lib/csharp/src/Transport/TBufferedTransport.cs b/lib/csharp/src/Transport/TBufferedTransport.cs
new file mode 100644
index 0000000..8870988
--- /dev/null
+++ b/lib/csharp/src/Transport/TBufferedTransport.cs
@@ -0,0 +1,194 @@
+/**
+ * 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;
+using System.IO;
+
+namespace Thrift.Transport
+{
+    public class TBufferedTransport : TTransport, IDisposable
+    {
+        private readonly int bufSize;
+        private readonly MemoryStream inputBuffer = new MemoryStream(0);
+        private readonly MemoryStream outputBuffer = new MemoryStream(0);
+        private readonly TTransport transport;
+
+        public TBufferedTransport(TTransport transport, int bufSize = 1024)
+        {
+            if (transport == null)
+                throw new ArgumentNullException("transport");
+            if (bufSize <= 0)
+                throw new ArgumentException("bufSize", "Buffer size must be a positive number.");
+            this.transport = transport;
+            this.bufSize = bufSize;
+        }
+
+        public TTransport UnderlyingTransport
+        {
+            get
+            {
+                CheckNotDisposed();
+                return transport;
+            }
+        }
+
+        public override bool IsOpen
+        {
+            get
+            {
+                // We can legitimately throw here but be nice a bit.
+                // CheckNotDisposed();
+                return !_IsDisposed && transport.IsOpen;
+            }
+        }
+
+        public override void Open()
+        {
+            CheckNotDisposed();
+            transport.Open();
+        }
+
+        public override void Close()
+        {
+            CheckNotDisposed();
+            transport.Close();
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            CheckNotDisposed();
+            ValidateBufferArgs(buf, off, len);
+            if (!IsOpen)
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+
+            if (inputBuffer.Capacity < bufSize)
+                inputBuffer.Capacity = bufSize;
+
+            while (true)
+            {
+                int got = inputBuffer.Read(buf, off, len);
+                if (got > 0)
+                    return got;
+
+                inputBuffer.Seek(0, SeekOrigin.Begin);
+                inputBuffer.SetLength(inputBuffer.Capacity);
+                int filled = transport.Read(inputBuffer.GetBuffer(), 0, (int)inputBuffer.Length);
+                inputBuffer.SetLength(filled);
+                if (filled == 0)
+                    return 0;
+            }
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            CheckNotDisposed();
+            ValidateBufferArgs(buf, off, len);
+            if (!IsOpen)
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            // Relative offset from "off" argument
+            int offset = 0;
+            if (outputBuffer.Length > 0)
+            {
+                int capa = (int)(outputBuffer.Capacity - outputBuffer.Length);
+                int writeSize = capa <= len ? capa : len;
+                outputBuffer.Write(buf, off, writeSize);
+                offset += writeSize;
+                if (writeSize == capa)
+                {
+                    transport.Write(outputBuffer.GetBuffer(), 0, (int)outputBuffer.Length);
+                    outputBuffer.SetLength(0);
+                }
+            }
+            while (len - offset >= bufSize)
+            {
+                transport.Write(buf, off + offset, bufSize);
+                offset += bufSize;
+            }
+            int remain = len - offset;
+            if (remain > 0)
+            {
+                if (outputBuffer.Capacity < bufSize)
+                    outputBuffer.Capacity = bufSize;
+                outputBuffer.Write(buf, off + offset, remain);
+            }
+        }
+
+        private void InternalFlush()
+        {
+            if (!IsOpen)
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            if (outputBuffer.Length > 0)
+            {
+                transport.Write(outputBuffer.GetBuffer(), 0, (int)outputBuffer.Length);
+                outputBuffer.SetLength(0);
+            }
+        }
+
+        public override void Flush()
+        {
+            CheckNotDisposed();
+            InternalFlush();
+
+            transport.Flush();
+        }
+
+        public override IAsyncResult BeginFlush(AsyncCallback callback, object state)
+        {
+            CheckNotDisposed();
+            InternalFlush();
+
+            return transport.BeginFlush( callback, state);
+        }
+
+        public override void EndFlush(IAsyncResult asyncResult)
+        {
+            transport.EndFlush( asyncResult);
+        }
+
+
+
+        protected void CheckNotDisposed()
+        {
+            if (_IsDisposed)
+                throw new ObjectDisposedException("TBufferedTransport");
+        }
+
+        #region " IDisposable Support "
+        protected bool _IsDisposed { get; private set; }
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (inputBuffer != null)
+                        inputBuffer.Dispose();
+                    if (outputBuffer != null)
+                        outputBuffer.Dispose();
+                    if (transport != null)
+                        transport.Dispose();
+                }
+            }
+            _IsDisposed = true;
+        }
+        #endregion
+    }
+}
diff --git a/lib/csharp/src/Transport/TFramedTransport.cs b/lib/csharp/src/Transport/TFramedTransport.cs
new file mode 100644
index 0000000..a746a32
--- /dev/null
+++ b/lib/csharp/src/Transport/TFramedTransport.cs
@@ -0,0 +1,205 @@
+/**
+ * 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;
+using System.IO;
+
+namespace Thrift.Transport
+{
+    public class TFramedTransport : TTransport, IDisposable
+    {
+        private readonly TTransport transport;
+        private readonly MemoryStream writeBuffer = new MemoryStream(1024);
+        private readonly MemoryStream readBuffer = new MemoryStream(1024);
+
+        private const int HeaderSize = 4;
+        private readonly byte[] headerBuf = new byte[HeaderSize];
+
+        public class Factory : TTransportFactory
+        {
+            public override TTransport GetTransport(TTransport trans)
+            {
+                return new TFramedTransport(trans);
+            }
+        }
+
+        public TFramedTransport(TTransport transport)
+        {
+            if (transport == null)
+                throw new ArgumentNullException("transport");
+            this.transport = transport;
+            InitWriteBuffer();
+        }
+
+        public override void Open()
+        {
+            CheckNotDisposed();
+            transport.Open();
+        }
+
+        public override bool IsOpen
+        {
+            get
+            {
+                // We can legitimately throw here but be nice a bit.
+                // CheckNotDisposed();
+                return !_IsDisposed && transport.IsOpen;
+            }
+        }
+
+        public override void Close()
+        {
+            CheckNotDisposed();
+            transport.Close();
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            CheckNotDisposed();
+            ValidateBufferArgs(buf, off, len);
+            if (!IsOpen)
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            int got = readBuffer.Read(buf, off, len);
+            if (got > 0)
+            {
+                return got;
+            }
+
+            // Read another frame of data
+            ReadFrame();
+
+            return readBuffer.Read(buf, off, len);
+        }
+
+        private void ReadFrame()
+        {
+            transport.ReadAll(headerBuf, 0, HeaderSize);
+            int size = DecodeFrameSize(headerBuf);
+
+            readBuffer.SetLength(size);
+            readBuffer.Seek(0, SeekOrigin.Begin);
+            byte[] buff = readBuffer.GetBuffer();
+            transport.ReadAll(buff, 0, size);
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            CheckNotDisposed();
+            ValidateBufferArgs(buf, off, len);
+            if (!IsOpen)
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            if (writeBuffer.Length + (long)len > (long)int.MaxValue)
+                Flush();
+            writeBuffer.Write(buf, off, len);
+        }
+
+        private void InternalFlush()
+        {
+            CheckNotDisposed();
+            if (!IsOpen)
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            byte[] buf = writeBuffer.GetBuffer();
+            int len = (int)writeBuffer.Length;
+            int data_len = len - HeaderSize;
+            if (data_len < 0)
+                throw new System.InvalidOperationException(); // logic error actually
+
+            // Inject message header into the reserved buffer space
+            EncodeFrameSize(data_len, buf);
+
+            // Send the entire message at once
+            transport.Write(buf, 0, len);
+
+            InitWriteBuffer();
+        }
+
+        public override void Flush()
+        {
+            CheckNotDisposed();
+            InternalFlush();
+
+            transport.Flush();
+        }
+
+        public override IAsyncResult BeginFlush(AsyncCallback callback, object state)
+        {
+            CheckNotDisposed();
+            InternalFlush();
+
+            return transport.BeginFlush( callback, state);
+        }
+
+        public override void EndFlush(IAsyncResult asyncResult)
+        {
+            transport.EndFlush( asyncResult);
+        }
+
+        private void InitWriteBuffer()
+        {
+            // Reserve space for message header to be put right before sending it out
+            writeBuffer.SetLength(HeaderSize);
+            writeBuffer.Seek(0, SeekOrigin.End);
+        }
+
+        private static void EncodeFrameSize(int frameSize, byte[] buf)
+        {
+            buf[0] = (byte)(0xff & (frameSize >> 24));
+            buf[1] = (byte)(0xff & (frameSize >> 16));
+            buf[2] = (byte)(0xff & (frameSize >> 8));
+            buf[3] = (byte)(0xff & (frameSize));
+        }
+
+        private static int DecodeFrameSize(byte[] buf)
+        {
+            return
+                ((buf[0] & 0xff) << 24) |
+                ((buf[1] & 0xff) << 16) |
+                ((buf[2] & 0xff) << 8) |
+                ((buf[3] & 0xff));
+        }
+
+
+        private void CheckNotDisposed()
+        {
+            if (_IsDisposed)
+                throw new ObjectDisposedException("TFramedTransport");
+        }
+
+        #region " IDisposable Support "
+        private bool _IsDisposed;
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (readBuffer != null)
+                        readBuffer.Dispose();
+                    if (writeBuffer != null)
+                        writeBuffer.Dispose();
+                    if (transport != null)
+                        transport.Dispose();
+                }
+            }
+            _IsDisposed = true;
+        }
+        #endregion
+    }
+}
diff --git a/lib/csharp/src/Transport/THttpClient.cs b/lib/csharp/src/Transport/THttpClient.cs
new file mode 100644
index 0000000..986799c
--- /dev/null
+++ b/lib/csharp/src/Transport/THttpClient.cs
@@ -0,0 +1,486 @@
+/**
+ * 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;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Threading;
+using System.Linq;
+using System.Security.Cryptography.X509Certificates;
+using System.IO.Compression;
+
+namespace Thrift.Transport
+{
+    public class THttpClient : TTransport, IDisposable
+    {
+        private readonly Uri uri;
+        private readonly X509Certificate[] certificates;
+        private Stream inputStream;
+        private MemoryStream outputStream = new MemoryStream();
+
+        // Timeouts in milliseconds
+        private int connectTimeout = 30000;
+
+        private int readTimeout = 30000;
+
+        private IDictionary<string, string> customHeaders = new Dictionary<string, string>();
+        private string userAgent = "C#/THttpClient";
+
+#if !SILVERLIGHT
+        private IWebProxy proxy = WebRequest.DefaultWebProxy;
+#endif
+
+        public THttpClient(Uri u)
+            : this(u, Enumerable.Empty<X509Certificate>())
+        {
+        }
+        public THttpClient(Uri u, string userAgent)
+            : this(u, userAgent, Enumerable.Empty<X509Certificate>())
+        {
+        }
+
+        public THttpClient(Uri u, IEnumerable<X509Certificate> certificates)
+        {
+            uri = u;
+            this.certificates = (certificates ?? Enumerable.Empty<X509Certificate>()).ToArray();
+        }
+        public THttpClient(Uri u, string userAgent, IEnumerable<X509Certificate> certificates)
+        {
+            uri = u;
+            this.userAgent = userAgent;
+            this.certificates = (certificates ?? Enumerable.Empty<X509Certificate>()).ToArray();
+        }
+
+        public int ConnectTimeout
+        {
+            set
+            {
+                connectTimeout = value;
+            }
+        }
+
+        public int ReadTimeout
+        {
+            set
+            {
+                readTimeout = value;
+            }
+        }
+
+        public IDictionary<string, string> CustomHeaders
+        {
+            get
+            {
+                return customHeaders;
+            }
+        }
+
+#if !SILVERLIGHT
+        public IWebProxy Proxy
+        {
+            set
+            {
+                proxy = value;
+            }
+        }
+#endif
+
+        public override bool IsOpen
+        {
+            get
+            {
+                return true;
+            }
+        }
+
+        public override void Open()
+        {
+        }
+
+        public override void Close()
+        {
+            if (inputStream != null)
+            {
+                inputStream.Close();
+                inputStream = null;
+            }
+            if (outputStream != null)
+            {
+                outputStream.Close();
+                outputStream = null;
+            }
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            if (inputStream == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No request has been sent");
+            }
+
+            try
+            {
+                int ret = inputStream.Read(buf, off, len);
+
+                if (ret == -1)
+                {
+                    throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "No more data available");
+                }
+
+                return ret;
+            }
+            catch (IOException iox)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString(), iox);
+            }
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            outputStream.Write(buf, off, len);
+        }
+
+#if !SILVERLIGHT
+        public override void Flush()
+        {
+            try
+            {
+                SendRequest();
+            }
+            finally
+            {
+                outputStream = new MemoryStream();
+            }
+        }
+
+        private void SendRequest()
+        {
+            try
+            {
+                HttpWebRequest connection = CreateRequest();
+                connection.Headers.Add("Accept-Encoding", "gzip, deflate");
+
+                byte[] data = outputStream.ToArray();
+                connection.ContentLength = data.Length;
+
+                using (Stream requestStream = connection.GetRequestStream())
+                {
+                    requestStream.Write(data, 0, data.Length);
+
+                    // Resolve HTTP hang that can happens after successive calls by making sure
+                    // that we release the response and response stream. To support this, we copy
+                    // the response to a memory stream.
+                    using (var response = connection.GetResponse())
+                    {
+                        using (var responseStream = response.GetResponseStream())
+                        {
+                            // Copy the response to a memory stream so that we can
+                            // cleanly close the response and response stream.
+                            inputStream = new MemoryStream();
+                            byte[] buffer = new byte[8192];  // multiple of 4096
+                            int bytesRead;
+                            while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
+                            {
+                                inputStream.Write(buffer, 0, bytesRead);
+                            }
+                            inputStream.Seek(0, 0);
+                        }
+
+                        var encodings = response.Headers.GetValues("Content-Encoding");
+                        if (encodings != null)
+                        {
+                            foreach (var encoding in encodings)
+                            {
+                                switch (encoding)
+                                {
+                                    case "gzip":
+                                        DecompressGZipped(ref inputStream);
+                                        break;
+                                    case "deflate":
+                                        DecompressDeflated(ref inputStream);
+                                        break;
+                                    default:
+                                        break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            catch (IOException iox)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString(), iox);
+            }
+            catch (WebException wx)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, "Couldn't connect to server: " + wx, wx);
+            }
+        }
+
+        private void DecompressDeflated(ref Stream inputStream)
+        {
+            var tmp = new MemoryStream();
+            using (var decomp = new DeflateStream(inputStream, CompressionMode.Decompress))
+            {
+                decomp.CopyTo(tmp);
+            }
+            inputStream.Dispose();
+            inputStream = tmp;
+            inputStream.Seek(0, 0);
+        }
+
+        private void DecompressGZipped(ref Stream inputStream)
+        {
+            var tmp = new MemoryStream();
+            using (var decomp = new GZipStream(inputStream, CompressionMode.Decompress))
+            {
+                decomp.CopyTo(tmp);
+            }
+            inputStream.Dispose();
+            inputStream = tmp;
+            inputStream.Seek(0, 0);
+        }
+#endif
+        private HttpWebRequest CreateRequest()
+        {
+            HttpWebRequest connection = (HttpWebRequest)WebRequest.Create(uri);
+
+
+#if !SILVERLIGHT
+            // Adding certificates through code is not supported with WP7 Silverlight
+            // see "Windows Phone 7 and Certificates_FINAL_121610.pdf"
+            connection.ClientCertificates.AddRange(certificates);
+
+            if (connectTimeout > 0)
+            {
+                connection.Timeout = connectTimeout;
+            }
+            if (readTimeout > 0)
+            {
+                connection.ReadWriteTimeout = readTimeout;
+            }
+#endif
+            // Make the request
+            connection.ContentType = "application/x-thrift";
+            connection.Accept = "application/x-thrift";
+            connection.UserAgent = userAgent;
+            connection.Method = "POST";
+#if !SILVERLIGHT
+            connection.ProtocolVersion = HttpVersion.Version10;
+#endif
+
+            //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
+            }
+
+#if !SILVERLIGHT
+            connection.Proxy = proxy;
+#endif
+
+            return connection;
+        }
+
+        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(), iox);
+            }
+        }
+
+        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(), exception);
+                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(), exception);
+            }
+            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);
+                }
+            }
+        }
+
+        #region " IDisposable Support "
+        private bool _IsDisposed;
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (inputStream != null)
+                        inputStream.Dispose();
+                    if (outputStream != null)
+                        outputStream.Dispose();
+                }
+            }
+            _IsDisposed = true;
+        }
+        #endregion
+    }
+}
diff --git a/lib/csharp/src/Transport/THttpHandler.cs b/lib/csharp/src/Transport/THttpHandler.cs
new file mode 100644
index 0000000..4115ef9
--- /dev/null
+++ b/lib/csharp/src/Transport/THttpHandler.cs
@@ -0,0 +1,102 @@
+/**
+ * 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;
+using System.Web;
+using System.Net;
+using System.IO;
+
+using Thrift.Protocol;
+
+namespace Thrift.Transport
+{
+    public class THttpHandler : IHttpHandler
+    {
+        protected TProcessor processor;
+
+        protected TProtocolFactory inputProtocolFactory;
+        protected TProtocolFactory outputProtocolFactory;
+
+        protected const string contentType = "application/x-thrift";
+        protected System.Text.Encoding encoding = System.Text.Encoding.UTF8;
+
+        public THttpHandler(TProcessor processor)
+            : this(processor, new TBinaryProtocol.Factory())
+        {
+
+        }
+
+        public THttpHandler(TProcessor processor, TProtocolFactory protocolFactory)
+            : this(processor, protocolFactory, protocolFactory)
+        {
+
+        }
+
+        public THttpHandler(TProcessor processor, TProtocolFactory inputProtocolFactory, TProtocolFactory outputProtocolFactory)
+        {
+            this.processor = processor;
+            this.inputProtocolFactory = inputProtocolFactory;
+            this.outputProtocolFactory = outputProtocolFactory;
+        }
+
+        public void ProcessRequest(HttpListenerContext context)
+        {
+            context.Response.ContentType = contentType;
+            context.Response.ContentEncoding = encoding;
+            ProcessRequest(context.Request.InputStream, context.Response.OutputStream);
+        }
+
+        public void ProcessRequest(HttpContext context)
+        {
+            context.Response.ContentType = contentType;
+            context.Response.ContentEncoding = encoding;
+            ProcessRequest(context.Request.InputStream, context.Response.OutputStream);
+        }
+
+        public void ProcessRequest(Stream input, Stream output)
+        {
+            TTransport transport = new TStreamTransport(input,output);
+
+            try
+            {
+                var inputProtocol = inputProtocolFactory.GetProtocol(transport);
+                var outputProtocol = outputProtocolFactory.GetProtocol(transport);
+
+                while (processor.Process(inputProtocol, outputProtocol))
+                {
+                }
+            }
+            catch (TTransportException)
+            {
+                // Client died, just move on
+            }
+            finally
+            {
+                transport.Close();
+            }
+        }
+
+        public bool IsReusable
+        {
+            get { return true; }
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/THttpTaskAsyncHandler.cs b/lib/csharp/src/Transport/THttpTaskAsyncHandler.cs
new file mode 100644
index 0000000..e491f32
--- /dev/null
+++ b/lib/csharp/src/Transport/THttpTaskAsyncHandler.cs
@@ -0,0 +1,97 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System.Threading.Tasks;
+using System.Web;
+using Thrift.Protocol;
+
+namespace Thrift.Transport
+{
+    /// <summary>
+    /// An async task based HTTP handler for processing thrift services.
+    /// </summary>
+    public class THttpTaskAsyncHandler : HttpTaskAsyncHandler
+    {
+        private readonly TAsyncProcessor _processor;
+        private readonly TProtocolFactory _inputProtocolFactory;
+        private readonly TProtocolFactory _outputProtocolFactory;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="THttpTaskAsyncHandler"/> class
+        /// using the <see cref="TBinaryProtocol.Factory"/> for both input and output streams.
+        /// </summary>
+        /// <param name="processor">The async processor implementation.</param>
+        public THttpTaskAsyncHandler(TAsyncProcessor processor)
+            : this(processor, new TBinaryProtocol.Factory())
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="THttpTaskAsyncHandler"/> class
+        /// using <paramref name="protocolFactory"/> for both input and output streams.
+        /// </summary>
+        /// <param name="processor">The async processor implementation.</param>
+        /// <param name="protocolFactory">The protocol factory.</param>
+        public THttpTaskAsyncHandler(TAsyncProcessor processor, TProtocolFactory protocolFactory)
+            : this(processor, protocolFactory, protocolFactory)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="THttpTaskAsyncHandler"/> class.
+        /// </summary>
+        /// <param name="processor">The async processor implementation.</param>
+        /// <param name="inputProtocolFactory">The input protocol factory.</param>
+        /// <param name="outputProtocolFactory">The output protocol factory.</param>
+        public THttpTaskAsyncHandler(TAsyncProcessor processor, TProtocolFactory inputProtocolFactory,
+            TProtocolFactory outputProtocolFactory)
+        {
+            _processor = processor;
+            _inputProtocolFactory = inputProtocolFactory;
+            _outputProtocolFactory = outputProtocolFactory;
+        }
+
+        public override async Task ProcessRequestAsync(HttpContext context)
+        {
+            var transport = new TStreamTransport(context.Request.InputStream, context.Response.OutputStream);
+
+            try
+            {
+                var input = _inputProtocolFactory.GetProtocol(transport);
+                var output = _outputProtocolFactory.GetProtocol(transport);
+
+                while (await _processor.ProcessAsync(input, output))
+                {
+                }
+            }
+            catch (TTransportException)
+            {
+                // Client died, just move on
+            }
+            finally
+            {
+                transport.Close();
+            }
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TMemoryBuffer.cs b/lib/csharp/src/Transport/TMemoryBuffer.cs
new file mode 100644
index 0000000..303d083
--- /dev/null
+++ b/lib/csharp/src/Transport/TMemoryBuffer.cs
@@ -0,0 +1,117 @@
+/**
+ * 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;
+using System.IO;
+using System.Reflection;
+using Thrift.Protocol;
+
+namespace Thrift.Transport
+{
+    public class TMemoryBuffer : TTransport
+    {
+
+        private readonly MemoryStream byteStream;
+
+        public TMemoryBuffer()
+        {
+            byteStream = new MemoryStream();
+        }
+
+        public TMemoryBuffer(byte[] buf)
+        {
+            byteStream = new MemoryStream(buf);
+        }
+
+        public override void Open()
+        {
+            /** do nothing **/
+        }
+
+        public override void Close()
+        {
+            /** do nothing **/
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            return byteStream.Read(buf, off, len);
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            byteStream.Write(buf, off, len);
+        }
+
+        public byte[] GetBuffer()
+        {
+            return byteStream.ToArray();
+        }
+
+
+        public override bool IsOpen
+        {
+            get { return true; }
+        }
+
+        public static byte[] Serialize(TAbstractBase s)
+        {
+            var t = new TMemoryBuffer();
+            var p = new TBinaryProtocol(t);
+
+            s.Write(p);
+
+            return t.GetBuffer();
+        }
+
+        public static T DeSerialize<T>(byte[] buf) where T : TAbstractBase
+        {
+            var trans = new TMemoryBuffer(buf);
+            var p = new TBinaryProtocol(trans);
+            if (typeof(TBase).IsAssignableFrom(typeof(T)))
+            {
+                var method = typeof(T).GetMethod("Read", BindingFlags.Instance | BindingFlags.Public);
+                var t = Activator.CreateInstance<T>();
+                method.Invoke(t, new object[] { p });
+                return t;
+            }
+            else
+            {
+                var method = typeof(T).GetMethod("Read", BindingFlags.Static | BindingFlags.Public);
+                return (T)method.Invoke(null, new object[] { p });
+            }
+        }
+
+        private bool _IsDisposed;
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (byteStream != null)
+                        byteStream.Dispose();
+                }
+            }
+            _IsDisposed = true;
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TNamedPipeClientTransport.cs b/lib/csharp/src/Transport/TNamedPipeClientTransport.cs
new file mode 100644
index 0000000..49a50aa
--- /dev/null
+++ b/lib/csharp/src/Transport/TNamedPipeClientTransport.cs
@@ -0,0 +1,111 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.IO.Pipes;
+using System.Threading;
+
+namespace Thrift.Transport
+{
+    public class TNamedPipeClientTransport : TTransport
+    {
+        private NamedPipeClientStream client;
+        private string ServerName;
+        private string PipeName;
+        private int ConnectTimeout;
+
+        public TNamedPipeClientTransport(string pipe, int timeout = Timeout.Infinite)
+        {
+            ServerName = ".";
+            PipeName = pipe;
+            ConnectTimeout = timeout;
+        }
+
+        public TNamedPipeClientTransport(string server, string pipe, int timeout = Timeout.Infinite)
+        {
+            ServerName = (server != "") ? server : ".";
+            PipeName = pipe;
+            ConnectTimeout = timeout;
+        }
+
+        public override bool IsOpen
+        {
+            get { return client != null && client.IsConnected; }
+        }
+
+        public override void Open()
+        {
+            if (IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen);
+            }
+            client = new NamedPipeClientStream(ServerName, PipeName, PipeDirection.InOut, PipeOptions.None);
+            client.Connect(ConnectTimeout);
+        }
+
+        public override void Close()
+        {
+            if (client != null)
+            {
+                client.Close();
+                client = null;
+            }
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            if (client == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            }
+
+            return client.Read(buf, off, len);
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            if (client == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            }
+
+            // if necessary, send the data in chunks
+            // there's a system limit around 0x10000 bytes that we hit otherwise
+            // MSDN: "Pipe write operations across a network are limited to 65,535 bytes per write. For more information regarding pipes, see the Remarks section."
+            var nBytes = Math.Min(len, 15 * 4096);  // 16 would exceed the limit
+            while (nBytes > 0)
+            {
+                client.Write(buf, off, nBytes);
+
+                off += nBytes;
+                len -= nBytes;
+                nBytes = Math.Min(len, nBytes);
+            }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            client.Dispose();
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TNamedPipeServerTransport.cs b/lib/csharp/src/Transport/TNamedPipeServerTransport.cs
new file mode 100644
index 0000000..32215cf
--- /dev/null
+++ b/lib/csharp/src/Transport/TNamedPipeServerTransport.cs
@@ -0,0 +1,296 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.IO.Pipes;
+using System.Threading;
+using System.Security.Principal;
+
+namespace Thrift.Transport
+{
+    public class TNamedPipeServerTransport : TServerTransport
+    {
+        /// <summary>
+        /// This is the address of the Pipe on the localhost.
+        /// </summary>
+        private readonly string pipeAddress;
+        private NamedPipeServerStream stream = null;
+        private bool asyncMode = true;
+
+        public TNamedPipeServerTransport(string pipeAddress)
+        {
+            this.pipeAddress = pipeAddress;
+        }
+
+        public override void Listen()
+        {
+            // nothing to do here
+        }
+
+        public override void Close()
+        {
+            if (stream != null)
+            {
+                try
+                {
+                    stream.Close();
+                    stream.Dispose();
+                }
+                finally
+                {
+                    stream = null;
+                }
+            }
+        }
+
+        private void EnsurePipeInstance()
+        {
+            if (stream == null)
+            {
+                var direction = PipeDirection.InOut;
+                var maxconn = NamedPipeServerStream.MaxAllowedServerInstances;
+                var mode = PipeTransmissionMode.Byte;
+                var options = asyncMode ? PipeOptions.Asynchronous : PipeOptions.None;
+                const int INBUF_SIZE = 4096;
+                const int OUTBUF_SIZE = 4096;
+
+                // security
+                var security = new PipeSecurity();
+                security.AddAccessRule(
+                    new PipeAccessRule(
+                        new SecurityIdentifier(WellKnownSidType.WorldSid, null),
+                        PipeAccessRights.Read | PipeAccessRights.Write | PipeAccessRights.Synchronize | PipeAccessRights.CreateNewInstance,
+                        System.Security.AccessControl.AccessControlType.Allow
+                    )
+                );
+
+                try
+                {
+                    stream = new NamedPipeServerStream(pipeAddress, direction, maxconn, mode, options, INBUF_SIZE, OUTBUF_SIZE, security);
+                }
+                catch (NotImplementedException)  // Mono still does not support async, fallback to sync
+                {
+                    if (asyncMode)
+                    {
+                        options &= (~PipeOptions.Asynchronous);
+                        stream = new NamedPipeServerStream(pipeAddress, direction, maxconn, mode, options, INBUF_SIZE, OUTBUF_SIZE, security);
+                        asyncMode = false;
+                    }
+                    else
+                    {
+                        throw;
+                    }
+                }
+
+            }
+        }
+
+        protected override TTransport AcceptImpl()
+        {
+            try
+            {
+                EnsurePipeInstance();
+
+                if (asyncMode)
+                {
+                    var evt = new ManualResetEvent(false);
+                    Exception eOuter = null;
+
+                    stream.BeginWaitForConnection(asyncResult =>
+                    {
+                        try
+                        {
+                            if (stream != null)
+                                stream.EndWaitForConnection(asyncResult);
+                            else
+                                eOuter = new TTransportException(TTransportException.ExceptionType.Interrupted);
+                        }
+                        catch (Exception e)
+                        {
+                            if (stream != null)
+                                eOuter = e;
+                            else
+                                eOuter = new TTransportException(TTransportException.ExceptionType.Interrupted, e.Message, e);
+                        }
+                        evt.Set();
+                    }, null);
+
+                    evt.WaitOne();
+
+                    if (eOuter != null)
+                        throw eOuter; // rethrow exception
+                }
+                else
+                {
+                    stream.WaitForConnection();
+                }
+
+                var trans = new ServerTransport(stream,asyncMode);
+                stream = null;  // pass ownership to ServerTransport
+                return trans;
+            }
+            catch (TTransportException)
+            {
+                Close();
+                throw;
+            }
+            catch (Exception e)
+            {
+                Close();
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, e.Message, e);
+            }
+        }
+
+        private class ServerTransport : TTransport
+        {
+            private NamedPipeServerStream stream;
+            private bool asyncMode;
+
+            public ServerTransport(NamedPipeServerStream stream, bool asyncMode)
+            {
+                this.stream = stream;
+                this.asyncMode = asyncMode;
+            }
+
+            public override bool IsOpen
+            {
+                get { return stream != null && stream.IsConnected; }
+            }
+
+            public override void Open()
+            {
+            }
+
+            public override void Close()
+            {
+                if (stream != null)
+                    stream.Close();
+            }
+
+            public override int Read(byte[] buf, int off, int len)
+            {
+                if (stream == null)
+                {
+                    throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+                }
+
+                if (asyncMode)
+                {
+                    Exception eOuter = null;
+                    var evt = new ManualResetEvent(false);
+                    int retval = 0;
+
+                    stream.BeginRead(buf, off, len, asyncResult =>
+                    {
+                        try
+                        {
+                            if (stream != null)
+                                retval = stream.EndRead(asyncResult);
+                            else
+                                eOuter = new TTransportException(TTransportException.ExceptionType.Interrupted);
+                        }
+                        catch (Exception e)
+                        {
+                            if (stream != null)
+                                eOuter = e;
+                            else
+                                eOuter = new TTransportException(TTransportException.ExceptionType.Interrupted, e.Message, e);
+                        }
+                        evt.Set();
+                    }, null);
+
+                    evt.WaitOne();
+
+                    if (eOuter != null)
+                        throw eOuter; // rethrow exception
+                    else
+                        return retval;
+                }
+                else
+                {
+                    return stream.Read(buf, off, len);
+                }
+            }
+
+            public override void Write(byte[] buf, int off, int len)
+            {
+                if (stream == null)
+                {
+                    throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+                }
+
+                // if necessary, send the data in chunks
+                // there's a system limit around 0x10000 bytes that we hit otherwise
+                // MSDN: "Pipe write operations across a network are limited to 65,535 bytes per write. For more information regarding pipes, see the Remarks section."
+                var nBytes = Math.Min(len, 15 * 4096);  // 16 would exceed the limit
+                while (nBytes > 0)
+                {
+
+                    if (asyncMode)
+                    {
+                        Exception eOuter = null;
+                        var evt = new ManualResetEvent(false);
+
+                        stream.BeginWrite(buf, off, nBytes, asyncResult =>
+                        {
+                            try
+                            {
+                                if (stream != null)
+                                    stream.EndWrite(asyncResult);
+                                else
+                                    eOuter = new TTransportException(TTransportException.ExceptionType.Interrupted);
+                            }
+                            catch (Exception e)
+                            {
+                                if (stream != null)
+                                    eOuter = e;
+                                else
+                                    eOuter = new TTransportException(TTransportException.ExceptionType.Interrupted, e.Message, e);
+                            }
+                            evt.Set();
+                        }, null);
+
+                        evt.WaitOne();
+
+                        if (eOuter != null)
+                            throw eOuter; // rethrow exception
+                    }
+                    else
+                    {
+                        stream.Write(buf, off, nBytes);
+                    }
+
+                    off += nBytes;
+                    len -= nBytes;
+                    nBytes = Math.Min(len, nBytes);
+                }
+            }
+
+            protected override void Dispose(bool disposing)
+            {
+                if (stream != null)
+                    stream.Dispose();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/csharp/src/Transport/TServerSocket.cs b/lib/csharp/src/Transport/TServerSocket.cs
new file mode 100644
index 0000000..d8ec62a
--- /dev/null
+++ b/lib/csharp/src/Transport/TServerSocket.cs
@@ -0,0 +1,176 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Net.Sockets;
+
+
+namespace Thrift.Transport
+{
+    public class TServerSocket : TServerTransport
+    {
+        /// <summary>
+        /// Underlying server with socket.
+        /// </summary>
+        private TcpListener server = null;
+
+        /// <summary>
+        /// Port to listen on.
+        /// </summary>
+        private int port = 0;
+
+        /// <summary>
+        /// Timeout for client sockets from accept.
+        /// </summary>
+        private int clientTimeout = 0;
+
+        /// <summary>
+        /// Whether or not to wrap new TSocket connections in buffers.
+        /// </summary>
+        private bool useBufferedSockets = false;
+
+        /// <summary>
+        /// Creates a server socket from underlying socket object.
+        /// </summary>
+        public TServerSocket(TcpListener listener)
+            : this(listener, 0)
+        {
+        }
+
+        /// <summary>
+        /// Creates a server socket from underlying socket object.
+        /// </summary>
+        public TServerSocket(TcpListener listener, int clientTimeout)
+        {
+            this.server = listener;
+            this.clientTimeout = clientTimeout;
+        }
+
+        /// <summary>
+        /// Creates just a port listening server socket.
+        /// </summary>
+        public TServerSocket(int port)
+            : this(port, 0)
+        {
+        }
+
+        /// <summary>
+        /// Creates just a port listening server socket.
+        /// </summary>
+        public TServerSocket(int port, int clientTimeout)
+            : this(port, clientTimeout, false)
+        {
+        }
+
+        public TServerSocket(int port, int clientTimeout, bool useBufferedSockets)
+        {
+            this.port = port;
+            this.clientTimeout = clientTimeout;
+            this.useBufferedSockets = useBufferedSockets;
+            try
+            {
+                // Make server socket
+                this.server = TSocketVersionizer.CreateTcpListener(this.port);
+                this.server.Server.NoDelay = true;
+            }
+            catch (Exception ex)
+            {
+                server = null;
+                throw new TTransportException("Could not create ServerSocket on port " + this.port + ".", ex);
+            }
+        }
+
+        public override void Listen()
+        {
+            // Make sure not to block on accept
+            if (server != null)
+            {
+                try
+                {
+                    server.Start();
+                }
+                catch (SocketException sx)
+                {
+                    throw new TTransportException("Could not accept on listening socket: " + sx.Message, sx);
+                }
+            }
+        }
+
+        protected override TTransport AcceptImpl()
+        {
+            if (server == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket.");
+            }
+            try
+            {
+                TSocket result2 = null;
+                TcpClient result = server.AcceptTcpClient();
+                try
+                {
+                    result2 = new TSocket(result);
+                    result2.Timeout = clientTimeout;
+                    if (useBufferedSockets)
+                    {
+                        TBufferedTransport result3 = new TBufferedTransport(result2);
+                        return result3;
+                    }
+                    else
+                    {
+                        return result2;
+                    }
+                }
+                catch (System.Exception)
+                {
+                    // If a TSocket was successfully created, then let
+                    // it do proper cleanup of the TcpClient object.
+                    if (result2 != null)
+                        result2.Dispose();
+                    else //  Otherwise, clean it up ourselves.
+                        ((IDisposable)result).Dispose();
+                    throw;
+                }
+            }
+            catch (Exception ex)
+            {
+                throw new TTransportException(ex.ToString(), ex);
+            }
+        }
+
+        public override void Close()
+        {
+            if (server != null)
+            {
+                try
+                {
+                    server.Stop();
+                }
+                catch (Exception ex)
+                {
+                    throw new TTransportException("WARNING: Could not close server socket: " + ex, ex);
+                }
+                server = null;
+            }
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TServerTransport.cs b/lib/csharp/src/Transport/TServerTransport.cs
new file mode 100644
index 0000000..e63880b
--- /dev/null
+++ b/lib/csharp/src/Transport/TServerTransport.cs
@@ -0,0 +1,44 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift.Transport
+{
+    public abstract class TServerTransport
+    {
+        public abstract void Listen();
+        public abstract void Close();
+        protected abstract TTransport AcceptImpl();
+
+        public TTransport Accept()
+        {
+            TTransport transport = AcceptImpl();
+            if (transport == null)
+            {
+                throw new TTransportException("accept() may not return NULL");
+            }
+            return transport;
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TSilverlightSocket.cs b/lib/csharp/src/Transport/TSilverlightSocket.cs
new file mode 100644
index 0000000..40469ab
--- /dev/null
+++ b/lib/csharp/src/Transport/TSilverlightSocket.cs
@@ -0,0 +1,393 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+/* only for silverlight */
+#if SILVERLIGHT
+
+using System;
+using System.Net.Sockets;
+using System.IO;
+using System.Net;
+using System.Threading;
+
+namespace Thrift.Transport
+{
+    public class TSilverlightSocket : TTransport
+    {
+        Socket socket = null;
+        static ManualResetEvent readAsyncComplete = new ManualResetEvent(false);
+        public event EventHandler<SocketAsyncEventArgs> connectHandler = null;
+
+        // memory stream for write cache.
+        private MemoryStream outputStream = new MemoryStream();
+
+        private string host = null;
+        private int port = 0;
+        private int timeout = 0;
+
+        // constructor
+        public TSilverlightSocket(string host, int port)
+            : this(host, port, 0)
+        {
+        }
+
+        // constructor
+        public TSilverlightSocket(string host, int port, int timeout)
+        {
+            this.host = host;
+            this.port = port;
+            this.timeout = timeout;
+
+            InitSocket();
+        }
+
+        private void InitSocket()
+        {
+            // Create a stream-based, TCP socket using the InterNetwork Address Family.
+            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+            socket.NoDelay = true;
+        }
+
+        public int Timeout
+        {
+            set
+            {
+                timeout = value;
+            }
+        }
+
+        public string Host
+        {
+            get
+            {
+                return host;
+            }
+        }
+
+        public int Port
+        {
+            get
+            {
+                return port;
+            }
+        }
+
+        public override bool IsOpen
+        {
+            get
+            {
+                if (socket == null)
+                {
+                    return false;
+                }
+
+                return socket.Connected;
+            }
+        }
+
+        public override void Open()
+        {
+            if (IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
+            }
+
+            if (string.IsNullOrEmpty(host))
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
+            }
+
+            if (port <= 0)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
+            }
+
+            if (socket == null)
+            {
+                InitSocket();
+            }
+
+            if (timeout == 0)     // no timeout -> infinite
+            {
+                timeout = 10000;  // set a default timeout for WP.
+            }
+
+            {
+                // Create DnsEndPoint. The hostName and port are passed in to this method.
+                DnsEndPoint hostEntry = new DnsEndPoint(this.host, this.port);
+
+                // Create a SocketAsyncEventArgs object to be used in the connection request
+                SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
+                socketEventArg.RemoteEndPoint = hostEntry;
+
+                // Inline event handler for the Completed event.
+                // Note: This event handler was implemented inline in order to make this method self-contained.
+                socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
+                {
+                    if (connectHandler != null)
+                    {
+                        connectHandler(this, e);
+                    }
+                });
+
+                // Make an asynchronous Connect request over the socket
+                socket.ConnectAsync(socketEventArg);
+            }
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            bool _timeout = true;
+            string _error = null;
+            int _recvBytes = -1;
+
+            if (socket == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Socket is not open");
+            }
+
+            // Create SocketAsyncEventArgs context object
+            SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
+            socketEventArg.RemoteEndPoint = socket.RemoteEndPoint;
+
+            // Setup the buffer to receive the data
+            socketEventArg.SetBuffer(buf, off, len);
+
+            // Inline event handler for the Completed event.
+            // Note: This even handler was implemented inline in order to make
+            // this method self-contained.
+            socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
+            {
+                _timeout = false;
+
+                if (e.SocketError == SocketError.Success)
+                {
+                    _recvBytes = e.BytesTransferred;
+                }
+                else
+                {
+                    _error = e.SocketError.ToString();
+                }
+
+                readAsyncComplete.Set();
+            });
+
+            // Sets the state of the event to nonsignaled, causing threads to block
+            readAsyncComplete.Reset();
+
+            // Make an asynchronous Receive request over the socket
+            socket.ReceiveAsync(socketEventArg);
+
+            // Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
+            // If no response comes back within this time then proceed
+            readAsyncComplete.WaitOne(this.timeout);
+
+            if (_timeout)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.TimedOut, "Socket recv timeout");
+            }
+
+            if (_error != null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, _error);
+            }
+
+            return _recvBytes;
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            outputStream.Write(buf, off, len);
+        }
+
+        private void beginFlush_Completed(object sender, SocketAsyncEventArgs e)
+        {
+            FlushAsyncResult flushAsyncResult = e.UserToken as FlushAsyncResult;
+            flushAsyncResult.UpdateStatusToComplete();
+            flushAsyncResult.NotifyCallbackWhenAvailable();
+
+            if (e.SocketError != SocketError.Success)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, e.SocketError.ToString());
+            }
+        }
+
+        public override IAsyncResult BeginFlush(AsyncCallback callback, object state)
+        {
+            // Extract request and reset buffer
+            byte[] data = outputStream.ToArray();
+
+            FlushAsyncResult flushAsyncResult = new FlushAsyncResult(callback, state);
+
+            SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
+            socketEventArg.RemoteEndPoint = socket.RemoteEndPoint;
+            socketEventArg.UserToken = flushAsyncResult;
+
+            socketEventArg.Completed += beginFlush_Completed;
+            socketEventArg.SetBuffer(data, 0, data.Length);
+
+            socket.SendAsync(socketEventArg);
+
+            return flushAsyncResult;
+        }
+
+        public override void EndFlush(IAsyncResult asyncResult)
+        {
+            try
+            {
+                var flushAsyncResult = (FlushAsyncResult)asyncResult;
+
+                if (!flushAsyncResult.IsCompleted)
+                {
+                    var waitHandle = flushAsyncResult.AsyncWaitHandle;
+                    waitHandle.WaitOne();
+                    waitHandle.Close();
+                }
+
+                if (flushAsyncResult.AsyncException != null)
+                {
+                    throw flushAsyncResult.AsyncException;
+                }
+            }
+            finally
+            {
+                outputStream = new MemoryStream();
+            }
+        }
+
+        // Copy from impl from THttpClient.cs
+        // 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 Socket 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);
+                }
+            }
+        }
+
+        public override void Close()
+        {
+            if (socket != null)
+            {
+                socket.Close();
+                socket = null;
+            }
+        }
+
+#region " IDisposable Support "
+        private bool _IsDisposed;
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (outputStream != null)
+                    {
+                        outputStream.Dispose();
+                    }
+                    outputStream = null;
+                    if (socket != null)
+                    {
+                        ((IDisposable)socket).Dispose();
+                    }
+                }
+            }
+            _IsDisposed = true;
+        }
+#endregion
+    }
+}
+
+
+#endif
diff --git a/lib/csharp/src/Transport/TSocket.cs b/lib/csharp/src/Transport/TSocket.cs
new file mode 100644
index 0000000..d8fa335
--- /dev/null
+++ b/lib/csharp/src/Transport/TSocket.cs
@@ -0,0 +1,245 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Net.Sockets;
+
+namespace Thrift.Transport
+{
+    public class TSocket : TStreamTransport
+    {
+        private TcpClient client = null;
+        private string host = null;
+        private int port = 0;
+        private int timeout = 0;
+
+        public TSocket(TcpClient client)
+        {
+            this.client = client;
+
+            if (IsOpen)
+            {
+                inputStream = client.GetStream();
+                outputStream = client.GetStream();
+            }
+        }
+
+        public TSocket(string host, int port)
+            : this(host, port, 0)
+        {
+        }
+
+        public TSocket(string host, int port, int timeout)
+        {
+            this.host = host;
+            this.port = port;
+            this.timeout = timeout;
+
+            InitSocket();
+        }
+
+        private void InitSocket()
+        {
+            this.client = TSocketVersionizer.CreateTcpClient();
+            this.client.ReceiveTimeout = client.SendTimeout = timeout;
+            this.client.Client.NoDelay = true;
+        }
+
+        public int Timeout
+        {
+            set
+            {
+                client.ReceiveTimeout = client.SendTimeout = timeout = value;
+            }
+        }
+
+        public TcpClient TcpClient
+        {
+            get
+            {
+                return client;
+            }
+        }
+
+        public string Host
+        {
+            get
+            {
+                return host;
+            }
+        }
+
+        public int Port
+        {
+            get
+            {
+                return port;
+            }
+        }
+
+        public override bool IsOpen
+        {
+            get
+            {
+                if (client == null)
+                {
+                    return false;
+                }
+
+                return client.Connected;
+            }
+        }
+
+        public override void Open()
+        {
+            if (IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
+            }
+
+            if (string.IsNullOrEmpty(host))
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
+            }
+
+            if (port <= 0)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
+            }
+
+            if (client == null)
+            {
+                InitSocket();
+            }
+
+            if (timeout == 0)            // no timeout -> infinite
+            {
+                client.Connect(host, port);
+            }
+            else                        // we have a timeout -> use it
+            {
+                ConnectHelper hlp = new ConnectHelper(client);
+                IAsyncResult asyncres = client.BeginConnect(host, port, new AsyncCallback(ConnectCallback), hlp);
+                bool bConnected = asyncres.AsyncWaitHandle.WaitOne(timeout) && client.Connected;
+                if (!bConnected)
+                {
+                    lock (hlp.Mutex)
+                    {
+                        if (hlp.CallbackDone)
+                        {
+                            asyncres.AsyncWaitHandle.Close();
+                            client.Close();
+                        }
+                        else
+                        {
+                            hlp.DoCleanup = true;
+                            client = null;
+                        }
+                    }
+                    throw new TTransportException(TTransportException.ExceptionType.TimedOut, "Connect timed out");
+                }
+            }
+
+            inputStream = client.GetStream();
+            outputStream = client.GetStream();
+        }
+
+
+        static void ConnectCallback(IAsyncResult asyncres)
+        {
+            ConnectHelper hlp = asyncres.AsyncState as ConnectHelper;
+            lock (hlp.Mutex)
+            {
+                hlp.CallbackDone = true;
+
+                try
+                {
+                    if (hlp.Client.Client != null)
+                        hlp.Client.EndConnect(asyncres);
+                }
+                catch (Exception)
+                {
+                    // catch that away
+                }
+
+                if (hlp.DoCleanup)
+                {
+                    try
+                    {
+                        asyncres.AsyncWaitHandle.Close();
+                    }
+                    catch (Exception) { }
+
+                    try
+                    {
+                        if (hlp.Client is IDisposable)
+                            ((IDisposable)hlp.Client).Dispose();
+                    }
+                    catch (Exception) { }
+                    hlp.Client = null;
+                }
+            }
+        }
+
+        private class ConnectHelper
+        {
+            public object Mutex = new object();
+            public bool DoCleanup = false;
+            public bool CallbackDone = false;
+            public TcpClient Client;
+            public ConnectHelper(TcpClient client)
+            {
+                Client = client;
+            }
+        }
+
+        public override void Close()
+        {
+            base.Close();
+            if (client != null)
+            {
+                client.Close();
+                client = null;
+            }
+        }
+
+        #region " IDisposable Support "
+        private bool _IsDisposed;
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (client != null)
+                        ((IDisposable)client).Dispose();
+                    base.Dispose(disposing);
+                }
+            }
+            _IsDisposed = true;
+        }
+        #endregion
+    }
+}
diff --git a/lib/csharp/src/Transport/TSocketVersionizer.cs b/lib/csharp/src/Transport/TSocketVersionizer.cs
new file mode 100644
index 0000000..8c2f8e9
--- /dev/null
+++ b/lib/csharp/src/Transport/TSocketVersionizer.cs
@@ -0,0 +1,78 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Text;
+#if NET45
+using System.Threading.Tasks;
+#endif
+
+namespace Thrift.Transport
+{
+    /// <summary>
+    /// PropertyInfo for the DualMode property of the System.Net.Sockets.Socket class. Used to determine if the sockets are capable of
+    /// automatic IPv4 and IPv6 handling. If DualMode is present the sockets automatically handle IPv4 and IPv6 connections.
+    /// If the DualMode is not available the system configuration determines whether IPv4 or IPv6 is used.
+    /// </summary>
+    internal static class TSocketVersionizer
+    {
+        /// <summary>
+        /// Creates a TcpClient according to the capabilities of the used framework.
+        /// </summary>
+        internal static TcpClient CreateTcpClient()
+        {
+            TcpClient client = null;
+
+#if NET45
+            client = new TcpClient(AddressFamily.InterNetworkV6);
+            client.Client.DualMode = true;
+#else
+            client = new TcpClient(AddressFamily.InterNetwork);
+#endif
+
+            return client;
+        }
+
+        /// <summary>
+        /// Creates a TcpListener according to the capabilities of the used framework.
+        /// </summary>
+        internal static TcpListener CreateTcpListener(Int32 port)
+        {
+            TcpListener listener = null;
+
+#if NET45
+            listener = new TcpListener(System.Net.IPAddress.IPv6Any, port);
+            listener.Server.DualMode = true;
+#else
+
+            listener = new TcpListener(System.Net.IPAddress.Any, port);
+#endif
+
+            return listener;
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TStreamTransport.cs b/lib/csharp/src/Transport/TStreamTransport.cs
new file mode 100644
index 0000000..304599f
--- /dev/null
+++ b/lib/csharp/src/Transport/TStreamTransport.cs
@@ -0,0 +1,128 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.IO;
+
+namespace Thrift.Transport
+{
+    public class TStreamTransport : TTransport
+    {
+        protected Stream inputStream;
+        protected Stream outputStream;
+
+        protected TStreamTransport()
+        {
+        }
+
+        public TStreamTransport(Stream inputStream, Stream outputStream)
+        {
+            this.inputStream = inputStream;
+            this.outputStream = outputStream;
+        }
+
+        public Stream OutputStream
+        {
+            get { return outputStream; }
+        }
+
+        public Stream InputStream
+        {
+            get { return inputStream; }
+        }
+
+        public override bool IsOpen
+        {
+            get { return true; }
+        }
+
+        public override void Open()
+        {
+        }
+
+        public override void Close()
+        {
+            if (inputStream != null)
+            {
+                inputStream.Close();
+                inputStream = null;
+            }
+            if (outputStream != null)
+            {
+                outputStream.Close();
+                outputStream = null;
+            }
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            if (inputStream == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot read from null inputstream");
+            }
+
+            return inputStream.Read(buf, off, len);
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            if (outputStream == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot write to null outputstream");
+            }
+
+            outputStream.Write(buf, off, len);
+        }
+
+        public override void Flush()
+        {
+            if (outputStream == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot flush null outputstream");
+            }
+
+            outputStream.Flush();
+        }
+
+
+        #region " IDisposable Support "
+        private bool _IsDisposed;
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (InputStream != null)
+                        InputStream.Dispose();
+                    if (OutputStream != null)
+                        OutputStream.Dispose();
+                }
+            }
+            _IsDisposed = true;
+        }
+        #endregion
+    }
+}
diff --git a/lib/csharp/src/Transport/TTLSServerSocket.cs b/lib/csharp/src/Transport/TTLSServerSocket.cs
new file mode 100644
index 0000000..716a97c
--- /dev/null
+++ b/lib/csharp/src/Transport/TTLSServerSocket.cs
@@ -0,0 +1,223 @@
+/**
+ * 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;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Thrift.Transport
+{
+    /// <summary>
+    /// SSL Server Socket Wrapper Class
+    /// </summary>
+    public class TTLSServerSocket : TServerTransport
+    {
+        /// <summary>
+        /// Underlying tcp server
+        /// </summary>
+        private TcpListener server = null;
+
+        /// <summary>
+        /// The port where the socket listen
+        /// </summary>
+        private int port = 0;
+
+        /// <summary>
+        /// Timeout for the created server socket
+        /// </summary>
+        private readonly int clientTimeout;
+
+        /// <summary>
+        /// Whether or not to wrap new TSocket connections in buffers
+        /// </summary>
+        private bool useBufferedSockets = false;
+
+        /// <summary>
+        /// The servercertificate with the private- and public-key
+        /// </summary>
+        private X509Certificate serverCertificate;
+
+        /// <summary>
+        /// The function to validate the client certificate.
+        /// </summary>
+        private RemoteCertificateValidationCallback clientCertValidator;
+
+        /// <summary>
+        /// The function to determine which certificate to use.
+        /// </summary>
+        private LocalCertificateSelectionCallback localCertificateSelectionCallback;
+
+        /// <summary>
+        /// The SslProtocols value that represents the protocol used for authentication.
+        /// </summary>
+        private readonly SslProtocols sslProtocols;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSServerSocket" /> class.
+        /// </summary>
+        /// <param name="port">The port where the server runs.</param>
+        /// <param name="certificate">The certificate object.</param>
+        public TTLSServerSocket(int port, X509Certificate2 certificate)
+            : this(port, 0, certificate)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSServerSocket" /> class.
+        /// </summary>
+        /// <param name="port">The port where the server runs.</param>
+        /// <param name="clientTimeout">Send/receive timeout.</param>
+        /// <param name="certificate">The certificate object.</param>
+        public TTLSServerSocket(int port, int clientTimeout, X509Certificate2 certificate)
+            : this(port, clientTimeout, false, certificate)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSServerSocket" /> class.
+        /// </summary>
+        /// <param name="port">The port where the server runs.</param>
+        /// <param name="clientTimeout">Send/receive timeout.</param>
+        /// <param name="useBufferedSockets">If set to <c>true</c> [use buffered sockets].</param>
+        /// <param name="certificate">The certificate object.</param>
+        /// <param name="clientCertValidator">The certificate validator.</param>
+        /// <param name="localCertificateSelectionCallback">The callback to select which certificate to use.</param>
+        /// <param name="sslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
+        public TTLSServerSocket(
+            int port,
+            int clientTimeout,
+            bool useBufferedSockets,
+            X509Certificate2 certificate,
+            RemoteCertificateValidationCallback clientCertValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            // TODO: Enable Tls11 and Tls12 (TLS 1.1 and 1.2) by default once we start using .NET 4.5+.
+            SslProtocols sslProtocols = SslProtocols.Tls)
+        {
+            if (!certificate.HasPrivateKey)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, "Your server-certificate needs to have a private key");
+            }
+
+            this.port = port;
+            this.clientTimeout = clientTimeout;
+            this.serverCertificate = certificate;
+            this.useBufferedSockets = useBufferedSockets;
+            this.clientCertValidator = clientCertValidator;
+            this.localCertificateSelectionCallback = localCertificateSelectionCallback;
+            this.sslProtocols = sslProtocols;
+            try
+            {
+                // Create server socket
+                this.server = TSocketVersionizer.CreateTcpListener(this.port);
+                this.server.Server.NoDelay = true;
+            }
+            catch (Exception ex)
+            {
+                server = null;
+                throw new TTransportException("Could not create ServerSocket on port " + this.port + ".", ex);
+            }
+        }
+
+        /// <summary>
+        /// Starts the server.
+        /// </summary>
+        public override void Listen()
+        {
+            // Make sure accept is not blocking
+            if (this.server != null)
+            {
+                try
+                {
+                    this.server.Start();
+                }
+                catch (SocketException sx)
+                {
+                    throw new TTransportException("Could not accept on listening socket: " + sx.Message, sx);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Callback for Accept Implementation
+        /// </summary>
+        /// <returns>
+        /// TTransport-object.
+        /// </returns>
+        protected override TTransport AcceptImpl()
+        {
+            if (this.server == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket.");
+            }
+
+            try
+            {
+                TcpClient client = this.server.AcceptTcpClient();
+                client.SendTimeout = client.ReceiveTimeout = this.clientTimeout;
+
+                //wrap the client in an SSL Socket passing in the SSL cert
+                TTLSSocket socket = new TTLSSocket(
+                    client,
+                    this.serverCertificate,
+                    true,
+                    this.clientCertValidator,
+                    this.localCertificateSelectionCallback,
+                    this.sslProtocols);
+
+                socket.setupTLS();
+
+                if (useBufferedSockets)
+                {
+                    TBufferedTransport trans = new TBufferedTransport(socket);
+                    return trans;
+                }
+                else
+                {
+                    return socket;
+                }
+
+            }
+            catch (Exception ex)
+            {
+                throw new TTransportException(ex.ToString(), ex);
+            }
+        }
+
+        /// <summary>
+        /// Stops the Server
+        /// </summary>
+        public override void Close()
+        {
+            if (this.server != null)
+            {
+                try
+                {
+                    this.server.Stop();
+                }
+                catch (Exception ex)
+                {
+                    throw new TTransportException("WARNING: Could not close server socket: " + ex, ex);
+                }
+                this.server = null;
+            }
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TTLSSocket.cs b/lib/csharp/src/Transport/TTLSSocket.cs
new file mode 100644
index 0000000..06286dc
--- /dev/null
+++ b/lib/csharp/src/Transport/TTLSSocket.cs
@@ -0,0 +1,445 @@
+/**
+ * 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;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Thrift.Transport
+{
+    /// <summary>
+    /// SSL Socket Wrapper class
+    /// </summary>
+    public class TTLSSocket : TStreamTransport
+    {
+        /// <summary>
+        /// Internal TCP Client
+        /// </summary>
+        private TcpClient client;
+
+        /// <summary>
+        /// The host
+        /// </summary>
+        private string host;
+
+        /// <summary>
+        /// The port
+        /// </summary>
+        private int port;
+
+        /// <summary>
+        /// The timeout for the connection
+        /// </summary>
+        private int timeout;
+
+        /// <summary>
+        /// Internal SSL Stream for IO
+        /// </summary>
+        private SslStream secureStream;
+
+        /// <summary>
+        /// Defines wheter or not this socket is a server socket<br/>
+        /// This is used for the TLS-authentication
+        /// </summary>
+        private bool isServer;
+
+        /// <summary>
+        /// The certificate
+        /// </summary>
+        private X509Certificate certificate;
+
+        /// <summary>
+        /// User defined certificate validator.
+        /// </summary>
+        private RemoteCertificateValidationCallback certValidator;
+
+        /// <summary>
+        /// The function to determine which certificate to use.
+        /// </summary>
+        private LocalCertificateSelectionCallback localCertificateSelectionCallback;
+
+        /// <summary>
+        /// The SslProtocols value that represents the protocol used for authentication.SSL protocols to be used.
+        /// </summary>
+        private readonly SslProtocols sslProtocols;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSSocket"/> class.
+        /// </summary>
+        /// <param name="client">An already created TCP-client</param>
+        /// <param name="certificate">The certificate.</param>
+        /// <param name="isServer">if set to <c>true</c> [is server].</param>
+        /// <param name="certValidator">User defined cert validator.</param>
+        /// <param name="localCertificateSelectionCallback">The callback to select which certificate to use.</param>
+        /// <param name="sslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
+        public TTLSSocket(
+            TcpClient client,
+            X509Certificate certificate,
+            bool isServer = false,
+            RemoteCertificateValidationCallback certValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            // TODO: Enable Tls11 and Tls12 (TLS 1.1 and 1.2) by default once we start using .NET 4.5+.
+            SslProtocols sslProtocols = SslProtocols.Tls)
+        {
+            this.client = client;
+            this.certificate = certificate;
+            this.certValidator = certValidator;
+            this.localCertificateSelectionCallback = localCertificateSelectionCallback;
+            this.sslProtocols = sslProtocols;
+            this.isServer = isServer;
+            if (isServer && certificate == null)
+            {
+                throw new ArgumentException("TTLSSocket needs certificate to be used for server", "certificate");
+            }
+
+            if (IsOpen)
+            {
+                base.inputStream = client.GetStream();
+                base.outputStream = client.GetStream();
+            }
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSSocket"/> class.
+        /// </summary>
+        /// <param name="host">The host, where the socket should connect to.</param>
+        /// <param name="port">The port.</param>
+        /// <param name="certificatePath">The certificate path.</param>
+        /// <param name="certValidator">User defined cert validator.</param>
+        /// <param name="localCertificateSelectionCallback">The callback to select which certificate to use.</param>
+        /// <param name="sslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
+        public TTLSSocket(
+            string host,
+            int port,
+            string certificatePath,
+            RemoteCertificateValidationCallback certValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            SslProtocols sslProtocols = SslProtocols.Tls)
+            : this(host, port, 0, X509Certificate.CreateFromCertFile(certificatePath), certValidator, localCertificateSelectionCallback, sslProtocols)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSSocket"/> class.
+        /// </summary>
+        /// <param name="host">The host, where the socket should connect to.</param>
+        /// <param name="port">The port.</param>
+        /// <param name="certificate">The certificate.</param>
+        /// <param name="certValidator">User defined cert validator.</param>
+        /// <param name="localCertificateSelectionCallback">The callback to select which certificate to use.</param>
+        /// <param name="sslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
+        public TTLSSocket(
+            string host,
+            int port,
+            X509Certificate certificate = null,
+            RemoteCertificateValidationCallback certValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            SslProtocols sslProtocols = SslProtocols.Tls)
+            : this(host, port, 0, certificate, certValidator, localCertificateSelectionCallback, sslProtocols)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSSocket"/> class.
+        /// </summary>
+        /// <param name="host">The host, where the socket should connect to.</param>
+        /// <param name="port">The port.</param>
+        /// <param name="timeout">The timeout.</param>
+        /// <param name="certificate">The certificate.</param>
+        /// <param name="certValidator">User defined cert validator.</param>
+        /// <param name="localCertificateSelectionCallback">The callback to select which certificate to use.</param>
+        /// <param name="sslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
+        public TTLSSocket(
+            string host,
+            int port,
+            int timeout,
+            X509Certificate certificate,
+            RemoteCertificateValidationCallback certValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            SslProtocols sslProtocols = SslProtocols.Tls)
+        {
+            this.host = host;
+            this.port = port;
+            this.timeout = timeout;
+            this.certificate = certificate;
+            this.certValidator = certValidator;
+            this.localCertificateSelectionCallback = localCertificateSelectionCallback;
+            this.sslProtocols = sslProtocols;
+
+            InitSocket();
+        }
+
+        /// <summary>
+        /// Creates the TcpClient and sets the timeouts
+        /// </summary>
+        private void InitSocket()
+        {
+            client = TSocketVersionizer.CreateTcpClient();
+            client.ReceiveTimeout = client.SendTimeout = timeout;
+            client.Client.NoDelay = true;
+        }
+
+        /// <summary>
+        /// Sets Send / Recv Timeout for IO
+        /// </summary>
+        public int Timeout
+        {
+            set
+            {
+                this.client.ReceiveTimeout = this.client.SendTimeout = this.timeout = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets the TCP client.
+        /// </summary>
+        public TcpClient TcpClient
+        {
+            get
+            {
+                return client;
+            }
+        }
+
+        /// <summary>
+        /// Gets the host.
+        /// </summary>
+        public string Host
+        {
+            get
+            {
+                return host;
+            }
+        }
+
+        /// <summary>
+        /// Gets the port.
+        /// </summary>
+        public int Port
+        {
+            get
+            {
+                return port;
+            }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether TCP Client is Cpen
+        /// </summary>
+        public override bool IsOpen
+        {
+            get
+            {
+                if (this.client == null)
+                {
+                    return false;
+                }
+
+                return this.client.Connected;
+            }
+        }
+
+        /// <summary>
+        /// Validates the certificates!<br/>
+        /// </summary>
+        /// <param name="sender">The sender-object.</param>
+        /// <param name="certificate">The used certificate.</param>
+        /// <param name="chain">The certificate chain.</param>
+        /// <param name="sslValidationErrors">An enum, which lists all the errors from the .NET certificate check.</param>
+        /// <returns></returns>
+        private bool DefaultCertificateValidator(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslValidationErrors)
+        {
+            return (sslValidationErrors == SslPolicyErrors.None);
+        }
+
+        /// <summary>
+        /// Connects to the host and starts the routine, which sets up the TLS
+        /// </summary>
+        public override void Open()
+        {
+            if (IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
+            }
+
+            if (string.IsNullOrEmpty(host))
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
+            }
+
+            if (port <= 0)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
+            }
+
+            if (client == null)
+            {
+                InitSocket();
+            }
+
+            if (timeout == 0)            // no timeout -> infinite
+            {
+                client.Connect(host, port);
+            }
+            else                        // we have a timeout -> use it
+            {
+                ConnectHelper hlp = new ConnectHelper(client);
+                IAsyncResult asyncres = client.BeginConnect(host, port, new AsyncCallback(ConnectCallback), hlp);
+                bool bConnected = asyncres.AsyncWaitHandle.WaitOne(timeout) && client.Connected;
+                if (!bConnected)
+                {
+                    lock (hlp.Mutex)
+                    {
+                        if (hlp.CallbackDone)
+                        {
+                            asyncres.AsyncWaitHandle.Close();
+                            client.Close();
+                        }
+                        else
+                        {
+                            hlp.DoCleanup = true;
+                            client = null;
+                        }
+                    }
+                    throw new TTransportException(TTransportException.ExceptionType.TimedOut, "Connect timed out");
+                }
+            }
+
+            setupTLS();
+        }
+
+        /// <summary>
+        /// Creates a TLS-stream and lays it over the existing socket
+        /// </summary>
+        public void setupTLS()
+        {
+            RemoteCertificateValidationCallback validator = this.certValidator ?? DefaultCertificateValidator;
+
+            if (this.localCertificateSelectionCallback != null)
+            {
+                this.secureStream = new SslStream(
+                    this.client.GetStream(),
+                    false,
+                    validator,
+                    this.localCertificateSelectionCallback
+                );
+            }
+            else
+            {
+                this.secureStream = new SslStream(
+                    this.client.GetStream(),
+                    false,
+                    validator
+                );
+            }
+
+            try
+            {
+                if (isServer)
+                {
+                    // Server authentication
+                    this.secureStream.AuthenticateAsServer(this.certificate, this.certValidator != null, sslProtocols, true);
+                }
+                else
+                {
+                    // Client authentication
+                    X509CertificateCollection certs = certificate != null ? new X509CertificateCollection { certificate } : new X509CertificateCollection();
+                    this.secureStream.AuthenticateAsClient(host, certs, sslProtocols, true);
+                }
+            }
+            catch (Exception)
+            {
+                this.Close();
+                throw;
+            }
+
+            inputStream = this.secureStream;
+            outputStream = this.secureStream;
+        }
+        
+        static void ConnectCallback(IAsyncResult asyncres)
+        {
+            ConnectHelper hlp = asyncres.AsyncState as ConnectHelper;
+            lock (hlp.Mutex)
+            {
+                hlp.CallbackDone = true;
+
+                try
+                {
+                    if (hlp.Client.Client != null)
+                        hlp.Client.EndConnect(asyncres);
+                }
+                catch (Exception)
+                {
+                    // catch that away
+                }
+
+                if (hlp.DoCleanup)
+                {
+                    try
+                    {
+                        asyncres.AsyncWaitHandle.Close();
+                    }
+                    catch (Exception) { }
+
+                    try
+                    {
+                        if (hlp.Client is IDisposable)
+                            ((IDisposable)hlp.Client).Dispose();
+                    }
+                    catch (Exception) { }
+                    hlp.Client = null;
+                }
+            }
+        }
+
+        private class ConnectHelper
+        {
+            public object Mutex = new object();
+            public bool DoCleanup = false;
+            public bool CallbackDone = false;
+            public TcpClient Client;
+            public ConnectHelper(TcpClient client)
+            {
+                Client = client;
+            }
+        }
+
+        /// <summary>
+        /// Closes the SSL Socket
+        /// </summary>
+        public override void Close()
+        {
+            base.Close();
+            if (this.client != null)
+            {
+                this.client.Close();
+                this.client = null;
+            }
+
+            if (this.secureStream != null)
+            {
+                this.secureStream.Close();
+                this.secureStream = null;
+            }
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TTransport.cs b/lib/csharp/src/Transport/TTransport.cs
new file mode 100644
index 0000000..5e4ac22
--- /dev/null
+++ b/lib/csharp/src/Transport/TTransport.cs
@@ -0,0 +1,146 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.IO;
+
+namespace Thrift.Transport
+{
+    public abstract class TTransport : IDisposable
+    {
+        public abstract bool IsOpen
+        {
+            get;
+        }
+
+        private byte[] _peekBuffer = new byte[1];
+        private bool _hasPeekByte;
+
+        public bool Peek()
+        {
+            //If we already have a byte read but not consumed, do nothing.
+            if (_hasPeekByte)
+                return true;
+
+            //If transport closed we can't peek.
+            if (!IsOpen)
+                return false;
+
+            //Try to read one byte. If succeeds we will need to store it for the next read.
+            try
+            {
+                int bytes = Read(_peekBuffer, 0, 1);
+                if (bytes == 0)
+                    return false;
+            }
+            catch (IOException)
+            {
+                return false;
+            }
+
+            _hasPeekByte = true;
+            return true;
+        }
+
+        public abstract void Open();
+
+        public abstract void Close();
+
+        protected static void ValidateBufferArgs(byte[] buf, int off, int len)
+        {
+            if (buf == null)
+                throw new ArgumentNullException("buf");
+            if (off < 0)
+                throw new ArgumentOutOfRangeException("Buffer offset is smaller than zero.");
+            if (len < 0)
+                throw new ArgumentOutOfRangeException("Buffer length is smaller than zero.");
+            if (off + len > buf.Length)
+                throw new ArgumentOutOfRangeException("Not enough data.");
+        }
+
+        public abstract int Read(byte[] buf, int off, int len);
+
+        public int ReadAll(byte[] buf, int off, int len)
+        {
+            ValidateBufferArgs(buf, off, len);
+            int got = 0;
+
+            //If we previously peeked a byte, we need to use that first.
+            if (_hasPeekByte)
+            {
+                buf[off + got++] = _peekBuffer[0];
+                _hasPeekByte = false;
+            }
+
+            while (got < len)
+            {
+                int ret = Read(buf, off + got, len - got);
+                if (ret <= 0)
+                {
+                    throw new TTransportException(
+                        TTransportException.ExceptionType.EndOfFile,
+                        "Cannot read, Remote side has closed");
+                }
+                got += ret;
+            }
+            return got;
+        }
+
+        public virtual void Write(byte[] buf)
+        {
+            Write(buf, 0, buf.Length);
+        }
+
+        public abstract void Write(byte[] buf, int off, int len);
+
+        public virtual void Flush()
+        {
+        }
+
+        public virtual IAsyncResult BeginFlush(AsyncCallback callback, object state)
+        {
+            throw new TTransportException(
+                TTransportException.ExceptionType.Unknown,
+                "Asynchronous operations are not supported by this transport.");
+        }
+
+        public virtual void EndFlush(IAsyncResult asyncResult)
+        {
+            throw new TTransportException(
+                TTransportException.ExceptionType.Unknown,
+                "Asynchronous operations are not supported by this transport.");
+        }
+
+        #region " IDisposable Support "
+        // IDisposable
+        protected abstract void Dispose(bool disposing);
+
+        public void Dispose()
+        {
+            // Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+        #endregion
+    }
+}
diff --git a/lib/csharp/src/Transport/TTransportException.cs b/lib/csharp/src/Transport/TTransportException.cs
new file mode 100644
index 0000000..7f6cc18
--- /dev/null
+++ b/lib/csharp/src/Transport/TTransportException.cs
@@ -0,0 +1,69 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift.Transport
+{
+    public class TTransportException : TException
+    {
+        protected ExceptionType type;
+
+        public TTransportException()
+            : base()
+        {
+        }
+
+        public TTransportException(ExceptionType type)
+            : this()
+        {
+            this.type = type;
+        }
+
+        public TTransportException(ExceptionType type, string message, Exception inner = null)
+            : base(message, inner)
+        {
+            this.type = type;
+        }
+
+        public TTransportException(string message, Exception inner = null)
+            : base(message, inner)
+        {
+        }
+
+        public ExceptionType Type
+        {
+            get { return type; }
+        }
+
+        public enum ExceptionType
+        {
+            Unknown,
+            NotOpen,
+            AlreadyOpen,
+            TimedOut,
+            EndOfFile,
+            Interrupted
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TTransportFactory.cs b/lib/csharp/src/Transport/TTransportFactory.cs
new file mode 100644
index 0000000..47a0c62
--- /dev/null
+++ b/lib/csharp/src/Transport/TTransportFactory.cs
@@ -0,0 +1,42 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift.Transport
+{
+    /// <summary>
+    /// From Mark Slee &amp; Aditya Agarwal of Facebook:
+    /// Factory class used to create wrapped instance of Transports.
+    /// This is used primarily in servers, which get Transports from
+    /// a ServerTransport and then may want to mutate them (i.e. create
+    /// a BufferedTransport from the underlying base transport)
+    /// </summary>
+    public class TTransportFactory
+    {
+        public virtual TTransport GetTransport(TTransport trans)
+        {
+            return trans;
+        }
+    }
+}
diff --git a/lib/csharp/src/thrift.snk b/lib/csharp/src/thrift.snk
new file mode 100644
index 0000000..97bc581
--- /dev/null
+++ b/lib/csharp/src/thrift.snk
Binary files differ
diff --git a/lib/csharp/test/JSON/JSONTest.csproj b/lib/csharp/test/JSON/JSONTest.csproj
new file mode 100644
index 0000000..f07d43e
--- /dev/null
+++ b/lib/csharp/test/JSON/JSONTest.csproj
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{E37A0034-DCBF-4886-A0DA-25A03D12D975}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>JSONTest</RootNamespace>
+    <AssemblyName>JSONTest</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkProfile>
+    </TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Thrift.csproj">
+      <Project>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</Project>
+      <Name>Thrift</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/lib/csharp/test/JSON/Program.cs b/lib/csharp/test/JSON/Program.cs
new file mode 100644
index 0000000..f61388a
--- /dev/null
+++ b/lib/csharp/test/JSON/Program.cs
@@ -0,0 +1,95 @@
+/**
+ * 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;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Thrift.Protocol;
+using Thrift.Transport;
+
+namespace JSONTest
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            TestThrift2365();  // JSON binary decodes too much data
+            TestThrift2336();  // hex encoding using \uXXXX where 0xXXXX > 0xFF
+            TestThrift3403(); // JSON escaped unicode surrogate pair support.
+        }
+
+
+        public static void TestThrift2365()
+        {
+            var rnd = new Random();
+            for (var len = 0; len < 10; ++len)
+            {
+                byte[] dataWritten = new byte[len];
+                rnd.NextBytes(dataWritten);
+
+                Stream stm = new MemoryStream();
+                TTransport trans = new TStreamTransport(null, stm);
+                TProtocol prot = new TJSONProtocol(trans);
+                prot.WriteBinary(dataWritten);
+
+                stm.Position = 0;
+                trans = new TStreamTransport(stm, null);
+                prot = new TJSONProtocol(trans);
+                byte[] dataRead = prot.ReadBinary();
+
+                Debug.Assert(dataRead.Length == dataWritten.Length);
+                for (var i = 0; i < dataRead.Length; ++i)
+                    Debug.Assert(dataRead[i] == dataWritten[i]);
+            }
+        }
+
+
+        public static void TestThrift2336()
+        {
+            const string RUSSIAN_TEXT = "\u0420\u0443\u0441\u0441\u043a\u043e\u0435 \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435";
+            const string RUSSIAN_JSON = "\"\\u0420\\u0443\\u0441\\u0441\\u043a\\u043e\\u0435 \\u041d\\u0430\\u0437\\u0432\\u0430\\u043d\\u0438\\u0435\"";
+
+            // prepare buffer with JSON data
+            byte[] rawBytes = new byte[RUSSIAN_JSON.Length];
+            for (var i = 0; i < RUSSIAN_JSON.Length; ++i)
+                rawBytes[i] = (byte)(RUSSIAN_JSON[i] & (char)0xFF);  // only low bytes
+
+            // parse and check
+            var stm = new MemoryStream(rawBytes);
+            var trans = new TStreamTransport(stm, null);
+            var prot = new TJSONProtocol(trans);
+            Debug.Assert(prot.ReadString() == RUSSIAN_TEXT, "reading JSON with hex-encoded chars > 8 bit");
+        }
+
+        public static void TestThrift3403()
+        {
+            string GCLEF_TEXT = "\ud834\udd1e";
+            const string GCLEF_JSON = "\"\\ud834\\udd1e\"";
+
+            // parse and check
+            var stm = new MemoryStream(Encoding.UTF8.GetBytes(GCLEF_JSON));
+            var trans = new TStreamTransport(stm, null);
+            var prot = new TJSONProtocol(trans);
+            Debug.Assert(prot.ReadString() == GCLEF_TEXT, "reading JSON with surrogate pair hex-encoded chars");
+        }
+    }
+}
diff --git a/lib/csharp/test/JSON/Properties/AssemblyInfo.cs b/lib/csharp/test/JSON/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..fdff4a1
--- /dev/null
+++ b/lib/csharp/test/JSON/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die mit einer Assembly verknüpft sind.
+[assembly: AssemblyTitle("JSONTest")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
+// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
+// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("2b2e7d56-3e65-4368-92d7-e34d56b7105e")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+//      Hauptversion
+//      Nebenversion
+//      Buildnummer
+//      Revision
+//
+// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
+// übernehmen, indem Sie "*" eingeben:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/lib/csharp/test/JSON/app.config b/lib/csharp/test/JSON/app.config
new file mode 100644
index 0000000..9c1919d
--- /dev/null
+++ b/lib/csharp/test/JSON/app.config
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<configuration>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
diff --git a/lib/csharp/test/Multiplex/Client/Multiplex.Test.Client.cs b/lib/csharp/test/Multiplex/Client/Multiplex.Test.Client.cs
new file mode 100644
index 0000000..c810a08
--- /dev/null
+++ b/lib/csharp/test/Multiplex/Client/Multiplex.Test.Client.cs
@@ -0,0 +1,82 @@
+/*
+ * 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;
+using System.Collections.Generic;
+using Thrift.Collections;
+using Thrift.Transport;
+using Thrift.Protocol;
+using Thrift.Server;
+using Thrift;
+using Test.Multiplex;
+
+namespace Test.Multiplex.Client
+{
+    public class TestClient
+    {
+        static void Execute(int port)
+        {
+            try
+            {
+                TTransport trans;
+                trans = new TSocket("localhost", port);
+                trans = new TFramedTransport(trans);
+                trans.Open();
+
+                TProtocol Protocol = new TBinaryProtocol(trans, true, true);
+
+                TMultiplexedProtocol multiplex;
+
+                multiplex = new TMultiplexedProtocol(Protocol, Constants.NAME_BENCHMARKSERVICE);
+                BenchmarkService.Iface bench = new BenchmarkService.Client(multiplex);
+
+                multiplex = new TMultiplexedProtocol(Protocol, Constants.NAME_AGGR);
+                Aggr.Iface aggr = new Aggr.Client(multiplex);
+
+                for (sbyte i = 1; 10 >= i; ++i)
+                {
+                    aggr.addValue(bench.fibonacci(i));
+                }
+
+                foreach (int k in aggr.getValues())
+                {
+                    Console.Write(k.ToString() + " ");
+                    Console.WriteLine("");
+                }
+                trans.Close();
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine(e.Message);
+            }
+        }
+
+        static void Main(string[] args)
+        {
+            int port = 9090;
+            if (args.Length > 0)
+            {
+                port = ushort.Parse(args[0]);
+            }
+            Execute(port);
+            Console.WriteLine("done.");
+        }
+    }
+}
+
diff --git a/lib/csharp/test/Multiplex/Client/MultiplexClient.csproj b/lib/csharp/test/Multiplex/Client/MultiplexClient.csproj
new file mode 100644
index 0000000..551640b
--- /dev/null
+++ b/lib/csharp/test/Multiplex/Client/MultiplexClient.csproj
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{5E91DA17-E548-415F-8C9F-9E84EDF8EE06}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>MultiplexClient</RootNamespace>
+    <AssemblyName>MultiplexClient</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>0.14.0.0</ApplicationVersion>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\Multiplex.Test.Common.cs">
+      <Link>Multiplex.Test.Common.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\Aggr.cs" />
+    <Compile Include="..\gen-csharp\BenchmarkService.cs" />
+    <Compile Include="..\gen-csharp\Error.cs" />
+    <Compile Include="Multiplex.Test.Client.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\src\Thrift.csproj">
+      <Project>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</Project>
+      <Name>Thrift</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>rmdir /s /q "$(ProjectDir)gen-csharp"
+del /f /q "$(ProjectDir)ThriftImpl.dll"
+SET OUTPUT_DIR=$(ProjectDir)
+
+SET THRIFT_FILE=$(ProjectDir)\..\..\..\..\..\contrib\async-test\aggr.thrift
+for %25%25I in ("%25OUTPUT_DIR%25") do set SHORT_DIR=%25%25~fsI
+for %25%25I in ("%25THRIFT_FILE%25") do set THRIFT_SHORT=%25%25~fsI
+"$(ProjectDir)\..\..\..\..\..\compiler\cpp\thrift.exe" --gen csharp -o %25SHORT_DIR%25 %25THRIFT_SHORT%25
+
+SET THRIFT_FILE=$(ProjectDir)\..\..\..\..\..\lib\rb\benchmark\Benchmark.thrift
+for %25%25I in ("%25OUTPUT_DIR%25") do set SHORT_DIR=%25%25~fsI
+for %25%25I in ("%25THRIFT_FILE%25") do set THRIFT_SHORT=%25%25~fsI
+"$(ProjectDir)\..\..\..\..\..\compiler\cpp\thrift.exe" --gen csharp -o %25SHORT_DIR%25 %25THRIFT_SHORT%25
+
+</PreBuildEvent>
+  </PropertyGroup>
+</Project>
diff --git a/lib/csharp/test/Multiplex/Client/Properties/AssemblyInfo.cs b/lib/csharp/test/Multiplex/Client/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..ce6692f
--- /dev/null
+++ b/lib/csharp/test/Multiplex/Client/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+ * 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("MultiplexClient")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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("66FC61E5-420B-4b56-8012-D6D6CE22537F")]
+
+// 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.14.0.0")]
+[assembly: AssemblyFileVersion("0.14.0.0")]
diff --git a/lib/csharp/test/Multiplex/Makefile.am b/lib/csharp/test/Multiplex/Makefile.am
new file mode 100644
index 0000000..9c1f1b8
--- /dev/null
+++ b/lib/csharp/test/Multiplex/Makefile.am
@@ -0,0 +1,63 @@
+#
+# 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.
+#
+
+GENERATED = \
+	gen-csharp/Aggr.cs \
+	gen-csharp/BenchmarkService.cs \
+	gen-csharp/Error.cs
+
+BUILT_SOURCES = $(GENERATED)
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+gen-csharp/Aggr.cs: $(top_srcdir)/contrib/async-test/aggr.thrift
+	$(THRIFT) --gen csharp $<
+
+gen-csharp/BenchmarkService.cs gen-csharp/Error.cs: $(top_srcdir)/lib/rb/benchmark/Benchmark.thrift
+	$(THRIFT) --gen csharp $<
+
+ThriftImpl.dll: Multiplex.Test.Common.cs $(GENERATED) ../../Thrift.dll
+	$(CSC) $(CSC_DEFINES) -t:library -out:./ThriftImpl.dll -reference:../../Thrift.dll $(GENERATED) $<
+
+MultiplexClient.exe: Client/Multiplex.Test.Client.cs ThriftImpl.dll
+	$(CSC) $(CSC_DEFINES) -out:$@ -reference:../../Thrift.dll -reference:ThriftImpl.dll $<
+
+MultiplexServer.exe: Server/Multiplex.Test.Server.cs ThriftImpl.dll
+	$(CSC) $(CSC_DEFINES) -out:$@ -reference:../../Thrift.dll -reference:ThriftImpl.dll $<
+
+CLEANFILES = \
+	MultiplexClient.exe \
+	MultiplexServer.exe \
+	ThriftImpl.dll
+
+DISTCLEANFILES = \
+	Makefile.in
+
+clean-local:
+	$(RM) -rf gen-csharp
+
+dist-hook:
+	$(RM) -r $(distdir)/gen-csharp/
+
+TESTPORT = 9501
+check-local: MultiplexServer.exe MultiplexClient.exe
+	echo $(TESTPORT)
+	MONO_PATH=../../ timeout 10 mono MultiplexServer.exe $(TESTPORT) &
+	sleep 1
+	MONO_PATH=../../ mono MultiplexClient.exe $(TESTPORT)
diff --git a/lib/csharp/test/Multiplex/Multiplex.Test.Common.cs b/lib/csharp/test/Multiplex/Multiplex.Test.Common.cs
new file mode 100644
index 0000000..a687852
--- /dev/null
+++ b/lib/csharp/test/Multiplex/Multiplex.Test.Common.cs
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+using System;
+using System.Collections.Generic;
+using Thrift.Collections;
+using Thrift.Transport;
+using Thrift.Protocol;
+using Thrift.Server;
+
+namespace Test.Multiplex
+{
+    public class Constants
+    {
+        public const string NAME_BENCHMARKSERVICE = "BenchmarkService";
+        public const string NAME_AGGR             = "Aggr";
+    }
+}
+
+
diff --git a/lib/csharp/test/Multiplex/Server/Multiplex.Test.Server.cs b/lib/csharp/test/Multiplex/Server/Multiplex.Test.Server.cs
new file mode 100644
index 0000000..9786189
--- /dev/null
+++ b/lib/csharp/test/Multiplex/Server/Multiplex.Test.Server.cs
@@ -0,0 +1,107 @@
+/*
+ * 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;
+using System.Collections.Generic;
+using Thrift.Collections;
+using Thrift.Transport;
+using Thrift.Protocol;
+using Thrift.Server;
+using Thrift;
+using Test.Multiplex;
+
+namespace Test.Multiplex.Server
+{
+    public class TestServer
+    {
+        class BenchmarkServiceImpl : BenchmarkService.Iface
+        {
+            public int fibonacci(sbyte n)
+            {
+                int prev, next, result;
+                prev   = 0;
+                result = 1;
+                while (n > 0)
+                {
+                    next   = result + prev;
+                    prev   = result;
+                    result = next;
+                    --n;
+                }
+                return result;
+            }
+        }
+
+        class AggrServiceImpl : Aggr.Iface
+        {
+            List<int> values = new List<int>();
+
+            public void addValue(int value)
+            {
+                values.Add(value);
+            }
+
+            public List<int> getValues()
+            {
+                return values;
+            }
+        }
+
+        static void Execute(int port)
+        {
+            try
+            {
+                // create protocol factory, default to BinaryProtocol
+                TProtocolFactory ProtocolFactory = new TBinaryProtocol.Factory(true,true);
+                TServerTransport servertrans = new TServerSocket(port, 0, false);
+                TTransportFactory TransportFactory = new TFramedTransport.Factory();
+
+                BenchmarkService.Iface benchHandler = new BenchmarkServiceImpl();
+                TProcessor benchProcessor = new BenchmarkService.Processor(benchHandler);
+
+                Aggr.Iface aggrHandler = new AggrServiceImpl();
+                TProcessor aggrProcessor = new Aggr.Processor(aggrHandler);
+
+                TMultiplexedProcessor multiplex = new TMultiplexedProcessor();
+                multiplex.RegisterProcessor(Constants.NAME_BENCHMARKSERVICE, benchProcessor);
+                multiplex.RegisterProcessor(Constants.NAME_AGGR, aggrProcessor);
+
+                TServer ServerEngine = new TSimpleServer(multiplex, servertrans, TransportFactory, ProtocolFactory);
+
+                Console.WriteLine("Starting the server ...");
+                ServerEngine.Serve();
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine(e.Message);
+            }
+        }
+
+        static void Main(string[] args)
+        {
+            int port = 9090;
+            if (args.Length > 0)
+            {
+                port = ushort.Parse(args[0]);
+            }
+            Execute(port);
+        }
+    }
+}
+
diff --git a/lib/csharp/test/Multiplex/Server/MultiplexServer.csproj b/lib/csharp/test/Multiplex/Server/MultiplexServer.csproj
new file mode 100644
index 0000000..771ee12
--- /dev/null
+++ b/lib/csharp/test/Multiplex/Server/MultiplexServer.csproj
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{D592BDF3-0DCE-48FB-890F-E4AE1D9CE7CD}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>MultiplexServer</RootNamespace>
+    <AssemblyName>MultiplexServer</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>0.14.0.0</ApplicationVersion>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\Multiplex.Test.Common.cs">
+      <Link>Multiplex.Test.Common.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\Aggr.cs" />
+    <Compile Include="..\gen-csharp\BenchmarkService.cs" />
+    <Compile Include="..\gen-csharp\Error.cs" />
+    <Compile Include="Multiplex.Test.Server.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\src\Thrift.csproj">
+      <Project>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</Project>
+      <Name>Thrift</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>rmdir /s /q "$(ProjectDir)gen-csharp"
+del /f /q "$(ProjectDir)ThriftImpl.dll"
+SET OUTPUT_DIR=$(ProjectDir)
+
+SET THRIFT_FILE=$(ProjectDir)\..\..\..\..\..\contrib\async-test\aggr.thrift
+for %25%25I in ("%25OUTPUT_DIR%25") do set SHORT_DIR=%25%25~fsI
+for %25%25I in ("%25THRIFT_FILE%25") do set THRIFT_SHORT=%25%25~fsI
+"$(ProjectDir)\..\..\..\..\..\compiler\cpp\thrift.exe" --gen csharp -o %25SHORT_DIR%25 %25THRIFT_SHORT%25
+
+SET THRIFT_FILE=$(ProjectDir)\..\..\..\..\..\lib\rb\benchmark\Benchmark.thrift
+for %25%25I in ("%25OUTPUT_DIR%25") do set SHORT_DIR=%25%25~fsI
+for %25%25I in ("%25THRIFT_FILE%25") do set THRIFT_SHORT=%25%25~fsI
+"$(ProjectDir)\..\..\..\..\..\compiler\cpp\thrift.exe" --gen csharp -o %25SHORT_DIR%25 %25THRIFT_SHORT%25
+
+</PreBuildEvent>
+  </PropertyGroup>
+</Project>
diff --git a/lib/csharp/test/Multiplex/Server/Properties/AssemblyInfo.cs b/lib/csharp/test/Multiplex/Server/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..50b11af
--- /dev/null
+++ b/lib/csharp/test/Multiplex/Server/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+ * 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("MultiplexServer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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("F2F436C1-3D4F-411a-ADC3-B98848476A8E")]
+
+// 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.14.0.0")]
+[assembly: AssemblyFileVersion("0.14.0.0")]
diff --git a/lib/csharp/test/ThriftMVCTest/App_Start/FilterConfig.cs b/lib/csharp/test/ThriftMVCTest/App_Start/FilterConfig.cs
new file mode 100644
index 0000000..855184f
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/App_Start/FilterConfig.cs
@@ -0,0 +1,31 @@
+/**
+ * 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.Web.Mvc;
+
+namespace ThriftMVCTest
+{
+    public static class FilterConfig
+    {
+        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
+        {
+            filters.Add(new HandleErrorAttribute());
+        }
+    }
+}
diff --git a/lib/csharp/test/ThriftMVCTest/App_Start/RouteConfig.cs b/lib/csharp/test/ThriftMVCTest/App_Start/RouteConfig.cs
new file mode 100644
index 0000000..b4b6023
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/App_Start/RouteConfig.cs
@@ -0,0 +1,39 @@
+/**
+ * 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.Web.Mvc;
+using System.Web.Routing;
+
+namespace ThriftMVCTest
+{
+    public static class RouteConfig
+    {
+        public static void RegisterRoutes(RouteCollection routes)
+        {
+            routes.IgnoreRoute("{resource}.thrift");
+            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
+
+            routes.MapRoute(
+                name: "Default",
+                url: "{controller}/{action}/{id}",
+                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
+            );
+        }
+    }
+}
diff --git a/lib/csharp/test/ThriftMVCTest/AsyncHttpHandler.cs b/lib/csharp/test/ThriftMVCTest/AsyncHttpHandler.cs
new file mode 100644
index 0000000..7f26184
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/AsyncHttpHandler.cs
@@ -0,0 +1,32 @@
+/**
+ * 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 Thrift.Transport;
+
+namespace ThriftMVCTest
+{
+    public class AsyncHttpHandler : THttpTaskAsyncHandler
+    {
+        public AsyncHttpHandler()
+            : base(
+                new Thrift.Test.SecondService.AsyncProcessor(new SecondServiceImpl()))
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs b/lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs
new file mode 100644
index 0000000..c9a1ec4
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs
@@ -0,0 +1,70 @@
+/**
+ * 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;
+using System.Threading.Tasks;
+using System.Web.Mvc;
+using Thrift.Protocol;
+using Thrift.Test;
+using Thrift.Transport;
+
+namespace ThriftMVCTest.Controllers
+{
+    public class HomeController : Controller
+    {
+        public ActionResult Index()
+        {
+            return View();
+        }
+
+        public async Task<ActionResult> TestThriftAsync()
+        {
+            var baseUri = new Uri(string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority,
+                Url.Content("~")));
+
+            SecondService.IAsync asyncService =
+                new SecondService.Client(new TBinaryProtocol(new THttpClient(new Uri(baseUri, "Async.thrift"))));
+
+            var result = await asyncService.secondtestStringAsync("TestString");
+            if (result != "testString(\"TestString\")")
+            {
+                throw new Exception("The wrong result was returned");
+            }
+
+            return RedirectToAction("Index");
+        }
+
+        public ActionResult TestThriftSync()
+        {
+            var baseUri = new Uri(string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority,
+                Url.Content("~")));
+
+            SecondService.ISync service =
+                new SecondService.Client(new TBinaryProtocol(new THttpClient(new Uri(baseUri, "Sync.thrift"))));
+
+            var result = service.secondtestString("TestString");
+            if (result != "testString(\"TestString\")")
+            {
+                throw new Exception("The wrong result was returned");
+            }
+
+            return RedirectToAction("Index");
+        }
+    }
+}
diff --git a/lib/csharp/test/ThriftMVCTest/Global.asax b/lib/csharp/test/ThriftMVCTest/Global.asax
new file mode 100644
index 0000000..7bb688c
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Global.asax
@@ -0,0 +1,19 @@
+<%@ Application Codebehind="Global.asax.cs" Inherits="ThriftMVCTest.MvcApplication" Language="C#" %>
+<!--
+  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.
+-->
diff --git a/lib/csharp/test/ThriftMVCTest/Global.asax.cs b/lib/csharp/test/ThriftMVCTest/Global.asax.cs
new file mode 100644
index 0000000..59731ef
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Global.asax.cs
@@ -0,0 +1,34 @@
+/**
+ * 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.Web.Mvc;
+using System.Web.Routing;
+
+namespace ThriftMVCTest
+{
+    public class MvcApplication : System.Web.HttpApplication
+    {
+        protected void Application_Start()
+        {
+            AreaRegistration.RegisterAllAreas();
+            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
+            RouteConfig.RegisterRoutes(RouteTable.Routes);
+        }
+    }
+}
diff --git a/lib/csharp/test/ThriftMVCTest/Properties/AssemblyInfo.cs b/lib/csharp/test/ThriftMVCTest/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..a87107c
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Properties/AssemblyInfo.cs
@@ -0,0 +1,53 @@
+/**
+ * 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.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("ThriftMVCTest")]
+[assembly: AssemblyDescription("A web project for testing the thrift ASP.NET features.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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("366f9bd0-3c0e-48aa-b2ca-61fd4a93e427")]
+
+// 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("0.14.0.0")]
+[assembly: AssemblyFileVersion("0.14.0.0")]
diff --git a/lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs b/lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs
new file mode 100644
index 0000000..fad301a
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs
@@ -0,0 +1,37 @@
+/**
+ * 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.Threading.Tasks;
+using Thrift.Test;
+
+namespace ThriftMVCTest
+{
+    public class SecondServiceImpl : SecondService.IAsync, SecondService.ISync
+    {
+        public Task<string> secondtestStringAsync(string thing)
+        {
+            return Task.FromResult(thing);
+        }
+
+        public string secondtestString(string thing)
+        {
+            return "testString(\"" + thing + "\")";
+        }
+    }
+}
diff --git a/lib/csharp/test/ThriftMVCTest/SyncHttpHandler.cs b/lib/csharp/test/ThriftMVCTest/SyncHttpHandler.cs
new file mode 100644
index 0000000..4fe2662
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/SyncHttpHandler.cs
@@ -0,0 +1,32 @@
+/**
+ * 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 Thrift.Transport;
+
+namespace ThriftMVCTest
+{
+    public class SyncHttpHandler : THttpHandler
+    {
+        public SyncHttpHandler()
+            : base(
+                new Thrift.Test.SecondService.Processor(new SecondServiceImpl()))
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/csharp/test/ThriftMVCTest/ThriftMVCTest.csproj b/lib/csharp/test/ThriftMVCTest/ThriftMVCTest.csproj
new file mode 100644
index 0000000..0eb969a
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/ThriftMVCTest.csproj
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>
+    </ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{891B4487-C7BA-427E-BBC8-4C596C229A10}</ProjectGuid>
+    <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ThriftMVCTest</RootNamespace>
+    <AssemblyName>ThriftMVCTest</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <MvcBuildViews>false</MvcBuildViews>
+    <UseIISExpress>true</UseIISExpress>
+    <IISExpressSSLPort />
+    <IISExpressAnonymousAuthentication />
+    <IISExpressWindowsAuthentication />
+    <IISExpressUseClassicPipelineMode />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Web.DynamicData" />
+    <Reference Include="System.Web.Entity" />
+    <Reference Include="System.Web.ApplicationServices" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Web" />
+    <Reference Include="System.Web.Extensions" />
+    <Reference Include="System.Web.Abstractions" />
+    <Reference Include="System.Web.Routing" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Web.Services" />
+    <Reference Include="System.EnterpriseServices" />
+    <Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Net.Http">
+    </Reference>
+    <Reference Include="System.Net.Http.WebRequest">
+    </Reference>
+    <Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
+    </Reference>
+    <Reference Include="ThriftImpl">
+      <HintPath>.\ThriftImpl.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="App_Start\FilterConfig.cs" />
+    <Compile Include="App_Start\RouteConfig.cs" />
+    <Compile Include="SyncHttpHandler.cs" />
+    <Compile Include="AsyncHttpHandler.cs" />
+    <Compile Include="Controllers\HomeController.cs" />
+    <Compile Include="Global.asax.cs">
+      <DependentUpon>Global.asax</DependentUpon>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SecondServiceImpl.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="favicon.ico" />
+    <Content Include="Global.asax" />
+    <Content Include="Web.config" />
+    <Content Include="Web.Debug.config">
+      <DependentUpon>Web.config</DependentUpon>
+    </Content>
+    <Content Include="Web.Release.config">
+      <DependentUpon>Web.config</DependentUpon>
+    </Content>
+    <Content Include="Views\Web.config" />
+    <Content Include="Views\_ViewStart.cshtml" />
+    <Content Include="Views\Shared\_Layout.cshtml" />
+    <Content Include="Views\Home\Index.cshtml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="App_Data\" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="packages.config">
+      <SubType>Designer</SubType>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Thrift.45.csproj">
+      <Project>{ebce35da-cf6a-42bc-a357-a9c09b534299}</Project>
+      <Name>Thrift.45</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
+  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
+  <Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
+    <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
+  </Target>
+  <ProjectExtensions>
+    <VisualStudio>
+      <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
+        <WebProjectProperties>
+          <UseIIS>True</UseIIS>
+          <AutoAssignPort>True</AutoAssignPort>
+          <DevelopmentServerPort>57482</DevelopmentServerPort>
+          <DevelopmentServerVPath>/</DevelopmentServerVPath>
+          <IISUrl>http://localhost:57482/</IISUrl>
+          <NTLMAuthentication>False</NTLMAuthentication>
+          <UseCustomServer>False</UseCustomServer>
+          <CustomServerUrl>
+          </CustomServerUrl>
+          <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
+        </WebProjectProperties>
+      </FlavorProperties>
+    </VisualStudio>
+  </ProjectExtensions>
+  <PropertyGroup>
+    <PreBuildEvent>rmdir /s /q "$(ProjectDir)gen-csharp"
+del /f /q "$(ProjectDir)ThriftImpl.dll"
+SET OUTPUT_DIR=$(ProjectDir)
+SET THRIFT_FILE=$(ProjectDir)\..\..\..\..\test\ThriftTest.thrift
+for %25%25I in ("%25OUTPUT_DIR%25") do set SHORT_DIR=%25%25~fsI
+for %25%25I in ("%25THRIFT_FILE%25") do set THRIFT_SHORT=%25%25~fsI
+"$(ProjectDir)\..\..\..\..\compiler\cpp\Debug\thrift.exe" --gen csharp:async=true -o %25SHORT_DIR%25 %25THRIFT_SHORT%25
+"$(MSBuildToolsPath)\Csc.exe" /t:library /out:"$(ProjectDir)ThriftImpl.dll" /recurse:"$(ProjectDir)gen-csharp"\* /reference:"$(ProjectDir)..\..\src\bin\Debug\Thrift45.dll"</PreBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target> -->
+</Project>
\ No newline at end of file
diff --git a/lib/csharp/test/ThriftMVCTest/Views/Home/Index.cshtml b/lib/csharp/test/ThriftMVCTest/Views/Home/Index.cshtml
new file mode 100644
index 0000000..f0ca7da
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Views/Home/Index.cshtml
@@ -0,0 +1,25 @@
+@*
+    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.
+*@
+
+@{
+    ViewBag.Title = "Home Page";
+}
+
+<p>@Html.ActionLink("Test Thrift Async Service", "TestThriftAsync")</p>
+<p>@Html.ActionLink("Test Thrift Sync Service", "TestThriftSync")</p>
diff --git a/lib/csharp/test/ThriftMVCTest/Views/Shared/_Layout.cshtml b/lib/csharp/test/ThriftMVCTest/Views/Shared/_Layout.cshtml
new file mode 100644
index 0000000..b41c99a
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Views/Shared/_Layout.cshtml
@@ -0,0 +1,30 @@
+@*
+    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.
+*@
+
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Thrift ASP.NET Test</title>
+</head>
+<body>
+    @RenderBody()
+</body>
+</html>
diff --git a/lib/csharp/test/ThriftMVCTest/Views/Web.config b/lib/csharp/test/ThriftMVCTest/Views/Web.config
new file mode 100644
index 0000000..3c21138
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Views/Web.config
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<configuration>
+  <configSections>
+    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
+      <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
+      <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
+    </sectionGroup>
+  </configSections>
+
+  <system.web.webPages.razor>
+    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
+    <pages pageBaseType="System.Web.Mvc.WebViewPage">
+      <namespaces>
+        <add namespace="System.Web.Mvc" />
+        <add namespace="System.Web.Mvc.Ajax" />
+        <add namespace="System.Web.Mvc.Html" />
+        <add namespace="System.Web.Optimization"/>
+        <add namespace="System.Web.Routing" />
+        <add namespace="ThriftMVCTest" />
+      </namespaces>
+    </pages>
+  </system.web.webPages.razor>
+
+  <appSettings>
+    <add key="webpages:Enabled" value="false" />
+  </appSettings>
+
+  <system.webServer>
+    <handlers>
+      <remove name="BlockViewHandler"/>
+      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
+    </handlers>
+  </system.webServer>
+
+  <system.web>
+    <compilation>
+      <assemblies>
+        <add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
+      </assemblies>
+    </compilation>
+  </system.web>
+</configuration>
diff --git a/lib/csharp/test/ThriftMVCTest/Views/_ViewStart.cshtml b/lib/csharp/test/ThriftMVCTest/Views/_ViewStart.cshtml
new file mode 100644
index 0000000..8cde2ee
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Views/_ViewStart.cshtml
@@ -0,0 +1,22 @@
+@*
+    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.
+*@
+
+@{
+    Layout = "~/Views/Shared/_Layout.cshtml";
+}
diff --git a/lib/csharp/test/ThriftMVCTest/Web.Debug.config b/lib/csharp/test/ThriftMVCTest/Web.Debug.config
new file mode 100644
index 0000000..45d56d8
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Web.Debug.config
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
+  <!--
+    In the example below, the "SetAttributes" transform will change the value of
+    "connectionString" to use "ReleaseSQLServer" only when the "Match" locator
+    finds an attribute "name" that has a value of "MyDB".
+
+    <connectionStrings>
+      <add name="MyDB"
+        connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
+        xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
+    </connectionStrings>
+  -->
+  <system.web>
+    <!--
+      In the example below, the "Replace" transform will replace the entire
+      <customErrors> section of your Web.config file.
+      Note that because there is only one customErrors section under the
+      <system.web> node, there is no need to use the "xdt:Locator" attribute.
+
+      <customErrors defaultRedirect="GenericError.htm"
+        mode="RemoteOnly" xdt:Transform="Replace">
+        <error statusCode="500" redirect="InternalError.htm"/>
+      </customErrors>
+    -->
+  </system.web>
+</configuration>
diff --git a/lib/csharp/test/ThriftMVCTest/Web.Release.config b/lib/csharp/test/ThriftMVCTest/Web.Release.config
new file mode 100644
index 0000000..157c340
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Web.Release.config
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
+  <!--
+    In the example below, the "SetAttributes" transform will change the value of
+    "connectionString" to use "ReleaseSQLServer" only when the "Match" locator
+    finds an attribute "name" that has a value of "MyDB".
+
+    <connectionStrings>
+      <add name="MyDB"
+        connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
+        xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
+    </connectionStrings>
+  -->
+  <system.web>
+    <compilation xdt:Transform="RemoveAttributes(debug)" />
+    <!--
+      In the example below, the "Replace" transform will replace the entire
+      <customErrors> section of your Web.config file.
+      Note that because there is only one customErrors section under the
+      <system.web> node, there is no need to use the "xdt:Locator" attribute.
+
+      <customErrors defaultRedirect="GenericError.htm"
+        mode="RemoteOnly" xdt:Transform="Replace">
+        <error statusCode="500" redirect="InternalError.htm"/>
+      </customErrors>
+    -->
+  </system.web>
+</configuration>
diff --git a/lib/csharp/test/ThriftMVCTest/Web.config b/lib/csharp/test/ThriftMVCTest/Web.config
new file mode 100644
index 0000000..9c57d11
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Web.config
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  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.
+-->
+
+<!--
+  For more information on how to configure your ASP.NET application, please visit
+  http://go.microsoft.com/fwlink/?LinkId=301880
+  -->
+<configuration>
+  <appSettings>
+    <add key="webpages:Version" value="3.0.0.0" />
+    <add key="webpages:Enabled" value="false" />
+    <add key="ClientValidationEnabled" value="true" />
+    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
+    <add key="owin:AutomaticAppStartup" value="false" />
+  </appSettings>
+  <system.web>
+    <authentication mode="None" />
+    <compilation debug="true" targetFramework="4.5" />
+    <httpRuntime targetFramework="4.5" />
+  </system.web>
+  <system.webServer>
+    <modules>
+      <remove name="FormsAuthentication" />
+    </modules>
+    <handlers>
+      <add name="AsyncHttpHandler" verb="*" path="Async.thrift" type="ThriftMVCTest.AsyncHttpHandler, ThriftMVCTest" />
+      <add name="SyncHttpHandler" verb="*" path="Sync.thrift" type="ThriftMVCTest.SyncHttpHandler, ThriftMVCTest" />
+    </handlers>
+  </system.webServer>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
+        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+</configuration>
\ No newline at end of file
diff --git a/lib/csharp/test/ThriftMVCTest/favicon.ico b/lib/csharp/test/ThriftMVCTest/favicon.ico
new file mode 100644
index 0000000..a3a7999
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/favicon.ico
Binary files differ
diff --git a/lib/csharp/test/ThriftMVCTest/packages.config b/lib/csharp/test/ThriftMVCTest/packages.config
new file mode 100644
index 0000000..98c8416
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/packages.config
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<packages>
+  <package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
+  <package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net45" />
+  <package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net45" />
+  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift
index ac49aee..bdc6d87 100644
--- a/test/ThriftTest.thrift
+++ b/test/ThriftTest.thrift
@@ -23,6 +23,7 @@
 
 namespace c_glib TTest
 namespace cpp thrift.test
+namespace csharp Thrift.Test
 namespace delphi Thrift.Test
 namespace go thrifttest
 namespace java thrift.test
diff --git a/test/csharp/Makefile.am b/test/csharp/Makefile.am
new file mode 100644
index 0000000..ad166e3
--- /dev/null
+++ b/test/csharp/Makefile.am
@@ -0,0 +1,95 @@
+#
+# 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.
+#
+
+GENERATED = \
+	gen-csharp/Thrift/Test/Bonk.cs \
+	gen-csharp/Thrift/Test/Bools.cs \
+	gen-csharp/Thrift/Test/BoolTest.cs \
+	gen-csharp/Thrift/Test/CrazyNesting.cs \
+	gen-csharp/Thrift/Test/EmptyStruct.cs \
+	gen-csharp/Thrift/Test/GuessProtocolStruct.cs \
+	gen-csharp/Thrift/Test/Insanity.cs \
+	gen-csharp/Thrift/Test/LargeDeltas.cs \
+	gen-csharp/Thrift/Test/ListBonks.cs \
+	gen-csharp/Thrift/Test/ListTypeVersioningV1.cs \
+	gen-csharp/Thrift/Test/ListTypeVersioningV2.cs \
+	gen-csharp/Thrift/Test/NestedListsBonk.cs \
+	gen-csharp/Thrift/Test/NestedListsI32x2.cs \
+	gen-csharp/Thrift/Test/NestedListsI32x3.cs \
+	gen-csharp/Thrift/Test/NestedMixedx2.cs \
+	gen-csharp/Thrift/Test/Numberz.cs \
+	gen-csharp/Thrift/Test/OneField.cs \
+	gen-csharp/Thrift/Test/SecondService.cs \
+	gen-csharp/Thrift/Test/StructA.cs \
+	gen-csharp/Thrift/Test/StructB.cs \
+	gen-csharp/Thrift/Test/ThriftTest.Constants.cs \
+	gen-csharp/Thrift/Test/ThriftTest.cs \
+	gen-csharp/Thrift/Test/VersioningTestV1.cs \
+	gen-csharp/Thrift/Test/VersioningTestV2.cs \
+	gen-csharp/Thrift/Test/Xception.cs \
+	gen-csharp/Thrift/Test/Xception2.cs \
+	gen-csharp/Thrift/Test/Xtruct.cs \
+	gen-csharp/Thrift/Test/Xtruct2.cs \
+	gen-csharp/Thrift/Test/Xtruct3.cs
+
+BUILT_SOURCES = $(GENERATED)
+
+if MONO_MCS
+CSC = mcs
+else
+CSC = gmcs
+endif
+
+if NET_2_0
+CSC_DEFINES = -d:NET_2_0
+endif
+
+LIBDIR = $(top_builddir)/lib/csharp
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+$(GENERATED): $(top_srcdir)/test/ThriftTest.thrift $(THRIFT)
+	$(THRIFT) --gen csharp -o . $<
+
+precross: TestClientServer.exe
+
+ThriftImpl.dll: $(GENERATED) $(LIBDIR)/Thrift.dll
+	$(CSC) $(CSC_DEFINES) -t:library -out:$@ -reference:$(LIBDIR)/Thrift.dll $(GENERATED)
+
+SRCS = TestClient.cs TestServer.cs Program.cs
+
+TestClientServer.exe: $(SRCS) ThriftImpl.dll
+	$(CSC) $(CSC_DEFINES) -out:$@ -reference:$(LIBDIR)/Thrift.dll -reference:ThriftImpl.dll $(SRCS)
+
+clean-local:
+	$(RM) -rf gen-csharp *.exe *.dll
+
+TESTPORT = 9500
+check-local: TestClientServer.exe
+	MONO_PATH=$(LIBDIR) timeout 10 mono TestClientServer.exe server --port=$(TESTPORT) &
+	sleep 1
+	MONO_PATH=$(LIBDIR) mono TestClientServer.exe client --port=$(TESTPORT)
+
+EXTRA_DIST = \
+	Properties/AssemblyInfo.cs \
+	ThriftTest.csproj \
+	ThriftTest.sln \
+	Program.cs \
+	TestServer.cs \
+	TestClient.cs
diff --git a/test/csharp/Program.cs b/test/csharp/Program.cs
new file mode 100644
index 0000000..8ec00e3
--- /dev/null
+++ b/test/csharp/Program.cs
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+
+using System;
+using Thrift.Transport;
+using Thrift.Protocol;
+using Thrift.Test; //generated code
+
+namespace Test
+{
+    class Program
+    {
+        static int Main(string[] args)
+        {
+            if (args.Length == 0)
+            {
+                Console.WriteLine("must provide 'server' or 'client' arg");
+                return -1;
+            }
+
+            try
+            {
+                Console.SetBufferSize(Console.BufferWidth, 4096);
+            }
+            catch (Exception)
+            {
+                Console.WriteLine("Failed to grow scroll-back buffer");
+            }
+
+            string[] subArgs = new string[args.Length - 1];
+            for(int i = 1; i < args.Length; i++)
+            {
+                subArgs[i-1] = args[i];
+            }
+            if (args[0] == "client")
+            {
+                return TestClient.Execute(subArgs);
+            }
+            else if (args[0] == "server")
+            {
+                return TestServer.Execute(subArgs) ? 0 : 1;
+            }
+            else
+            {
+                Console.WriteLine("first argument must be 'server' or 'client'");
+            }
+            return 0;
+        }
+    }
+}
diff --git a/test/csharp/Properties/AssemblyInfo.cs b/test/csharp/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..376ff25
--- /dev/null
+++ b/test/csharp/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+ * 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("ThriftTest")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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("f41b193b-f1ab-48ee-8843-f88e43084e26")]
+
+// 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.14.0.0")]
+[assembly: AssemblyFileVersion("0.14.0.0")]
diff --git a/test/csharp/TestClient.cs b/test/csharp/TestClient.cs
new file mode 100644
index 0000000..949c06e
--- /dev/null
+++ b/test/csharp/TestClient.cs
@@ -0,0 +1,870 @@
+/*
+ * 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;
+using System.Linq;
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Threading;
+using System.Security.Cryptography.X509Certificates;
+using Thrift.Collections;
+using Thrift.Protocol;
+using Thrift.Transport;
+using Thrift.Test;
+using System.Security.Authentication;
+
+namespace Test
+{
+    public class TestClient
+    {
+        public class TestParams
+        {
+            public int numIterations = 1;
+            public string host = "localhost";
+            public int port = 9090;
+            public string url;
+            public string pipe;
+            public bool buffered;
+            public bool framed;
+            public string protocol;
+            public bool encrypted = false;
+            public bool multiplexed = false;
+            protected bool _isFirstTransport = true;
+
+
+            public TTransport CreateTransport()
+            {
+                if (url == null)
+                {
+                    // endpoint transport
+                    TTransport trans = null;
+                    if (pipe != null)
+                        trans = new TNamedPipeClientTransport(pipe);
+                    else
+                    {
+                        if (encrypted)
+                        {
+                            string certPath = "../keys/client.p12";
+                            X509Certificate cert = new X509Certificate2(certPath, "thrift");
+                            trans = new TTLSSocket(host, port, 0, cert, 
+                                (o, c, chain, errors) => true, 
+                                null, SslProtocols.Tls);
+                        }
+                        else
+                        {
+                            trans = new TSocket(host, port);
+                        }
+                    }
+
+                    // layered transport
+                    if (buffered)
+                        trans = new TBufferedTransport(trans);
+                    if (framed)
+                        trans = new TFramedTransport(trans);
+
+                    if (_isFirstTransport)
+                    {
+                        //ensure proper open/close of transport
+                        trans.Open();
+                        trans.Close();
+                        _isFirstTransport = false;
+                    }
+                    return trans;
+                }
+                else
+                {
+                    return new THttpClient(new Uri(url));
+                }
+            }
+
+            public TProtocol CreateProtocol(TTransport transport)
+            {
+                if (protocol == "compact")
+                    return new TCompactProtocol(transport);
+                else if (protocol == "json")
+                    return new TJSONProtocol(transport);
+                else
+                    return new TBinaryProtocol(transport);
+            }
+        };
+
+        private const int ErrorBaseTypes = 1;
+        private const int ErrorStructs = 2;
+        private const int ErrorContainers = 4;
+        private const int ErrorExceptions = 8;
+        private const int ErrorProtocol = 16;
+        private const int ErrorUnknown = 64;
+
+        private class ClientTest
+        {
+            private readonly TestParams param;
+            private readonly TTransport transport;
+            private readonly SecondService.Client second;
+            private readonly ThriftTest.Client client;
+            private readonly int numIterations;
+            private bool done;
+
+            public int ReturnCode { get; set; }
+
+            public ClientTest(TestParams paramin)
+            {
+                param = paramin;
+                transport = param.CreateTransport();
+                TProtocol protocol = param.CreateProtocol(transport);
+                if (param.multiplexed)
+                {
+                    second = new SecondService.Client(new TMultiplexedProtocol(protocol, "SecondService"));
+                }
+                client = new ThriftTest.Client(protocol);
+                numIterations = param.numIterations;
+            }
+            public void Execute()
+            {
+                if (done)
+                {
+                    Console.WriteLine("Execute called more than once");
+                    throw new InvalidOperationException();
+                }
+
+                for (int i = 0; i < numIterations; i++)
+                {
+                    try
+                    {
+                        if (!transport.IsOpen)
+                            transport.Open();
+                    }
+                    catch (TTransportException ex)
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        Console.WriteLine("Connect failed: " + ex.Message);
+                        ReturnCode |= ErrorUnknown;
+                        Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                        continue;
+                    }
+
+                    try
+                    {
+                        ReturnCode |= ExecuteClientTest(client, second, param);
+                    }
+                    catch (Exception ex)
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                        ReturnCode |= ErrorUnknown;
+                    }
+                }
+                try
+                {
+                    transport.Close();
+                }
+                catch(Exception ex)
+                {
+                    Console.WriteLine("Error while closing transport");
+                    Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                }
+                done = true;
+            }
+        }
+
+        public static int Execute(string[] args)
+        {
+            try
+            {
+                TestParams param = new TestParams();
+                int numThreads = 1;
+                try
+                {
+                    for (int i = 0; i < args.Length; i++)
+                    {
+                        if (args[i] == "-u")
+                        {
+                            param.url = args[++i];
+                        }
+                        else if (args[i] == "-n")
+                        {
+                            param.numIterations = Convert.ToInt32(args[++i]);
+                        }
+                        else if (args[i] == "-pipe")  // -pipe <name>
+                        {
+                            param.pipe = args[++i];
+                            Console.WriteLine("Using named pipes transport");
+                        }
+                        else if (args[i].Contains("--host="))
+                        {
+                            param.host = args[i].Substring(args[i].IndexOf("=") + 1);
+                        }
+                        else if (args[i].Contains("--port="))
+                        {
+                            param.port = int.Parse(args[i].Substring(args[i].IndexOf("=")+1));
+                        }
+                        else if (args[i] == "-b" || args[i] == "--buffered" || args[i] == "--transport=buffered")
+                        {
+                            param.buffered = true;
+                            Console.WriteLine("Using buffered sockets");
+                        }
+                        else if (args[i] == "-f" || args[i] == "--framed"  || args[i] == "--transport=framed")
+                        {
+                            param.framed = true;
+                            Console.WriteLine("Using framed transport");
+                        }
+                        else if (args[i] == "-t")
+                        {
+                            numThreads = Convert.ToInt32(args[++i]);
+                        }
+                        else if (args[i] == "--compact" || args[i] == "--protocol=compact" || args[i] == "--protocol=multic")
+                        {
+                            param.protocol = "compact";
+                            Console.WriteLine("Using compact protocol");
+                        }
+                        else if (args[i] == "--json" || args[i] == "--protocol=json" || args[i] == "--protocol=multij")
+                        {
+                            param.protocol = "json";
+                            Console.WriteLine("Using JSON protocol");
+                        }
+                        else if (args[i] == "--ssl")
+                        {
+                            param.encrypted = true;
+                            Console.WriteLine("Using encrypted transport");
+                        }
+
+                        if (args[i].StartsWith("--protocol=multi"))
+                        {
+                            param.multiplexed = true;
+                        }
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    Console.WriteLine("Error while  parsing arguments");
+                    Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                    return ErrorUnknown;
+                }
+
+                var tests = Enumerable.Range(0, numThreads).Select(_ => new ClientTest(param)).ToArray();
+                //issue tests on separate threads simultaneously
+                var threads = tests.Select(test => new Thread(test.Execute)).ToArray();
+                DateTime start = DateTime.Now;
+                foreach (var t in threads)
+                    t.Start();
+                foreach (var t in threads)
+                    t.Join();
+                Console.WriteLine("Total time: " + (DateTime.Now - start));
+                Console.WriteLine();
+                return tests.Select(t => t.ReturnCode).Aggregate((r1, r2) => r1 | r2);
+            }
+            catch (Exception outerEx)
+            {
+                Console.WriteLine("*** FAILED ***");
+                Console.WriteLine("Unexpected error");
+                Console.WriteLine(outerEx.Message + " ST: " + outerEx.StackTrace);
+                return ErrorUnknown;
+            }
+        }
+
+        public static string BytesToHex(byte[] data) {
+            return BitConverter.ToString(data).Replace("-", string.Empty);
+        }
+
+        public static byte[] PrepareTestData(bool randomDist, bool huge)
+        {
+            // huge = true tests for THRIFT-4372
+            byte[] retval = new byte[huge ? 0x12345 : 0x100];
+            int initLen = retval.Length;
+
+            // linear distribution, unless random is requested
+            if (!randomDist) {
+                for (var i = 0; i < initLen; ++i) {
+                    retval[i] = (byte)i;
+                }
+                return retval;
+            }
+
+            // random distribution
+            for (var i = 0; i < initLen; ++i) {
+                retval[i] = (byte)0;
+            }
+            var rnd = new Random();
+            for (var i = 1; i < initLen; ++i) {
+                while( true) {
+                    int nextPos = rnd.Next() % initLen;
+                    if (retval[nextPos] == 0) {
+                        retval[nextPos] = (byte)i;
+                        break;
+                    }
+                }
+            }
+            return retval;
+        }
+
+        public static int ExecuteClientTest(ThriftTest.Client client, SecondService.Client second, TestParams param)
+        {
+            int returnCode = 0;
+
+            Console.Write("testVoid()");
+            client.testVoid();
+            Console.WriteLine(" = void");
+
+            Console.Write("testString(\"Test\")");
+            string s = client.testString("Test");
+            Console.WriteLine(" = \"" + s + "\"");
+            if ("Test" != s)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            if (param.multiplexed)
+            {
+                Console.WriteLine("secondTestString(\"Test2\")");
+                s = second.secondtestString("Test2");
+              Console.WriteLine(" = \"" + s + "\"");
+              if ("testString(\"Test2\")" != s)
+              {
+                  Console.WriteLine("*** FAILED ***");
+                  returnCode |= ErrorProtocol;
+              }
+            }
+
+            Console.Write("testBool(true)");
+            bool t = client.testBool((bool)true);
+            Console.WriteLine(" = " + t);
+            if (!t)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+            Console.Write("testBool(false)");
+            bool f = client.testBool((bool)false);
+            Console.WriteLine(" = " + f);
+            if (f)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testByte(1)");
+            sbyte i8 = client.testByte((sbyte)1);
+            Console.WriteLine(" = " + i8);
+            if (1 != i8)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testI32(-1)");
+            int i32 = client.testI32(-1);
+            Console.WriteLine(" = " + i32);
+            if (-1 != i32)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testI64(-34359738368)");
+            long i64 = client.testI64(-34359738368);
+            Console.WriteLine(" = " + i64);
+            if (-34359738368 != i64)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            // TODO: Validate received message
+            Console.Write("testDouble(5.325098235)");
+            double dub = client.testDouble(5.325098235);
+            Console.WriteLine(" = " + dub);
+            if (5.325098235 != dub)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+            Console.Write("testDouble(-0.000341012439638598279)");
+            dub = client.testDouble(-0.000341012439638598279);
+            Console.WriteLine(" = " + dub);
+            if (-0.000341012439638598279 != dub)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            for (i32 = 0; i32 < 2; ++i32)
+            {
+                var huge = (i32 > 0);
+                byte[] binOut = PrepareTestData(false,huge);
+                Console.Write("testBinary(" + BytesToHex(binOut) + ")");
+                try
+                {
+                    byte[] binIn = client.testBinary(binOut);
+                    Console.WriteLine(" = " + BytesToHex(binIn));
+                    if (binIn.Length != binOut.Length)
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        returnCode |= ErrorBaseTypes;
+                    }
+                    for (int ofs = 0; ofs < Math.Min(binIn.Length, binOut.Length); ++ofs)
+                        if (binIn[ofs] != binOut[ofs])
+                        {
+                            Console.WriteLine("*** FAILED ***");
+                            returnCode |= ErrorBaseTypes;
+                        }
+                }
+                catch (Thrift.TApplicationException ex)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorBaseTypes;
+                    Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                }
+            }
+
+            // binary equals? only with hashcode option enabled ...
+            Console.WriteLine("Test CrazyNesting");
+            if( typeof(CrazyNesting).GetMethod("Equals").DeclaringType == typeof(CrazyNesting))
+            {
+                CrazyNesting one = new CrazyNesting();
+                CrazyNesting two = new CrazyNesting();
+                one.String_field = "crazy";
+                two.String_field = "crazy";
+                one.Binary_field = new byte[10] { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF };
+                two.Binary_field = new byte[10] { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF };
+                if (!one.Equals(two))
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorContainers;
+                    throw new Exception("CrazyNesting.Equals failed");
+                }
+            }
+
+            // TODO: Validate received message
+            Console.Write("testStruct({\"Zero\", 1, -3, -5})");
+            Xtruct o = new Xtruct();
+            o.String_thing = "Zero";
+            o.Byte_thing = (sbyte)1;
+            o.I32_thing = -3;
+            o.I64_thing = -5;
+            Xtruct i = client.testStruct(o);
+            Console.WriteLine(" = {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}");
+
+            // TODO: Validate received message
+            Console.Write("testNest({1, {\"Zero\", 1, -3, -5}, 5})");
+            Xtruct2 o2 = new Xtruct2();
+            o2.Byte_thing = (sbyte)1;
+            o2.Struct_thing = o;
+            o2.I32_thing = 5;
+            Xtruct2 i2 = client.testNest(o2);
+            i = i2.Struct_thing;
+            Console.WriteLine(" = {" + i2.Byte_thing + ", {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}, " + i2.I32_thing + "}");
+
+            Dictionary<int, int> mapout = new Dictionary<int, int>();
+            for (int j = 0; j < 5; j++)
+            {
+                mapout[j] = j - 10;
+            }
+            Console.Write("testMap({");
+            bool first = true;
+            foreach (int key in mapout.Keys)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(key + " => " + mapout[key]);
+            }
+            Console.Write("})");
+
+            Dictionary<int, int> mapin = client.testMap(mapout);
+
+            Console.Write(" = {");
+            first = true;
+            foreach (int key in mapin.Keys)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(key + " => " + mapin[key]);
+            }
+            Console.WriteLine("}");
+
+            // TODO: Validate received message
+            List<int> listout = new List<int>();
+            for (int j = -2; j < 3; j++)
+            {
+                listout.Add(j);
+            }
+            Console.Write("testList({");
+            first = true;
+            foreach (int j in listout)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.Write("})");
+
+            List<int> listin = client.testList(listout);
+
+            Console.Write(" = {");
+            first = true;
+            foreach (int j in listin)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.WriteLine("}");
+
+            //set
+            // TODO: Validate received message
+            THashSet<int> setout = new THashSet<int>();
+            for (int j = -2; j < 3; j++)
+            {
+                setout.Add(j);
+            }
+            Console.Write("testSet({");
+            first = true;
+            foreach (int j in setout)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.Write("})");
+
+            THashSet<int> setin = client.testSet(setout);
+
+            Console.Write(" = {");
+            first = true;
+            foreach (int j in setin)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.WriteLine("}");
+
+
+            Console.Write("testEnum(ONE)");
+            Numberz ret = client.testEnum(Numberz.ONE);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.ONE != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(TWO)");
+            ret = client.testEnum(Numberz.TWO);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.TWO != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(THREE)");
+            ret = client.testEnum(Numberz.THREE);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.THREE != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(FIVE)");
+            ret = client.testEnum(Numberz.FIVE);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.FIVE != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(EIGHT)");
+            ret = client.testEnum(Numberz.EIGHT);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.EIGHT != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testTypedef(309858235082523)");
+            long uid = client.testTypedef(309858235082523L);
+            Console.WriteLine(" = " + uid);
+            if (309858235082523L != uid)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            // TODO: Validate received message
+            Console.Write("testMapMap(1)");
+            Dictionary<int, Dictionary<int, int>> mm = client.testMapMap(1);
+            Console.Write(" = {");
+            foreach (int key in mm.Keys)
+            {
+                Console.Write(key + " => {");
+                Dictionary<int, int> m2 = mm[key];
+                foreach (int k2 in m2.Keys)
+                {
+                    Console.Write(k2 + " => " + m2[k2] + ", ");
+                }
+                Console.Write("}, ");
+            }
+            Console.WriteLine("}");
+
+            // TODO: Validate received message
+            Insanity insane = new Insanity();
+            insane.UserMap = new Dictionary<Numberz, long>();
+            insane.UserMap[Numberz.FIVE] = 5000L;
+            Xtruct truck = new Xtruct();
+            truck.String_thing = "Truck";
+            truck.Byte_thing = (sbyte)8;
+            truck.I32_thing = 8;
+            truck.I64_thing = 8;
+            insane.Xtructs = new List<Xtruct>();
+            insane.Xtructs.Add(truck);
+            Console.Write("testInsanity()");
+            Dictionary<long, Dictionary<Numberz, Insanity>> whoa = client.testInsanity(insane);
+            Console.Write(" = {");
+            foreach (long key in whoa.Keys)
+            {
+                Dictionary<Numberz, Insanity> val = whoa[key];
+                Console.Write(key + " => {");
+
+                foreach (Numberz k2 in val.Keys)
+                {
+                    Insanity v2 = val[k2];
+
+                    Console.Write(k2 + " => {");
+                    Dictionary<Numberz, long> userMap = v2.UserMap;
+
+                    Console.Write("{");
+                    if (userMap != null)
+                    {
+                        foreach (Numberz k3 in userMap.Keys)
+                        {
+                            Console.Write(k3 + " => " + userMap[k3] + ", ");
+                        }
+                    }
+                    else
+                    {
+                        Console.Write("null");
+                    }
+                    Console.Write("}, ");
+
+                    List<Xtruct> xtructs = v2.Xtructs;
+
+                    Console.Write("{");
+                    if (xtructs != null)
+                    {
+                        foreach (Xtruct x in xtructs)
+                        {
+                            Console.Write("{\"" + x.String_thing + "\", " + x.Byte_thing + ", " + x.I32_thing + ", " + x.I32_thing + "}, ");
+                        }
+                    }
+                    else
+                    {
+                        Console.Write("null");
+                    }
+                    Console.Write("}");
+
+                    Console.Write("}, ");
+                }
+                Console.Write("}, ");
+            }
+            Console.WriteLine("}");
+
+            sbyte arg0 = 1;
+            int arg1 = 2;
+            long arg2 = long.MaxValue;
+            Dictionary<short, string> multiDict = new Dictionary<short, string>();
+            multiDict[1] = "one";
+            Numberz arg4 = Numberz.FIVE;
+            long arg5 = 5000000;
+            Console.Write("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")");
+            Xtruct multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5);
+            Console.Write(" = Xtruct(byte_thing:" + multiResponse.Byte_thing + ",String_thing:" + multiResponse.String_thing
+                        + ",i32_thing:" + multiResponse.I32_thing + ",i64_thing:" + multiResponse.I64_thing + ")\n");
+
+            try
+            {
+                Console.WriteLine("testException(\"Xception\")");
+                client.testException("Xception");
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Xception ex)
+            {
+                if (ex.ErrorCode != 1001 || ex.Message != "Xception")
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testException(\"TException\")");
+                client.testException("TException");
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Thrift.TException)
+            {
+                // OK
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testException(\"ok\")");
+                client.testException("ok");
+                // OK
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+
+            try
+            {
+                Console.WriteLine("testMultiException(\"Xception\", ...)");
+                client.testMultiException("Xception", "ignore");
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Xception ex)
+            {
+                if (ex.ErrorCode != 1001 || ex.Message != "This is an Xception")
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testMultiException(\"Xception2\", ...)");
+                client.testMultiException("Xception2", "ignore");
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Xception2 ex)
+            {
+                if (ex.ErrorCode != 2002 || ex.Struct_thing.String_thing != "This is an Xception2")
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testMultiException(\"success\", \"OK\")");
+                if ("OK" != client.testMultiException("success", "OK").String_thing)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+
+            Stopwatch sw = new Stopwatch();
+            sw.Start();
+            Console.WriteLine("Test Oneway(1)");
+            client.testOneway(1);
+            sw.Stop();
+            if (sw.ElapsedMilliseconds > 1000)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("Test Calltime()");
+            var times = 50;
+            sw.Reset();
+            sw.Start();
+            for (int k = 0; k < times; ++k)
+                client.testVoid();
+            sw.Stop();
+            Console.WriteLine(" = {0} ms a testVoid() call", sw.ElapsedMilliseconds / times);
+            return returnCode;
+        }
+    }
+}
diff --git a/test/csharp/TestServer.cs b/test/csharp/TestServer.cs
new file mode 100644
index 0000000..bf645c2
--- /dev/null
+++ b/test/csharp/TestServer.cs
@@ -0,0 +1,535 @@
+/*
+ * 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.
+ */
+
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+using System;
+using System.Collections.Generic;
+using System.Security.Cryptography.X509Certificates;
+using Thrift.Collections;
+using Thrift.Test; //generated code
+using Thrift.Transport;
+using Thrift.Protocol;
+using Thrift.Server;
+using Thrift;
+using System.Threading;
+using System.Text;
+using System.Security.Authentication;
+
+namespace Test
+{
+    public class TestServer
+    {
+        public static int _clientID = -1;
+        public delegate void TestLogDelegate(string msg, params object[] values);
+
+        public class TradeServerEventHandler : TServerEventHandler
+        {
+            public int callCount = 0;
+            public void preServe()
+            {
+                callCount++;
+            }
+            public Object createContext(Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output)
+            {
+                callCount++;
+                return null;
+            }
+            public void deleteContext(Object serverContext, Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output)
+            {
+                callCount++;
+            }
+            public void processContext(Object serverContext, Thrift.Transport.TTransport transport)
+            {
+                callCount++;
+            }
+        };
+
+
+        public class TestHandler : ThriftTest.Iface, Thrift.TControllingHandler
+        {
+            public TServer server { get; set; }
+            private int handlerID;
+            private StringBuilder reusableStringBuilder = new StringBuilder();
+            private TestLogDelegate testLogDelegate;
+
+            public TestHandler()
+            {
+                handlerID = Interlocked.Increment(ref _clientID);
+                testLogDelegate += testConsoleLogger;
+                testLogDelegate.Invoke("New TestHandler instance created");
+            }
+
+            public void testConsoleLogger(string msg, params object[] values)
+            {
+                reusableStringBuilder.Clear();
+                reusableStringBuilder.AppendFormat("handler{0:D3}:",handlerID);
+                reusableStringBuilder.AppendFormat(msg, values);
+                reusableStringBuilder.AppendLine();
+                Console.Write( reusableStringBuilder.ToString() );
+            }
+
+            public void testVoid()
+            {
+                testLogDelegate.Invoke("testVoid()");
+            }
+
+            public string testString(string thing)
+            {
+                testLogDelegate.Invoke("testString({0})", thing);
+                return thing;
+            }
+
+            public bool testBool(bool thing)
+            {
+                testLogDelegate.Invoke("testBool({0})", thing);
+                return thing;
+            }
+
+            public sbyte testByte(sbyte thing)
+            {
+                testLogDelegate.Invoke("testByte({0})", thing);
+                return thing;
+            }
+
+            public int testI32(int thing)
+            {
+                testLogDelegate.Invoke("testI32({0})", thing);
+                return thing;
+            }
+
+            public long testI64(long thing)
+            {
+                testLogDelegate.Invoke("testI64({0})", thing);
+                return thing;
+            }
+
+            public double testDouble(double thing)
+            {
+                testLogDelegate.Invoke("testDouble({0})", thing);
+                return thing;
+            }
+
+            public byte[] testBinary(byte[] thing)
+            {
+                string hex = BitConverter.ToString(thing).Replace("-", string.Empty);
+                testLogDelegate.Invoke("testBinary({0:X})", hex);
+                return thing;
+            }
+
+            public Xtruct testStruct(Xtruct thing)
+            {
+                testLogDelegate.Invoke("testStruct({{\"{0}\", {1}, {2}, {3}}})", thing.String_thing, thing.Byte_thing, thing.I32_thing, thing.I64_thing);
+                return thing;
+            }
+
+            public Xtruct2 testNest(Xtruct2 nest)
+            {
+                Xtruct thing = nest.Struct_thing;
+                testLogDelegate.Invoke("testNest({{{0}, {{\"{1}\", {2}, {3}, {4}, {5}}}}})",
+                                 nest.Byte_thing,
+                                 thing.String_thing,
+                                 thing.Byte_thing,
+                                 thing.I32_thing,
+                                 thing.I64_thing,
+                                 nest.I32_thing);
+                return nest;
+            }
+
+            public Dictionary<int, int> testMap(Dictionary<int, int> thing)
+            {
+                reusableStringBuilder.Clear();
+                reusableStringBuilder.Append("testMap({{");
+                bool first = true;
+                foreach (int key in thing.Keys)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        reusableStringBuilder.Append(", ");
+                    }
+                    reusableStringBuilder.AppendFormat("{0} => {1}", key, thing[key]);
+                }
+                reusableStringBuilder.Append("}})");
+                testLogDelegate.Invoke(reusableStringBuilder.ToString());
+                return thing;
+            }
+
+            public Dictionary<string, string> testStringMap(Dictionary<string, string> thing)
+            {
+                reusableStringBuilder.Clear();
+                reusableStringBuilder.Append("testStringMap({{");
+                bool first = true;
+                foreach (string key in thing.Keys)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        reusableStringBuilder.Append(", ");
+                    }
+                    reusableStringBuilder.AppendFormat("{0} => {1}", key, thing[key]);
+                }
+                reusableStringBuilder.Append("}})");
+                testLogDelegate.Invoke(reusableStringBuilder.ToString());
+                return thing;
+            }
+
+            public THashSet<int> testSet(THashSet<int> thing)
+            {
+                reusableStringBuilder.Clear();
+                reusableStringBuilder.Append("testSet({{");
+                bool first = true;
+                foreach (int elem in thing)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        reusableStringBuilder.Append(", ");
+                    }
+                    reusableStringBuilder.AppendFormat("{0}", elem);
+                }
+                reusableStringBuilder.Append("}})");
+                testLogDelegate.Invoke(reusableStringBuilder.ToString());
+                return thing;
+            }
+
+            public List<int> testList(List<int> thing)
+            {
+                reusableStringBuilder.Clear();
+                reusableStringBuilder.Append("testList({{");
+                bool first = true;
+                foreach (int elem in thing)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        reusableStringBuilder.Append(", ");
+                    }
+                    reusableStringBuilder.AppendFormat("{0}", elem);
+                }
+                reusableStringBuilder.Append("}})");
+                testLogDelegate.Invoke(reusableStringBuilder.ToString());
+                return thing;
+            }
+
+            public Numberz testEnum(Numberz thing)
+            {
+                testLogDelegate.Invoke("testEnum({0})", thing);
+                return thing;
+            }
+
+            public long testTypedef(long thing)
+            {
+                testLogDelegate.Invoke("testTypedef({0})", thing);
+                return thing;
+            }
+
+            public Dictionary<int, Dictionary<int, int>> testMapMap(int hello)
+            {
+                testLogDelegate.Invoke("testMapMap({0})", hello);
+                Dictionary<int, Dictionary<int, int>> mapmap =
+                  new Dictionary<int, Dictionary<int, int>>();
+
+                Dictionary<int, int> pos = new Dictionary<int, int>();
+                Dictionary<int, int> neg = new Dictionary<int, int>();
+                for (int i = 1; i < 5; i++)
+                {
+                    pos[i] = i;
+                    neg[-i] = -i;
+                }
+
+                mapmap[4] = pos;
+                mapmap[-4] = neg;
+
+                return mapmap;
+            }
+
+            // Insanity
+            // returns:
+            // { 1 => { 2 => argument,
+            //          3 => argument,
+            //        },
+            //   2 => { 6 => <empty Insanity struct>, },
+            // }
+            public Dictionary<long, Dictionary<Numberz, Insanity>> testInsanity(Insanity argument)
+            {
+                testLogDelegate.Invoke("testInsanity()");
+
+                Dictionary<Numberz, Insanity> first_map = new Dictionary<Numberz, Insanity>();
+                Dictionary<Numberz, Insanity> second_map = new Dictionary<Numberz, Insanity>(); ;
+
+                first_map[Numberz.TWO] = argument;
+                first_map[Numberz.THREE] = argument;
+
+                second_map[Numberz.SIX] = new Insanity();
+
+                Dictionary<long, Dictionary<Numberz, Insanity>> insane =
+                  new Dictionary<long, Dictionary<Numberz, Insanity>>();
+                insane[(long)1] = first_map;
+                insane[(long)2] = second_map;
+
+                return insane;
+            }
+
+            public Xtruct testMulti(sbyte arg0, int arg1, long arg2, Dictionary<short, string> arg3, Numberz arg4, long arg5)
+            {
+                testLogDelegate.Invoke("testMulti()");
+
+                Xtruct hello = new Xtruct(); ;
+                hello.String_thing = "Hello2";
+                hello.Byte_thing = arg0;
+                hello.I32_thing = arg1;
+                hello.I64_thing = arg2;
+                return hello;
+            }
+
+            /**
+             * Print 'testException(%s)' with arg as '%s'
+             * @param string arg - a string indication what type of exception to throw
+             * if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+             * elsen if arg == "TException" throw TException
+             * else do not throw anything
+             */
+            public void testException(string arg)
+            {
+                testLogDelegate.Invoke("testException({0})", arg);
+                if (arg == "Xception")
+                {
+                    Xception x = new Xception();
+                    x.ErrorCode = 1001;
+                    x.Message = arg;
+                    throw x;
+                }
+                if (arg == "TException")
+                {
+                    throw new Thrift.TException();
+                }
+                return;
+            }
+
+            public Xtruct testMultiException(string arg0, string arg1)
+            {
+                testLogDelegate.Invoke("testMultiException({0}, {1})", arg0,arg1);
+                if (arg0 == "Xception")
+                {
+                    Xception x = new Xception();
+                    x.ErrorCode = 1001;
+                    x.Message = "This is an Xception";
+                    throw x;
+                }
+                else if (arg0 == "Xception2")
+                {
+                    Xception2 x = new Xception2();
+                    x.ErrorCode = 2002;
+                    x.Struct_thing = new Xtruct();
+                    x.Struct_thing.String_thing = "This is an Xception2";
+                    throw x;
+                }
+
+                Xtruct result = new Xtruct();
+                result.String_thing = arg1;
+                return result;
+            }
+
+            public void testStop()
+            {
+                if (server != null)
+                {
+                    server.Stop();
+                }
+            }
+
+            public void testOneway(int arg)
+            {
+                testLogDelegate.Invoke("testOneway({0}), sleeping...", arg);
+                System.Threading.Thread.Sleep(arg * 1000);
+                testLogDelegate.Invoke("testOneway finished");
+            }
+
+        } // class TestHandler
+
+        private enum ServerType
+        {
+            TSimpleServer,
+            TThreadedServer,
+            TThreadPoolServer,
+        }
+
+        private enum ProcessorFactoryType
+        {
+            TSingletonProcessorFactory,
+            TPrototypeProcessorFactory,
+        }
+
+        public static bool Execute(string[] args)
+        {
+            try
+            {
+                bool useBufferedSockets = false, useFramed = false, useEncryption = false, compact = false, json = false;
+                ServerType serverType = ServerType.TSimpleServer;
+                ProcessorFactoryType processorFactoryType = ProcessorFactoryType.TSingletonProcessorFactory;
+                int port = 9090;
+                string pipe = null;
+                for (int i = 0; i < args.Length; i++)
+                {
+                    if (args[i] == "-pipe")  // -pipe name
+                    {
+                        pipe = args[++i];
+                    }
+                    else if (args[i].Contains("--port="))
+                    {
+                        port = int.Parse(args[i].Substring(args[i].IndexOf("=") + 1));
+                    }
+                    else if (args[i] == "-b" || args[i] == "--buffered" || args[i] == "--transport=buffered")
+                    {
+                        useBufferedSockets = true;
+                    }
+                    else if (args[i] == "-f" || args[i] == "--framed" || args[i] == "--transport=framed")
+                    {
+                        useFramed = true;
+                    }
+                    else if (args[i] == "--compact" || args[i] == "--protocol=compact")
+                    {
+                        compact = true;
+                    }
+                    else if (args[i] == "--json" || args[i] == "--protocol=json")
+                    {
+                        json = true;
+                    }
+                    else if (args[i] == "--threaded" || args[i] == "--server-type=threaded")
+                    {
+                        serverType = ServerType.TThreadedServer;
+                    }
+                    else if (args[i] == "--threadpool" || args[i] == "--server-type=threadpool")
+                    {
+                        serverType = ServerType.TThreadPoolServer;
+                    }
+                    else if (args[i] == "--prototype" || args[i] == "--processor=prototype")
+                    {
+                        processorFactoryType = ProcessorFactoryType.TPrototypeProcessorFactory;
+                    }
+                    else if (args[i] == "--ssl")
+                    {
+                        useEncryption = true;
+                    }
+                }
+
+                // Transport
+                TServerTransport trans;
+                if (pipe != null)
+                {
+                    trans = new TNamedPipeServerTransport(pipe);
+                }
+                else
+                {
+                    if (useEncryption)
+                    {
+                        string certPath = "../keys/server.p12";
+                        trans = new TTLSServerSocket(port, 0, useBufferedSockets, new X509Certificate2(certPath, "thrift"), 
+                            null,
+                            null, SslProtocols.Tls);
+                    }
+                    else
+                    {
+                        trans = new TServerSocket(port, 0, useBufferedSockets);
+                    }
+                }
+
+                TProtocolFactory proto;
+                if (compact)
+                    proto = new TCompactProtocol.Factory();
+                else if (json)
+                    proto = new TJSONProtocol.Factory();
+                else
+                    proto = new TBinaryProtocol.Factory();
+
+                TProcessorFactory processorFactory;
+                if (processorFactoryType == ProcessorFactoryType.TPrototypeProcessorFactory)
+                {
+                    processorFactory = new TPrototypeProcessorFactory<ThriftTest.Processor, TestHandler>();
+                }
+                else
+                {
+                    // Processor
+                    TestHandler testHandler = new TestHandler();
+                    ThriftTest.Processor testProcessor = new ThriftTest.Processor(testHandler);
+                    processorFactory = new TSingletonProcessorFactory(testProcessor);
+                }
+
+                TTransportFactory transFactory;
+                if (useFramed)
+                    transFactory = new TFramedTransport.Factory();
+                else
+                    transFactory = new TTransportFactory();
+
+                TServer serverEngine;
+                switch (serverType)
+                {
+                    case ServerType.TThreadPoolServer:
+                        serverEngine = new TThreadPoolServer(processorFactory, trans, transFactory, proto);
+                        break;
+                    case ServerType.TThreadedServer:
+                        serverEngine = new TThreadedServer(processorFactory, trans, transFactory, proto);
+                        break;
+                    default:
+                        serverEngine = new TSimpleServer(processorFactory, trans, transFactory, proto);
+                        break;
+                }
+
+                //Server event handler
+                TradeServerEventHandler serverEvents = new TradeServerEventHandler();
+                serverEngine.setEventHandler(serverEvents);
+
+                // Run it
+                string where = (pipe != null ? "on pipe " + pipe : "on port " + port);
+                Console.WriteLine("Starting the " + serverType.ToString() + " " + where +
+                    (processorFactoryType == ProcessorFactoryType.TPrototypeProcessorFactory ? " with processor prototype factory " : "") +
+                    (useBufferedSockets ? " with buffered socket" : "") +
+                    (useFramed ? " with framed transport" : "") +
+                    (useEncryption ? " with encryption" : "") +
+                    (compact ? " with compact protocol" : "") +
+                    (json ? " with json protocol" : "") +
+                    "...");
+                serverEngine.Serve();
+
+            }
+            catch (Exception x)
+            {
+                Console.Error.Write(x);
+                return false;
+            }
+            Console.WriteLine("done.");
+            return true;
+        }
+    }
+}
diff --git a/test/csharp/ThriftTest.csproj b/test/csharp/ThriftTest.csproj
new file mode 100644
index 0000000..2ff0926
--- /dev/null
+++ b/test/csharp/ThriftTest.csproj
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ThriftTest</RootNamespace>
+    <AssemblyName>ThriftTest</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>0.14.0.0</ApplicationVersion>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="ThriftImpl, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>.\ThriftImpl.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TestClient.cs" />
+    <Compile Include="TestServer.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\lib\csharp\Thrift.csproj">
+      <Project>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</Project>
+      <Name>Thrift</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>rmdir /s /q "$(ProjectDir)gen-csharp"
+del /f /q "$(ProjectDir)ThriftImpl.dll"
+SET OUTPUT_DIR=$(ProjectDir)
+SET THRIFT_FILE=$(ProjectDir)\..\ThriftTest.thrift
+for %25%25I in ("%25OUTPUT_DIR%25") do set SHORT_DIR=%25%25~fsI
+for %25%25I in ("%25THRIFT_FILE%25") do set THRIFT_SHORT=%25%25~fsI
+"$(ProjectDir)\..\..\compiler\cpp\thrift.exe" --gen csharp -o %25SHORT_DIR%25 %25THRIFT_SHORT%25
+$(MSBuildToolsPath)\Csc.exe /t:library /out:"$(ProjectDir)ThriftImpl.dll" /recurse:"$(ProjectDir)gen-csharp"\* /reference:"$(ProjectDir)..\..\lib\csharp\bin\Debug\Thrift.dll"</PreBuildEvent>
+  </PropertyGroup>
+</Project>
diff --git a/test/csharp/ThriftTest.sln b/test/csharp/ThriftTest.sln
new file mode 100644
index 0000000..1765a03
--- /dev/null
+++ b/test/csharp/ThriftTest.sln
@@ -0,0 +1,17 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftTest", "ThriftTest.csproj", "{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/tutorial/csharp/CsharpClient/CsharpClient.cs b/tutorial/csharp/CsharpClient/CsharpClient.cs
new file mode 100644
index 0000000..113a472
--- /dev/null
+++ b/tutorial/csharp/CsharpClient/CsharpClient.cs
@@ -0,0 +1,92 @@
+/*
+ * 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;
+using Thrift;
+using Thrift.Protocol;
+using Thrift.Server;
+using Thrift.Transport;
+
+
+namespace CSharpTutorial
+{
+    public class CSharpClient
+    {
+        public static void Main()
+        {
+            try
+            {
+                TTransport transport = new TSocket("localhost", 9090);
+                TProtocol protocol = new TBinaryProtocol(transport);
+                Calculator.Client client = new Calculator.Client(protocol);
+
+                transport.Open();
+                try
+                {
+                    client.ping();
+                    Console.WriteLine("ping()");
+
+                    int sum = client.add(1, 1);
+                    Console.WriteLine("1+1={0}", sum);
+
+                    Work work = new Work();
+
+                    work.Op = Operation.DIVIDE;
+                    work.Num1 = 1;
+                    work.Num2 = 0;
+                    try
+                    {
+                        int quotient = client.calculate(1, work);
+                        Console.WriteLine("Whoa we can divide by 0");
+                    }
+                    catch (InvalidOperation io)
+                    {
+                        Console.WriteLine("Invalid operation: " + io.Why);
+                    }
+
+                    work.Op = Operation.SUBTRACT;
+                    work.Num1 = 15;
+                    work.Num2 = 10;
+                    try
+                    {
+                        int diff = client.calculate(1, work);
+                        Console.WriteLine("15-10={0}", diff);
+                    }
+                    catch (InvalidOperation io)
+                    {
+                        Console.WriteLine("Invalid operation: " + io.Why);
+                    }
+
+                    SharedStruct log = client.getStruct(1);
+                    Console.WriteLine("Check log: {0}", log.Value);
+
+                }
+                finally
+                {
+                    transport.Close();
+                }
+            }
+            catch (TApplicationException x)
+            {
+                Console.WriteLine(x.StackTrace);
+            }
+
+        }
+    }
+}
diff --git a/tutorial/csharp/CsharpClient/CsharpClient.csproj b/tutorial/csharp/CsharpClient/CsharpClient.csproj
new file mode 100644
index 0000000..1ea7ff6
--- /dev/null
+++ b/tutorial/csharp/CsharpClient/CsharpClient.csproj
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{18F24087-4760-43DA-ACAB-7B9F0E096B11}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>CsharpClient</RootNamespace>
+    <AssemblyName>CsharpClient</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\gen-csharp\Calculator.cs">
+      <Link>Calculator.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\InvalidOperation.cs">
+      <Link>InvalidOperation.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\Operation.cs">
+      <Link>Operation.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\SharedService.cs">
+      <Link>SharedService.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\SharedStruct.cs">
+      <Link>SharedStruct.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\tutorial.Constants.cs">
+      <Link>tutorial.Constants.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\Work.cs">
+      <Link>Work.cs</Link>
+    </Compile>
+    <Compile Include="CsharpClient.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\lib\csharp\src\Thrift.csproj">
+      <Project>{499eb63c-d74c-47e8-ae48-a2fc94538e9d}</Project>
+      <Name>Thrift</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent>pushd "$(SolutionDir)"
+thrift  -gen csharp   -r  ../tutorial.thrift
+popd
+</PreBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs b/tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..8f5b32a
--- /dev/null
+++ b/tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+ * 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("CsharpClient")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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("1a461214-fa28-452a-bd1d-d23ca8e947e3")]
+
+// 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.14.0.0")]
+[assembly: AssemblyFileVersion("0.14.0.0")]
diff --git a/tutorial/csharp/CsharpServer/CsharpServer.cs b/tutorial/csharp/CsharpServer/CsharpServer.cs
new file mode 100644
index 0000000..439790a
--- /dev/null
+++ b/tutorial/csharp/CsharpServer/CsharpServer.cs
@@ -0,0 +1,129 @@
+/*
+ * 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;
+using System.Collections.Generic;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace CSharpTutorial
+{
+    public class CalculatorHandler : Calculator.Iface
+    {
+        Dictionary<int, SharedStruct> log;
+
+        public CalculatorHandler()
+        {
+            log = new Dictionary<int, SharedStruct>();
+        }
+
+        public void ping()
+        {
+            Console.WriteLine("ping()");
+        }
+
+        public int add(int n1, int n2)
+        {
+            Console.WriteLine("add({0},{1})", n1, n2);
+            return n1 + n2;
+        }
+
+        public int calculate(int logid, Work work)
+        {
+            Console.WriteLine("calculate({0}, [{1},{2},{3}])", logid, work.Op, work.Num1, work.Num2);
+            int val = 0;
+            switch (work.Op)
+            {
+                case Operation.ADD:
+                    val = work.Num1 + work.Num2;
+                    break;
+
+                case Operation.SUBTRACT:
+                    val = work.Num1 - work.Num2;
+                    break;
+
+                case Operation.MULTIPLY:
+                    val = work.Num1 * work.Num2;
+                    break;
+
+                case Operation.DIVIDE:
+                    if (work.Num2 == 0)
+                    {
+                        InvalidOperation io = new InvalidOperation();
+                        io.WhatOp = (int)work.Op;
+                        io.Why = "Cannot divide by 0";
+                        throw io;
+                    }
+                    val = work.Num1 / work.Num2;
+                    break;
+
+                default:
+                    {
+                        InvalidOperation io = new InvalidOperation();
+                        io.WhatOp = (int)work.Op;
+                        io.Why = "Unknown operation";
+                        throw io;
+                    }
+            }
+
+            SharedStruct entry = new SharedStruct();
+            entry.Key = logid;
+            entry.Value = val.ToString();
+            log[logid] = entry;
+
+            return val;
+        }
+
+        public SharedStruct getStruct(int key)
+        {
+            Console.WriteLine("getStruct({0})", key);
+            return log[key];
+        }
+
+        public void zip()
+        {
+            Console.WriteLine("zip()");
+        }
+    }
+
+    public class CSharpServer
+    {
+        public static void Main()
+        {
+            try
+            {
+                CalculatorHandler handler = new CalculatorHandler();
+                Calculator.Processor processor = new Calculator.Processor(handler);
+                TServerTransport serverTransport = new TServerSocket(9090);
+                TServer server = new TSimpleServer(processor, serverTransport);
+
+                // Use this for a multithreaded server
+                // server = new TThreadPoolServer(processor, serverTransport);
+
+                Console.WriteLine("Starting the server...");
+                server.Serve();
+            }
+            catch (Exception x)
+            {
+                Console.WriteLine(x.StackTrace);
+            }
+            Console.WriteLine("done.");
+        }
+    }
+}
diff --git a/tutorial/csharp/CsharpServer/CsharpServer.csproj b/tutorial/csharp/CsharpServer/CsharpServer.csproj
new file mode 100644
index 0000000..0748180
--- /dev/null
+++ b/tutorial/csharp/CsharpServer/CsharpServer.csproj
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{66707BAE-BBF9-4F03-B53E-BE3AD58322F8}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>CsharpServer</RootNamespace>
+    <AssemblyName>CsharpServer</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\gen-csharp\Calculator.cs">
+      <Link>Calculator.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\InvalidOperation.cs">
+      <Link>InvalidOperation.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\Operation.cs">
+      <Link>Operation.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\SharedService.cs">
+      <Link>SharedService.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\SharedStruct.cs">
+      <Link>SharedStruct.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\tutorial.Constants.cs">
+      <Link>tutorial.Constants.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\Work.cs">
+      <Link>Work.cs</Link>
+    </Compile>
+    <Compile Include="CsharpServer.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\lib\csharp\src\Thrift.csproj">
+      <Project>{499eb63c-d74c-47e8-ae48-a2fc94538e9d}</Project>
+      <Name>Thrift</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent>pushd "$(SolutionDir)"
+thrift  -gen csharp   -r  ../tutorial.thrift
+popd
+
+</PreBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs b/tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0d4f0fb
--- /dev/null
+++ b/tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+ * 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("CsharpServer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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("e3b428f4-b2e9-4fc1-8a34-84abc4339860")]
+
+// 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.14.0.0")]
+[assembly: AssemblyFileVersion("0.14.0.0")]
diff --git a/tutorial/csharp/tutorial.sln b/tutorial/csharp/tutorial.sln
new file mode 100644
index 0000000..ec57a18
--- /dev/null
+++ b/tutorial/csharp/tutorial.sln
@@ -0,0 +1,39 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsharpClient", "CsharpClient\CsharpClient.csproj", "{18F24087-4760-43DA-ACAB-7B9F0E096B11}"
+    ProjectSection(ProjectDependencies) = postProject
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D} = {499EB63C-D74C-47E8-AE48-A2FC94538E9D}
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8} = {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}
+    EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsharpServer", "CsharpServer\CsharpServer.csproj", "{66707BAE-BBF9-4F03-B53E-BE3AD58322F8}"
+    ProjectSection(ProjectDependencies) = postProject
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D} = {499EB63C-D74C-47E8-AE48-A2FC94538E9D}
+    EndProjectSection
+EndProject
+Global
+    GlobalSection(SolutionConfigurationPlatforms) = preSolution
+        Debug|Any CPU = Debug|Any CPU
+        Release|Any CPU = Release|Any CPU
+    EndGlobalSection
+    GlobalSection(ProjectConfigurationPlatforms) = postSolution
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU
+        {18F24087-4760-43DA-ACAB-7B9F0E096B11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+        {18F24087-4760-43DA-ACAB-7B9F0E096B11}.Debug|Any CPU.Build.0 = Debug|Any CPU
+        {18F24087-4760-43DA-ACAB-7B9F0E096B11}.Release|Any CPU.ActiveCfg = Release|Any CPU
+        {18F24087-4760-43DA-ACAB-7B9F0E096B11}.Release|Any CPU.Build.0 = Release|Any CPU
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Release|Any CPU.Build.0 = Release|Any CPU
+    EndGlobalSection
+    GlobalSection(SolutionProperties) = preSolution
+        HideSolutionNode = FALSE
+    EndGlobalSection
+EndGlobal