You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by je...@apache.org on 2017/01/04 18:41:21 UTC

[5/9] thrift git commit: THRIFT-3933 Microsoft .Net Core library port and generator for this library Client: .NET Core Patch: Volodymyr Gotra PR #1088, with significant improvements by Jens Geyer PR #1149

http://git-wip-us.apache.org/repos/asf/thrift/blob/b587a12a/lib/netcore/Thrift/Protocols/TJSONProtocol.cs
----------------------------------------------------------------------
diff --git a/lib/netcore/Thrift/Protocols/TJSONProtocol.cs b/lib/netcore/Thrift/Protocols/TJSONProtocol.cs
new file mode 100644
index 0000000..a4ddd5b
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TJSONProtocol.cs
@@ -0,0 +1,1170 @@
+// 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.Globalization;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols.Entities;
+using Thrift.Protocols.Utilities;
+using Thrift.Transports;
+
+namespace Thrift.Protocols
+{
+    //TODO: implementation of TProtocol
+
+    /// <summary>
+    ///     JSON protocol implementation for thrift.
+    ///     This is a full-featured protocol supporting Write and Read.
+    ///     Please see the C++ class header for a detailed description of the
+    ///     protocol's wire format.
+    ///     Adapted from the Java version.
+    /// </summary>
+    // ReSharper disable once InconsistentNaming
+    public class TJsonProtocol : TProtocol
+    {
+        private const long Version = 1;
+
+        private const int DefStringSize = 16;
+
+        private static readonly byte[] Comma = {(byte) ','};
+        private static readonly byte[] Colon = {(byte) ':'};
+        private static readonly byte[] Lbrace = {(byte) '{'};
+        private static readonly byte[] Rbrace = {(byte) '}'};
+        private static readonly byte[] Lbracket = {(byte) '['};
+        private static readonly byte[] Rbracket = {(byte) ']'};
+        private static readonly byte[] Quote = {(byte) '"'};
+        private static readonly byte[] Backslash = {(byte) '\\'};
+
+        private static readonly byte[] NameBool = {(byte) 't', (byte) 'f'};
+        private static readonly byte[] NameByte = {(byte) 'i', (byte) '8'};
+        private static readonly byte[] NameI16 = {(byte) 'i', (byte) '1', (byte) '6'};
+        private static readonly byte[] NameI32 = {(byte) 'i', (byte) '3', (byte) '2'};
+        private static readonly byte[] NameI64 = {(byte) 'i', (byte) '6', (byte) '4'};
+        private static readonly byte[] NameDouble = {(byte) 'd', (byte) 'b', (byte) 'l'};
+        private static readonly byte[] NameStruct = {(byte) 'r', (byte) 'e', (byte) 'c'};
+        private static readonly byte[] NameString = {(byte) 's', (byte) 't', (byte) 'r'};
+        private static readonly byte[] NameMap = {(byte) 'm', (byte) 'a', (byte) 'p'};
+        private static readonly byte[] NameList = {(byte) 'l', (byte) 's', (byte) 't'};
+        private static readonly byte[] NameSet = {(byte) 's', (byte) 'e', (byte) 't'};
+
+        private readonly char[] _escapeChars = "\"\\/bfnrt".ToCharArray();
+
+        private readonly byte[] _escapeCharVals =
+        {
+            (byte) '"', (byte) '\\', (byte) '/', (byte) '\b', (byte) '\f', (byte) '\n', (byte) '\r', (byte) '\t'
+        };
+
+        private readonly byte[] _escseq = {(byte) '\\', (byte) 'u', (byte) '0', (byte) '0'};
+
+        private readonly byte[] _jsonCharTable =
+        {
+            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
+        };
+
+        // Temporary buffer used by several methods
+        private readonly byte[] _tempBuffer = new byte[4];
+
+        // Current context that we are in
+        protected JsonBaseContext Context;
+
+        // Stack of nested contexts that we may be in
+        protected Stack<JsonBaseContext> ContextStack = new Stack<JsonBaseContext>();
+
+        // Reader that manages a 1-byte buffer
+        protected LookaheadReader Reader;
+
+        // Default encoding
+        protected Encoding Utf8Encoding = Encoding.UTF8;
+
+        /// <summary>
+        ///     TJsonProtocol Constructor
+        /// </summary>
+        public TJsonProtocol(TClientTransport trans)
+            : base(trans)
+        {
+            //throw new NotImplementedException("TJsonProtocol is not fully ready for usage");
+
+            Context = new JsonBaseContext(this);
+            Reader = new LookaheadReader(this);
+        }
+
+        private static byte[] GetTypeNameForTypeId(TType typeId)
+        {
+            switch (typeId)
+            {
+                case TType.Bool:
+                    return NameBool;
+                case TType.Byte:
+                    return NameByte;
+                case TType.I16:
+                    return NameI16;
+                case TType.I32:
+                    return NameI32;
+                case TType.I64:
+                    return NameI64;
+                case TType.Double:
+                    return NameDouble;
+                case TType.String:
+                    return NameString;
+                case TType.Struct:
+                    return NameStruct;
+                case TType.Map:
+                    return NameMap;
+                case TType.Set:
+                    return NameSet;
+                case TType.List:
+                    return NameList;
+                default:
+                    throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType");
+            }
+        }
+
+        private static TType GetTypeIdForTypeName(byte[] name)
+        {
+            var 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 exType");
+            }
+            return result;
+        }
+
+        /// <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>
+        ///     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 async Task ReadJsonSyntaxCharAsync(byte[] b, CancellationToken cancellationToken)
+        {
+            var ch = await Reader.ReadAsync(cancellationToken);
+            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');
+            }
+
+            if ((ch >= 'a') && (ch <= 'f'))
+            {
+                ch += 10;
+                return (byte) ((char) ch - 'a');
+            }
+
+            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');
+            }
+            val -= 10;
+            return (byte) ((char) val + 'a');
+        }
+
+        /// <summary>
+        ///     Write the bytes in array buf as a JSON characters, escaping as needed
+        /// </summary>
+        private async Task WriteJsonStringAsync(byte[] b, CancellationToken cancellationToken)
+        {
+            await Context.WriteAsync(cancellationToken);
+            await Trans.WriteAsync(Quote, cancellationToken);
+
+            var len = b.Length;
+            for (var i = 0; i < len; i++)
+            {
+                if ((b[i] & 0x00FF) >= 0x30)
+                {
+                    if (b[i] == Backslash[0])
+                    {
+                        await Trans.WriteAsync(Backslash, cancellationToken);
+                        await Trans.WriteAsync(Backslash, cancellationToken);
+                    }
+                    else
+                    {
+                        await Trans.WriteAsync(b, i, 1, cancellationToken);
+                    }
+                }
+                else
+                {
+                    _tempBuffer[0] = _jsonCharTable[b[i]];
+                    if (_tempBuffer[0] == 1)
+                    {
+                        await Trans.WriteAsync(b, i, 1, cancellationToken);
+                    }
+                    else if (_tempBuffer[0] > 1)
+                    {
+                        await Trans.WriteAsync(Backslash, cancellationToken);
+                        await Trans.WriteAsync(_tempBuffer, 0, 1, cancellationToken);
+                    }
+                    else
+                    {
+                        await Trans.WriteAsync(_escseq, cancellationToken);
+                        _tempBuffer[0] = HexChar((byte) (b[i] >> 4));
+                        _tempBuffer[1] = HexChar(b[i]);
+                        await Trans.WriteAsync(_tempBuffer, 0, 2, cancellationToken);
+                    }
+                }
+            }
+            await Trans.WriteAsync(Quote, cancellationToken);
+        }
+
+        /// <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 async Task WriteJsonIntegerAsync(long num, CancellationToken cancellationToken)
+        {
+            await Context.WriteAsync(cancellationToken);
+            var str = num.ToString();
+
+            var escapeNum = Context.EscapeNumbers();
+            if (escapeNum)
+            {
+                await Trans.WriteAsync(Quote, cancellationToken);
+            }
+
+            await Trans.WriteAsync(Utf8Encoding.GetBytes(str), cancellationToken);
+
+            if (escapeNum)
+            {
+                await Trans.WriteAsync(Quote, cancellationToken);
+            }
+        }
+
+        /// <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 async Task WriteJsonDoubleAsync(double num, CancellationToken cancellationToken)
+        {
+            await Context.WriteAsync(cancellationToken);
+            var str = num.ToString("G17", CultureInfo.InvariantCulture);
+            var special = false;
+
+            switch (str[0])
+            {
+                case 'N': // NaN
+                case 'I': // Infinity
+                    special = true;
+                    break;
+                case '-':
+                    if (str[1] == 'I')
+                    {
+                        // -Infinity
+                        special = true;
+                    }
+                    break;
+            }
+
+            var escapeNum = special || Context.EscapeNumbers();
+
+            if (escapeNum)
+            {
+                await Trans.WriteAsync(Quote, cancellationToken);
+            }
+
+            await Trans.WriteAsync(Utf8Encoding.GetBytes(str), cancellationToken);
+
+            if (escapeNum)
+            {
+                await Trans.WriteAsync(Quote, cancellationToken);
+            }
+        }
+
+        /// <summary>
+        ///     Write out contents of byte array b as a JSON string with base-64 encoded
+        ///     data
+        /// </summary>
+        private async Task WriteJsonBase64Async(byte[] b, CancellationToken cancellationToken)
+        {
+            await Context.WriteAsync(cancellationToken);
+            await Trans.WriteAsync(Quote, cancellationToken);
+
+            var len = b.Length;
+            var off = 0;
+
+            // Ignore padding
+            var bound = len >= 2 ? len - 2 : 0;
+
+            for (var i = len - 1; i >= bound && b[i] == '='; --i)
+            {
+                --len;
+            }
+
+            while (len >= 3)
+            {
+                // Encode 3 bytes at a time
+                TBase64Utils.Encode(b, off, 3, _tempBuffer, 0);
+                await Trans.WriteAsync(_tempBuffer, 0, 4, cancellationToken);
+                off += 3;
+                len -= 3;
+            }
+
+            if (len > 0)
+            {
+                // Encode remainder
+                TBase64Utils.Encode(b, off, len, _tempBuffer, 0);
+                await Trans.WriteAsync(_tempBuffer, 0, len + 1, cancellationToken);
+            }
+
+            await Trans.WriteAsync(Quote, cancellationToken);
+        }
+
+        private async Task WriteJsonObjectStartAsync(CancellationToken cancellationToken)
+        {
+            await Context.WriteAsync(cancellationToken);
+            await Trans.WriteAsync(Lbrace, cancellationToken);
+            PushContext(new JsonPairContext(this));
+        }
+
+        private async Task WriteJsonObjectEndAsync(CancellationToken cancellationToken)
+        {
+            PopContext();
+            await Trans.WriteAsync(Rbrace, cancellationToken);
+        }
+
+        private async Task WriteJsonArrayStartAsync(CancellationToken cancellationToken)
+        {
+            await Context.WriteAsync(cancellationToken);
+            await Trans.WriteAsync(Lbracket, cancellationToken);
+            PushContext(new JsonListContext(this));
+        }
+
+        private async Task WriteJsonArrayEndAsync(CancellationToken cancellationToken)
+        {
+            PopContext();
+            await Trans.WriteAsync(Rbracket, cancellationToken);
+        }
+
+        public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayStartAsync(cancellationToken);
+            await WriteJsonIntegerAsync(Version, cancellationToken);
+
+            var b = Utf8Encoding.GetBytes(message.Name);
+            await WriteJsonStringAsync(b, cancellationToken);
+
+            await WriteJsonIntegerAsync((long) message.Type, cancellationToken);
+            await WriteJsonIntegerAsync(message.SeqID, cancellationToken);
+        }
+
+        public override async Task WriteMessageEndAsync(CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteStructBeginAsync(TStruct struc, CancellationToken cancellationToken)
+        {
+            await WriteJsonObjectStartAsync(cancellationToken);
+        }
+
+        public override async Task WriteStructEndAsync(CancellationToken cancellationToken)
+        {
+            await WriteJsonObjectEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken)
+        {
+            await WriteJsonIntegerAsync(field.ID, cancellationToken);
+            await WriteJsonObjectStartAsync(cancellationToken);
+            await WriteJsonStringAsync(GetTypeNameForTypeId(field.Type), cancellationToken);
+        }
+
+        public override async Task WriteFieldEndAsync(CancellationToken cancellationToken)
+        {
+            await WriteJsonObjectEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteFieldStopAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayStartAsync(cancellationToken);
+            await WriteJsonStringAsync(GetTypeNameForTypeId(map.KeyType), cancellationToken);
+            await WriteJsonStringAsync(GetTypeNameForTypeId(map.ValueType), cancellationToken);
+            await WriteJsonIntegerAsync(map.Count, cancellationToken);
+            await WriteJsonObjectStartAsync(cancellationToken);
+        }
+
+        public override async Task WriteMapEndAsync(CancellationToken cancellationToken)
+        {
+            await WriteJsonObjectEndAsync(cancellationToken);
+            await WriteJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayStartAsync(cancellationToken);
+            await WriteJsonStringAsync(GetTypeNameForTypeId(list.ElementType), cancellationToken);
+            await WriteJsonIntegerAsync(list.Count, cancellationToken);
+        }
+
+        public override async Task WriteListEndAsync(CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayStartAsync(cancellationToken);
+            await WriteJsonStringAsync(GetTypeNameForTypeId(set.ElementType), cancellationToken);
+            await WriteJsonIntegerAsync(set.Count, cancellationToken);
+        }
+
+        public override async Task WriteSetEndAsync(CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken)
+        {
+            await WriteJsonIntegerAsync(b ? 1 : 0, cancellationToken);
+        }
+
+        public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken)
+        {
+            await WriteJsonIntegerAsync(b, cancellationToken);
+        }
+
+        public override async Task WriteI16Async(short i16, CancellationToken cancellationToken)
+        {
+            await WriteJsonIntegerAsync(i16, cancellationToken);
+        }
+
+        public override async Task WriteI32Async(int i32, CancellationToken cancellationToken)
+        {
+            await WriteJsonIntegerAsync(i32, cancellationToken);
+        }
+
+        public override async Task WriteI64Async(long i64, CancellationToken cancellationToken)
+        {
+            await WriteJsonIntegerAsync(i64, cancellationToken);
+        }
+
+        public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken)
+        {
+            await WriteJsonDoubleAsync(d, cancellationToken);
+        }
+
+        public override async Task WriteStringAsync(string s, CancellationToken cancellationToken)
+        {
+            var b = Utf8Encoding.GetBytes(s);
+            await WriteJsonStringAsync(b, cancellationToken);
+        }
+
+        public override async Task WriteBinaryAsync(byte[] b, CancellationToken cancellationToken)
+        {
+            await WriteJsonBase64Async(b, cancellationToken);
+        }
+
+        /// <summary>
+        ///     Read in a JSON string, unescaping as appropriate.. Skip Reading from the
+        ///     context if skipContext is true.
+        /// </summary>
+        private async Task<byte[]> ReadJsonStringAsync(bool skipContext, CancellationToken cancellationToken)
+        {
+            using (var buffer = new MemoryStream())
+            {
+                var codeunits = new List<char>();
+
+
+                if (!skipContext)
+                {
+                    await Context.ReadAsync(cancellationToken);
+                }
+
+                await ReadJsonSyntaxCharAsync(Quote, cancellationToken);
+
+                while (true)
+                {
+                    var ch = await Reader.ReadAsync(cancellationToken);
+                    if (ch == Quote[0])
+                    {
+                        break;
+                    }
+
+                    // escaped?
+                    if (ch != _escseq[0])
+                    {
+                        await buffer.WriteAsync(new[] {ch}, 0, 1, cancellationToken);
+                        continue;
+                    }
+
+                    // distinguish between \uXXXX and \?
+                    ch = await Reader.ReadAsync(cancellationToken);
+                    if (ch != _escseq[1]) // control chars like \n
+                    {
+                        var off = Array.IndexOf(_escapeChars, (char) ch);
+                        if (off == -1)
+                        {
+                            throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected control char");
+                        }
+                        ch = _escapeCharVals[off];
+                        await buffer.WriteAsync(new[] {ch}, 0, 1, cancellationToken);
+                        continue;
+                    }
+
+
+                    // it's \uXXXX
+                    await Trans.ReadAllAsync(_tempBuffer, 0, 4, cancellationToken);
+
+                    var wch = (short) ((HexVal(_tempBuffer[0]) << 12) +
+                                       (HexVal(_tempBuffer[1]) << 8) +
+                                       (HexVal(_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());
+                        await buffer.WriteAsync(tmp, 0, tmp.Length, cancellationToken);
+                        codeunits.Clear();
+                    }
+                    else
+                    {
+                        var tmp = Utf8Encoding.GetBytes(new[] {(char) wch});
+                        await buffer.WriteAsync(tmp, 0, tmp.Length, cancellationToken);
+                    }
+                }
+
+                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 static 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 async Task<string> ReadJsonNumericCharsAsync(CancellationToken cancellationToken)
+        {
+            var strbld = new StringBuilder();
+            while (true)
+            {
+                var ch = await Reader.PeekAsync(cancellationToken);
+                if (!IsJsonNumeric(ch))
+                {
+                    break;
+                }
+                strbld.Append((char) await Reader.ReadAsync(cancellationToken));
+            }
+            return strbld.ToString();
+        }
+
+        /// <summary>
+        ///     Read in a JSON number. If the context dictates, Read in enclosing quotes.
+        /// </summary>
+        private async Task<long> ReadJsonIntegerAsync(CancellationToken cancellationToken)
+        {
+            await Context.ReadAsync(cancellationToken);
+            if (Context.EscapeNumbers())
+            {
+                await ReadJsonSyntaxCharAsync(Quote, cancellationToken);
+            }
+
+            var str = await ReadJsonNumericCharsAsync(cancellationToken);
+            if (Context.EscapeNumbers())
+            {
+                await ReadJsonSyntaxCharAsync(Quote, cancellationToken);
+            }
+
+            try
+            {
+                return long.Parse(str);
+            }
+            catch (FormatException)
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA, "Bad data encounted in numeric data");
+            }
+        }
+
+        /// <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 async Task<double> ReadJsonDoubleAsync(CancellationToken cancellationToken)
+        {
+            await Context.ReadAsync(cancellationToken);
+            if (await Reader.PeekAsync(cancellationToken) == Quote[0])
+            {
+                var arr = await ReadJsonStringAsync(true, cancellationToken);
+                var 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;
+            }
+
+            if (Context.EscapeNumbers())
+            {
+                // This will throw - we should have had a quote if escapeNum == true
+                await ReadJsonSyntaxCharAsync(Quote, cancellationToken);
+            }
+
+            try
+            {
+                return double.Parse(await ReadJsonNumericCharsAsync(cancellationToken), CultureInfo.InvariantCulture);
+            }
+            catch (FormatException)
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA, "Bad data encounted in numeric data");
+            }
+        }
+
+        /// <summary>
+        ///     Read in a JSON string containing base-64 encoded data and decode it.
+        /// </summary>
+        private async Task<byte[]> ReadJsonBase64Async(CancellationToken cancellationToken)
+        {
+            var b = await ReadJsonStringAsync(false, cancellationToken);
+            var len = b.Length;
+            var off = 0;
+            var 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 exType)
+            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?)
+            var result = new byte[size];
+            Array.Copy(b, 0, result, 0, size);
+            return result;
+        }
+
+        private async Task ReadJsonObjectStartAsync(CancellationToken cancellationToken)
+        {
+            await Context.ReadAsync(cancellationToken);
+            await ReadJsonSyntaxCharAsync(Lbrace, cancellationToken);
+            PushContext(new JsonPairContext(this));
+        }
+
+        private async Task ReadJsonObjectEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonSyntaxCharAsync(Rbrace, cancellationToken);
+            PopContext();
+        }
+
+        private async Task ReadJsonArrayStartAsync(CancellationToken cancellationToken)
+        {
+            await Context.ReadAsync(cancellationToken);
+            await ReadJsonSyntaxCharAsync(Lbracket, cancellationToken);
+            PushContext(new JsonListContext(this));
+        }
+
+        private async Task ReadJsonArrayEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonSyntaxCharAsync(Rbracket, cancellationToken);
+            PopContext();
+        }
+
+        public override async Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
+        {
+            var message = new TMessage();
+            await ReadJsonArrayStartAsync(cancellationToken);
+            if (await ReadJsonIntegerAsync(cancellationToken) != Version)
+            {
+                throw new TProtocolException(TProtocolException.BAD_VERSION, "Message contained bad version.");
+            }
+
+            var buf = await ReadJsonStringAsync(false, cancellationToken);
+            message.Name = Utf8Encoding.GetString(buf, 0, buf.Length);
+            message.Type = (TMessageType) await ReadJsonIntegerAsync(cancellationToken);
+            message.SeqID = (int) await ReadJsonIntegerAsync(cancellationToken);
+            return message;
+        }
+
+        public override async Task ReadMessageEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonObjectStartAsync(cancellationToken);
+            return new TStruct();
+        }
+
+        public override async Task ReadStructEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonObjectEndAsync(cancellationToken);
+        }
+
+        public override async Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
+        {
+            var field = new TField();
+            var ch = await Reader.PeekAsync(cancellationToken);
+            if (ch == Rbrace[0])
+            {
+                field.Type = TType.Stop;
+            }
+            else
+            {
+                field.ID = (short) await ReadJsonIntegerAsync(cancellationToken);
+                await ReadJsonObjectStartAsync(cancellationToken);
+                field.Type = GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken));
+            }
+            return field;
+        }
+
+        public override async Task ReadFieldEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonObjectEndAsync(cancellationToken);
+        }
+
+        public override async Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
+        {
+            var map = new TMap();
+            await ReadJsonArrayStartAsync(cancellationToken);
+            map.KeyType = GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken));
+            map.ValueType = GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken));
+            map.Count = (int) await ReadJsonIntegerAsync(cancellationToken);
+            await ReadJsonObjectStartAsync(cancellationToken);
+            return map;
+        }
+
+        public override async Task ReadMapEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonObjectEndAsync(cancellationToken);
+            await ReadJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task<TList> ReadListBeginAsync(CancellationToken cancellationToken)
+        {
+            var list = new TList();
+            await ReadJsonArrayStartAsync(cancellationToken);
+            list.ElementType = GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken));
+            list.Count = (int) await ReadJsonIntegerAsync(cancellationToken);
+            return list;
+        }
+
+        public override async Task ReadListEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
+        {
+            var set = new TSet();
+            await ReadJsonArrayStartAsync(cancellationToken);
+            set.ElementType = GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken));
+            set.Count = (int) await ReadJsonIntegerAsync(cancellationToken);
+            return set;
+        }
+
+        public override async Task ReadSetEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task<bool> ReadBoolAsync(CancellationToken cancellationToken)
+        {
+            return await ReadJsonIntegerAsync(cancellationToken) != 0;
+        }
+
+        public override async Task<sbyte> ReadByteAsync(CancellationToken cancellationToken)
+        {
+            return (sbyte) await ReadJsonIntegerAsync(cancellationToken);
+        }
+
+        public override async Task<short> ReadI16Async(CancellationToken cancellationToken)
+        {
+            return (short) await ReadJsonIntegerAsync(cancellationToken);
+        }
+
+        public override async Task<int> ReadI32Async(CancellationToken cancellationToken)
+        {
+            return (int) await ReadJsonIntegerAsync(cancellationToken);
+        }
+
+        public override async Task<long> ReadI64Async(CancellationToken cancellationToken)
+        {
+            return await ReadJsonIntegerAsync(cancellationToken);
+        }
+
+        public override async Task<double> ReadDoubleAsync(CancellationToken cancellationToken)
+        {
+            return await ReadJsonDoubleAsync(cancellationToken);
+        }
+
+        public override async Task<string> ReadStringAsync(CancellationToken cancellationToken)
+        {
+            var buf = await ReadJsonStringAsync(false, cancellationToken);
+            return Utf8Encoding.GetString(buf, 0, buf.Length);
+        }
+
+        public override async Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
+        {
+            return await ReadJsonBase64Async(cancellationToken);
+        }
+
+        /// <summary>
+        ///     Factory for JSON protocol objects
+        /// </summary>
+        public class Factory : ITProtocolFactory
+        {
+            public TProtocol GetProtocol(TClientTransport trans)
+            {
+                return new TJsonProtocol(trans);
+            }
+        }
+
+        /// <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)
+            {
+                Proto = proto;
+            }
+
+            public virtual async Task WriteAsync(CancellationToken cancellationToken)
+            {
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    await Task.FromCanceled(cancellationToken);
+                }
+            }
+
+            public virtual async Task ReadAsync(CancellationToken cancellationToken)
+            {
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    await Task.FromCanceled(cancellationToken);
+                }
+            }
+
+            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
+        {
+            private bool _first = true;
+
+            public JsonListContext(TJsonProtocol protocol)
+                : base(protocol)
+            {
+            }
+
+            public override async Task WriteAsync(CancellationToken cancellationToken)
+            {
+                if (_first)
+                {
+                    _first = false;
+                }
+                else
+                {
+                    await Proto.Trans.WriteAsync(Comma, cancellationToken);
+                }
+            }
+
+            public override async Task ReadAsync(CancellationToken cancellationToken)
+            {
+                if (_first)
+                {
+                    _first = false;
+                }
+                else
+                {
+                    await Proto.ReadJsonSyntaxCharAsync(Comma, cancellationToken);
+                }
+            }
+        }
+
+        /// <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
+        {
+            private bool _colon = true;
+
+            private bool _first = true;
+
+            public JsonPairContext(TJsonProtocol proto)
+                : base(proto)
+            {
+            }
+
+            public override async Task WriteAsync(CancellationToken cancellationToken)
+            {
+                if (_first)
+                {
+                    _first = false;
+                    _colon = true;
+                }
+                else
+                {
+                    await Proto.Trans.WriteAsync(_colon ? Colon : Comma, cancellationToken);
+                    _colon = !_colon;
+                }
+            }
+
+            public override async Task ReadAsync(CancellationToken cancellationToken)
+            {
+                if (_first)
+                {
+                    _first = false;
+                    _colon = true;
+                }
+                else
+                {
+                    await Proto.ReadJsonSyntaxCharAsync(_colon ? Colon : Comma, cancellationToken);
+                    _colon = !_colon;
+                }
+            }
+
+            public override bool EscapeNumbers()
+            {
+                return _colon;
+            }
+        }
+
+        /// <summary>
+        ///     Holds up to one byte from the transport
+        /// </summary>
+        protected class LookaheadReader
+        {
+            private readonly byte[] _data = new byte[1];
+
+            private bool _hasData;
+            protected TJsonProtocol Proto;
+
+            public LookaheadReader(TJsonProtocol proto)
+            {
+                Proto = proto;
+            }
+
+            /// <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 async Task<byte> ReadAsync(CancellationToken cancellationToken)
+            {
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    return await Task.FromCanceled<byte>(cancellationToken);
+                }
+
+                if (_hasData)
+                {
+                    _hasData = false;
+                }
+                else
+                {
+                    await Proto.Trans.ReadAllAsync(_data, 0, 1, cancellationToken);
+                }
+                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 async Task<byte> PeekAsync(CancellationToken cancellationToken)
+            {
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    return await Task.FromCanceled<byte>(cancellationToken);
+                }
+
+                if (!_hasData)
+                {
+                    await Proto.Trans.ReadAllAsync(_data, 0, 1, cancellationToken);
+                }
+                _hasData = true;
+                return _data[0];
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/b587a12a/lib/netcore/Thrift/Protocols/TMultiplexedProtocol.cs
----------------------------------------------------------------------
diff --git a/lib/netcore/Thrift/Protocols/TMultiplexedProtocol.cs b/lib/netcore/Thrift/Protocols/TMultiplexedProtocol.cs
new file mode 100644
index 0000000..5b2202e
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TMultiplexedProtocol.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.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols.Entities;
+
+namespace Thrift.Protocols
+{
+    /**
+    * 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.
+    *
+    * NOTE: THIS IS NOT TO BE USED BY SERVERS.
+    * On the server, use TMultiplexedProcessor to handle requests from a multiplexing client.
+    *
+    * This example uses a single socket transport to invoke two services:
+    *
+    *     TSocketClientTransport transport = new TSocketClientTransport("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());
+    *
+    */
+
+    //TODO: implementation of TProtocol
+
+    // ReSharper disable once InconsistentNaming
+    public class TMultiplexedProtocol : TProtocolDecorator
+    {
+        /** Used to delimit the service name from the function name */
+        public const string Separator = ":";
+
+        private readonly string _serviceName;
+
+        /**
+         * Wrap the specified protocol, allowing it to be used to communicate with a
+         * multiplexing server.  The <code>serviceName</code> is required as it is
+         * prepended to the message header so that the multiplexing server can broker
+         * the function call to the proper service.
+         *
+         * Args:
+         *  protocol        Your communication protocol of choice, e.g. TBinaryProtocol
+         *  serviceName     The service name of the service communicating via this protocol.
+         */
+
+        public TMultiplexedProtocol(TProtocol protocol, string serviceName)
+            : base(protocol)
+        {
+            _serviceName = serviceName;
+        }
+
+        /**
+         * Prepends the service name to the function name, separated by TMultiplexedProtocol.SEPARATOR.
+         * Args:
+         *   tMessage     The original message.
+         */
+
+        public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
+        {
+            switch (message.Type)
+            {
+                case TMessageType.Call:
+                case TMessageType.Oneway:
+                    await
+                        base.WriteMessageBeginAsync(
+                            new TMessage($"{_serviceName}{Separator}{message.Name}", message.Type, message.SeqID),
+                            cancellationToken);
+                    break;
+                default:
+                    await base.WriteMessageBeginAsync(message, cancellationToken);
+                    break;
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/b587a12a/lib/netcore/Thrift/Protocols/TProtocol.cs
----------------------------------------------------------------------
diff --git a/lib/netcore/Thrift/Protocols/TProtocol.cs b/lib/netcore/Thrift/Protocols/TProtocol.cs
new file mode 100644
index 0000000..8fef861
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TProtocol.cs
@@ -0,0 +1,377 @@
+// 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.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols.Entities;
+using Thrift.Transports;
+
+namespace Thrift.Protocols
+{
+    // ReSharper disable once InconsistentNaming
+    public abstract class TProtocol : IDisposable
+    {
+        private const int DefaultRecursionDepth = 64;
+        private bool _isDisposed;
+        protected int RecursionDepth;
+
+        protected TClientTransport Trans;
+
+        protected TProtocol(TClientTransport trans)
+        {
+            Trans = trans;
+            RecursionLimit = DefaultRecursionDepth;
+            RecursionDepth = 0;
+        }
+
+        public TClientTransport Transport => Trans;
+
+        //TODO: check for protected
+        protected int RecursionLimit { get; set; }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        public void IncrementRecursionDepth()
+        {
+            if (RecursionDepth < RecursionLimit)
+            {
+                ++RecursionDepth;
+            }
+            else
+            {
+                throw new TProtocolException(TProtocolException.DEPTH_LIMIT, "Depth limit exceeded");
+            }
+        }
+
+        public void DecrementRecursionDepth()
+        {
+            --RecursionDepth;
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_isDisposed)
+            {
+                if (disposing)
+                {
+                    (Trans as IDisposable)?.Dispose();
+                }
+            }
+            _isDisposed = true;
+        }
+
+        public virtual async Task WriteMessageBeginAsync(TMessage message)
+        {
+            await WriteMessageBeginAsync(message, CancellationToken.None);
+        }
+
+        public abstract Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken);
+
+        public virtual async Task WriteMessageEndAsync()
+        {
+            await WriteMessageEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteMessageEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteStructBeginAsync(TStruct struc)
+        {
+            await WriteStructBeginAsync(struc, CancellationToken.None);
+        }
+
+        public abstract Task WriteStructBeginAsync(TStruct struc, CancellationToken cancellationToken);
+
+        public virtual async Task WriteStructEndAsync()
+        {
+            await WriteStructEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteStructEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteFieldBeginAsync(TField field)
+        {
+            await WriteFieldBeginAsync(field, CancellationToken.None);
+        }
+
+        public abstract Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken);
+
+        public virtual async Task WriteFieldEndAsync()
+        {
+            await WriteFieldEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteFieldEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteFieldStopAsync()
+        {
+            await WriteFieldStopAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteFieldStopAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteMapBeginAsync(TMap map)
+        {
+            await WriteMapBeginAsync(map, CancellationToken.None);
+        }
+
+        public abstract Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken);
+
+        public virtual async Task WriteMapEndAsync()
+        {
+            await WriteMapEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteMapEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteListBeginAsync(TList list)
+        {
+            await WriteListBeginAsync(list, CancellationToken.None);
+        }
+
+        public abstract Task WriteListBeginAsync(TList list, CancellationToken cancellationToken);
+
+        public virtual async Task WriteListEndAsync()
+        {
+            await WriteListEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteListEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteSetBeginAsync(TSet set)
+        {
+            await WriteSetBeginAsync(set, CancellationToken.None);
+        }
+
+        public abstract Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken);
+
+        public virtual async Task WriteSetEndAsync()
+        {
+            await WriteSetEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteSetEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteBoolAsync(bool b)
+        {
+            await WriteBoolAsync(b, CancellationToken.None);
+        }
+
+        public abstract Task WriteBoolAsync(bool b, CancellationToken cancellationToken);
+
+        public virtual async Task WriteByteAsync(sbyte b)
+        {
+            await WriteByteAsync(b, CancellationToken.None);
+        }
+
+        public abstract Task WriteByteAsync(sbyte b, CancellationToken cancellationToken);
+
+        public virtual async Task WriteI16Async(short i16)
+        {
+            await WriteI16Async(i16, CancellationToken.None);
+        }
+
+        public abstract Task WriteI16Async(short i16, CancellationToken cancellationToken);
+
+        public virtual async Task WriteI32Async(int i32)
+        {
+            await WriteI32Async(i32, CancellationToken.None);
+        }
+
+        public abstract Task WriteI32Async(int i32, CancellationToken cancellationToken);
+
+        public virtual async Task WriteI64Async(long i64)
+        {
+            await WriteI64Async(i64, CancellationToken.None);
+        }
+
+        public abstract Task WriteI64Async(long i64, CancellationToken cancellationToken);
+
+        public virtual async Task WriteDoubleAsync(double d)
+        {
+            await WriteDoubleAsync(d, CancellationToken.None);
+        }
+
+        public abstract Task WriteDoubleAsync(double d, CancellationToken cancellationToken);
+
+        public virtual async Task WriteStringAsync(string s)
+        {
+            await WriteStringAsync(s, CancellationToken.None);
+        }
+
+        public virtual async Task WriteStringAsync(string s, CancellationToken cancellationToken)
+        {
+            var bytes = Encoding.UTF8.GetBytes(s);
+            await WriteBinaryAsync(bytes, cancellationToken);
+        }
+
+        public virtual async Task WriteBinaryAsync(byte[] b)
+        {
+            await WriteBinaryAsync(b, CancellationToken.None);
+        }
+
+        public abstract Task WriteBinaryAsync(byte[] b, CancellationToken cancellationToken);
+
+        public virtual async Task<TMessage> ReadMessageBeginAsync()
+        {
+            return await ReadMessageBeginAsync(CancellationToken.None);
+        }
+
+        public abstract Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken);
+
+        public virtual async Task ReadMessageEndAsync()
+        {
+            await ReadMessageEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task ReadMessageEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<TStruct> ReadStructBeginAsync()
+        {
+            return await ReadStructBeginAsync(CancellationToken.None);
+        }
+
+        public abstract Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken);
+
+        public virtual async Task ReadStructEndAsync()
+        {
+            await ReadStructEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task ReadStructEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<TField> ReadFieldBeginAsync()
+        {
+            return await ReadFieldBeginAsync(CancellationToken.None);
+        }
+
+        public abstract Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken);
+
+        public virtual async Task ReadFieldEndAsync()
+        {
+            await ReadFieldEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task ReadFieldEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<TMap> ReadMapBeginAsync()
+        {
+            return await ReadMapBeginAsync(CancellationToken.None);
+        }
+
+        public abstract Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken);
+
+        public virtual async Task ReadMapEndAsync()
+        {
+            await ReadMapEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task ReadMapEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<TList> ReadListBeginAsync()
+        {
+            return await ReadListBeginAsync(CancellationToken.None);
+        }
+
+        public abstract Task<TList> ReadListBeginAsync(CancellationToken cancellationToken);
+
+        public virtual async Task ReadListEndAsync()
+        {
+            await ReadListEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task ReadListEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<TSet> ReadSetBeginAsync()
+        {
+            return await ReadSetBeginAsync(CancellationToken.None);
+        }
+
+        public abstract Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken);
+
+        public virtual async Task ReadSetEndAsync()
+        {
+            await ReadSetEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task ReadSetEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<bool> ReadBoolAsync()
+        {
+            return await ReadBoolAsync(CancellationToken.None);
+        }
+
+        public abstract Task<bool> ReadBoolAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<sbyte> ReadByteAsync()
+        {
+            return await ReadByteAsync(CancellationToken.None);
+        }
+
+        public abstract Task<sbyte> ReadByteAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<short> ReadI16Async()
+        {
+            return await ReadI16Async(CancellationToken.None);
+        }
+
+        public abstract Task<short> ReadI16Async(CancellationToken cancellationToken);
+
+        public virtual async Task<int> ReadI32Async()
+        {
+            return await ReadI32Async(CancellationToken.None);
+        }
+
+        public abstract Task<int> ReadI32Async(CancellationToken cancellationToken);
+
+        public virtual async Task<long> ReadI64Async()
+        {
+            return await ReadI64Async(CancellationToken.None);
+        }
+
+        public abstract Task<long> ReadI64Async(CancellationToken cancellationToken);
+
+        public virtual async Task<double> ReadDoubleAsync()
+        {
+            return await ReadDoubleAsync(CancellationToken.None);
+        }
+
+        public abstract Task<double> ReadDoubleAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<string> ReadStringAsync()
+        {
+            return await ReadStringAsync(CancellationToken.None);
+        }
+
+        public virtual async Task<string> ReadStringAsync(CancellationToken cancellationToken)
+        {
+            var buf = await ReadBinaryAsync(cancellationToken);
+            return Encoding.UTF8.GetString(buf, 0, buf.Length);
+        }
+
+        public virtual async Task<byte[]> ReadBinaryAsync()
+        {
+            return await ReadBinaryAsync(CancellationToken.None);
+        }
+
+        public abstract Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/b587a12a/lib/netcore/Thrift/Protocols/TProtocolDecorator.cs
----------------------------------------------------------------------
diff --git a/lib/netcore/Thrift/Protocols/TProtocolDecorator.cs b/lib/netcore/Thrift/Protocols/TProtocolDecorator.cs
new file mode 100644
index 0000000..458b117
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TProtocolDecorator.cs
@@ -0,0 +1,252 @@
+// 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;
+using System.Threading.Tasks;
+using Thrift.Protocols.Entities;
+
+namespace Thrift.Protocols
+{
+    // ReSharper disable once InconsistentNaming
+    /// <summary>
+    ///     TProtocolDecorator forwards all requests to an enclosed 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 TProtocol.
+    /// </summary>
+    public abstract class TProtocolDecorator : TProtocol
+    {
+        private readonly TProtocol _wrappedProtocol;
+
+        protected TProtocolDecorator(TProtocol protocol)
+            : base(protocol.Transport)
+        {
+            if (protocol == null)
+            {
+                throw new ArgumentNullException(nameof(protocol));
+            }
+
+            _wrappedProtocol = protocol;
+        }
+
+        public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteMessageBeginAsync(message, cancellationToken);
+        }
+
+        public override async Task WriteMessageEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteMessageEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteStructBeginAsync(TStruct struc, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteStructBeginAsync(struc, cancellationToken);
+        }
+
+        public override async Task WriteStructEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteStructEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteFieldBeginAsync(field, cancellationToken);
+        }
+
+        public override async Task WriteFieldEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteFieldEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteFieldStopAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteFieldStopAsync(cancellationToken);
+        }
+
+        public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteMapBeginAsync(map, cancellationToken);
+        }
+
+        public override async Task WriteMapEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteMapEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteListBeginAsync(list, cancellationToken);
+        }
+
+        public override async Task WriteListEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteListEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteSetBeginAsync(set, cancellationToken);
+        }
+
+        public override async Task WriteSetEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteSetEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteBoolAsync(b, cancellationToken);
+        }
+
+        public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteByteAsync(b, cancellationToken);
+        }
+
+        public override async Task WriteI16Async(short i16, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteI16Async(i16, cancellationToken);
+        }
+
+        public override async Task WriteI32Async(int i32, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteI32Async(i32, cancellationToken);
+        }
+
+        public override async Task WriteI64Async(long i64, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteI64Async(i64, cancellationToken);
+        }
+
+        public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteDoubleAsync(d, cancellationToken);
+        }
+
+        public override async Task WriteStringAsync(string s, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteStringAsync(s, cancellationToken);
+        }
+
+        public override async Task WriteBinaryAsync(byte[] b, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteBinaryAsync(b, cancellationToken);
+        }
+
+        public override async Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadMessageBeginAsync(cancellationToken);
+        }
+
+        public override async Task ReadMessageEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.ReadMessageEndAsync(cancellationToken);
+        }
+
+        public override async Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadStructBeginAsync(cancellationToken);
+        }
+
+        public override async Task ReadStructEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.ReadStructEndAsync(cancellationToken);
+        }
+
+        public override async Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadFieldBeginAsync(cancellationToken);
+        }
+
+        public override async Task ReadFieldEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.ReadFieldEndAsync(cancellationToken);
+        }
+
+        public override async Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadMapBeginAsync(cancellationToken);
+        }
+
+        public override async Task ReadMapEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.ReadMapEndAsync(cancellationToken);
+        }
+
+        public override async Task<TList> ReadListBeginAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadListBeginAsync(cancellationToken);
+        }
+
+        public override async Task ReadListEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.ReadListEndAsync(cancellationToken);
+        }
+
+        public override async Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadSetBeginAsync(cancellationToken);
+        }
+
+        public override async Task ReadSetEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.ReadSetEndAsync(cancellationToken);
+        }
+
+        public override async Task<bool> ReadBoolAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadBoolAsync(cancellationToken);
+        }
+
+        public override async Task<sbyte> ReadByteAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadByteAsync(cancellationToken);
+        }
+
+        public override async Task<short> ReadI16Async(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadI16Async(cancellationToken);
+        }
+
+        public override async Task<int> ReadI32Async(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadI32Async(cancellationToken);
+        }
+
+        public override async Task<long> ReadI64Async(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadI64Async(cancellationToken);
+        }
+
+        public override async Task<double> ReadDoubleAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadDoubleAsync(cancellationToken);
+        }
+
+        public override async Task<string> ReadStringAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadStringAsync(cancellationToken);
+        }
+
+        public override async Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadBinaryAsync(cancellationToken);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/b587a12a/lib/netcore/Thrift/Protocols/TProtocolException.cs
----------------------------------------------------------------------
diff --git a/lib/netcore/Thrift/Protocols/TProtocolException.cs b/lib/netcore/Thrift/Protocols/TProtocolException.cs
new file mode 100644
index 0000000..02d0d3f
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TProtocolException.cs
@@ -0,0 +1,58 @@
+// 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.Protocols
+{
+    public class TProtocolException : TException
+    {
+        // do not rename public contants - they used in generated files
+        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()
+        {
+        }
+
+        public TProtocolException(int type)
+        {
+            Type = type;
+        }
+
+        public TProtocolException(int type, string message)
+            : base(message)
+        {
+            Type = type;
+        }
+
+        public TProtocolException(string message)
+            : base(message)
+        {
+        }
+
+        public int GetExceptionType()
+        {
+            return Type;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/b587a12a/lib/netcore/Thrift/Protocols/Utilities/TBase64Utils.cs
----------------------------------------------------------------------
diff --git a/lib/netcore/Thrift/Protocols/Utilities/TBase64Utils.cs b/lib/netcore/Thrift/Protocols/Utilities/TBase64Utils.cs
new file mode 100644
index 0000000..15fd45c
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Utilities/TBase64Utils.cs
@@ -0,0 +1,101 @@
+// 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.Protocols.Utilities
+{
+    // ReSharper disable once InconsistentNaming
+    internal static class TBase64Utils
+    {
+        //TODO: Constants
+        //TODO: Check for args
+        //TODO: Unitests
+
+        internal const string EncodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+        private static readonly int[] DecodeTable =
+        {
+            -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 Encode(byte[] src, int srcOff, int len, byte[] dst, int dstOff)
+        {
+            if (src == null)
+            {
+                throw new ArgumentNullException(nameof(src));
+            }
+
+            dst[dstOff] = (byte) EncodeTable[(src[srcOff] >> 2) & 0x3F];
+
+            if (len == 3)
+            {
+                dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+                dst[dstOff + 2] = (byte) EncodeTable[((src[srcOff + 1] << 2) & 0x3C) | ((src[srcOff + 2] >> 6) & 0x03)];
+                dst[dstOff + 3] = (byte) EncodeTable[src[srcOff + 2] & 0x3F];
+            }
+            else if (len == 2)
+            {
+                dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+                dst[dstOff + 2] = (byte) EncodeTable[(src[srcOff + 1] << 2) & 0x3C];
+            }
+            else
+            {
+                // len == 1
+                dst[dstOff + 1] = (byte) EncodeTable[(src[srcOff] << 4) & 0x30];
+            }
+        }
+
+        internal static void Decode(byte[] src, int srcOff, int len, byte[] dst, int dstOff)
+        {
+            if (src == null)
+            {
+                throw new ArgumentNullException(nameof(src));
+            }
+
+            dst[dstOff] = (byte) ((DecodeTable[src[srcOff] & 0x0FF] << 2) | (DecodeTable[src[srcOff + 1] & 0x0FF] >> 4));
+
+            if (len > 2)
+            {
+                dst[dstOff + 1] =
+                    (byte)
+                    (((DecodeTable[src[srcOff + 1] & 0x0FF] << 4) & 0xF0) | (DecodeTable[src[srcOff + 2] & 0x0FF] >> 2));
+                if (len > 3)
+                {
+                    dst[dstOff + 2] =
+                        (byte)
+                        (((DecodeTable[src[srcOff + 2] & 0x0FF] << 6) & 0xC0) | DecodeTable[src[srcOff + 3] & 0x0FF]);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/b587a12a/lib/netcore/Thrift/Protocols/Utilities/TProtocolUtil.cs
----------------------------------------------------------------------
diff --git a/lib/netcore/Thrift/Protocols/Utilities/TProtocolUtil.cs b/lib/netcore/Thrift/Protocols/Utilities/TProtocolUtil.cs
new file mode 100644
index 0000000..6232149
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Utilities/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.
+
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols.Entities;
+
+namespace Thrift.Protocols
+{
+    // ReSharper disable once InconsistentNaming
+    public static class TProtocolUtil
+    {
+        public static async Task SkipAsync(TProtocol prot, TType type, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+
+            prot.IncrementRecursionDepth();
+            try
+            {
+                switch (type)
+                {
+                    case TType.Bool:
+                        await prot.ReadBoolAsync(cancellationToken);
+                        break;
+                    case TType.Byte:
+                        await prot.ReadByteAsync(cancellationToken);
+                        break;
+                    case TType.I16:
+                        await prot.ReadI16Async(cancellationToken);
+                        break;
+                    case TType.I32:
+                        await prot.ReadI32Async(cancellationToken);
+                        break;
+                    case TType.I64:
+                        await prot.ReadI64Async(cancellationToken);
+                        break;
+                    case TType.Double:
+                        await prot.ReadDoubleAsync(cancellationToken);
+                        break;
+                    case TType.String:
+                        // Don't try to decode the string, just skip it.
+                        await prot.ReadBinaryAsync(cancellationToken);
+                        break;
+                    case TType.Struct:
+                        await prot.ReadStructBeginAsync(cancellationToken);
+                        while (true)
+                        {
+                            var field = await prot.ReadFieldBeginAsync(cancellationToken);
+                            if (field.Type == TType.Stop)
+                            {
+                                break;
+                            }
+                            await SkipAsync(prot, field.Type, cancellationToken);
+                            await prot.ReadFieldEndAsync(cancellationToken);
+                        }
+                        await prot.ReadStructEndAsync(cancellationToken);
+                        break;
+                    case TType.Map:
+                        var map = await prot.ReadMapBeginAsync(cancellationToken);
+                        for (var i = 0; i < map.Count; i++)
+                        {
+                            await SkipAsync(prot, map.KeyType, cancellationToken);
+                            await SkipAsync(prot, map.ValueType, cancellationToken);
+                        }
+                        await prot.ReadMapEndAsync(cancellationToken);
+                        break;
+                    case TType.Set:
+                        var set = await prot.ReadSetBeginAsync(cancellationToken);
+                        for (var i = 0; i < set.Count; i++)
+                        {
+                            await SkipAsync(prot, set.ElementType, cancellationToken);
+                        }
+                        await prot.ReadSetEndAsync(cancellationToken);
+                        break;
+                    case TType.List:
+                        var list = await prot.ReadListBeginAsync(cancellationToken);
+                        for (var i = 0; i < list.Count; i++)
+                        {
+                            await SkipAsync(prot, list.ElementType, cancellationToken);
+                        }
+                        await prot.ReadListEndAsync(cancellationToken);
+                        break;
+                }
+            }
+            finally
+            {
+                prot.DecrementRecursionDepth();
+            }
+        }
+    }
+}
\ No newline at end of file