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

Only compiler, test, lib and tutorial code.
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();
+            }
+        }
+    }
+}