revamp of c# channel options
diff --git a/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs b/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
new file mode 100644
index 0000000..ee846ea
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
@@ -0,0 +1,105 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Internal.Tests
+{
+    public class ChannelOptionsTest
+    {
+        [Test]
+        public void IntOption()
+        {
+            var option = new ChannelOption("somename", 1);
+
+            Assert.AreEqual(ChannelOption.OptionType.Integer, option.Type);
+            Assert.AreEqual("somename", option.Name);
+            Assert.AreEqual(1, option.IntValue);
+            Assert.Throws(typeof(InvalidOperationException), () => {var s = option.StringValue; });
+        }
+
+        [Test]
+        public void StringOption()
+        {
+            var option = new ChannelOption("somename", "ABCDEF");
+
+            Assert.AreEqual(ChannelOption.OptionType.String, option.Type);
+            Assert.AreEqual("somename", option.Name);
+            Assert.AreEqual("ABCDEF", option.StringValue);
+            Assert.Throws(typeof(InvalidOperationException), () => {var s = option.IntValue; });
+        }
+
+        [Test]
+        public void ConstructorPreconditions()
+        {
+            Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption(null, "abc"); });
+            Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption(null, 1); });
+            Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption("abc", null); });
+        }
+
+        [Test]
+        public void CreateChannelArgsNull()
+        {
+            var channelArgs = ChannelOptions.CreateChannelArgs(null);
+            Assert.IsTrue(channelArgs.IsInvalid);
+        }
+
+        [Test]
+        public void CreateChannelArgsEmpty()
+        {
+            var options = new List<ChannelOption>();
+            var channelArgs = ChannelOptions.CreateChannelArgs(options);
+            channelArgs.Dispose();
+        }
+
+        [Test]
+        public void CreateChannelArgs()
+        {
+            var options = new List<ChannelOption>
+            {
+                new ChannelOption("ABC", "XYZ"),
+                new ChannelOption("somename", "IJKLM"),
+                new ChannelOption("intoption", 12345),
+                new ChannelOption("GHIJK", 12345),
+            };
+
+            var channelArgs = ChannelOptions.CreateChannelArgs(options);
+            channelArgs.Dispose();
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 0296539..92e28b7 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -3,8 +3,6 @@
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>8.0.30703</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
     <ProjectGuid>{86EC5CB4-4EA2-40A2-8057-86542A0353BB}</ProjectGuid>
     <OutputType>Library</OutputType>
     <RootNamespace>Grpc.Core.Tests</RootNamespace>
@@ -48,6 +46,8 @@
     <Compile Include="Internal\MetadataArraySafeHandleTest.cs" />
     <Compile Include="Internal\CompletionQueueSafeHandleTest.cs" />
     <Compile Include="Internal\CompletionQueueEventTest.cs" />
+    <Compile Include="Internal\ChannelArgsSafeHandleTest.cs" />
+    <Compile Include="ChannelOptionsTest.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
@@ -63,4 +63,4 @@
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
   </ItemGroup>
   <ItemGroup />
-</Project>
\ No newline at end of file
+</Project>
diff --git a/src/csharp/Grpc.Core.Tests/Internal/ChannelArgsSafeHandleTest.cs b/src/csharp/Grpc.Core.Tests/Internal/ChannelArgsSafeHandleTest.cs
new file mode 100644
index 0000000..af0aaa5
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Internal/ChannelArgsSafeHandleTest.cs
@@ -0,0 +1,75 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Internal.Tests
+{
+    public class ChannelArgsSafeHandleTest
+    {
+        [Test]
+        public void CreateEmptyAndDestroy()
+        {
+            var channelArgs = ChannelArgsSafeHandle.Create(0);
+            channelArgs.Dispose();
+        }
+
+        [Test]
+        public void CreateNonEmptyAndDestroy()
+        {
+            var channelArgs = ChannelArgsSafeHandle.Create(5);
+            channelArgs.Dispose();
+        }
+
+        [Test]
+        public void CreateNullAndDestroy()
+        {
+            var channelArgs = ChannelArgsSafeHandle.CreateNull();
+            channelArgs.Dispose();
+        }
+
+        [Test]
+        public void CreateFillAndDestroy()
+        {
+            var channelArgs = ChannelArgsSafeHandle.Create(3);
+            channelArgs.SetInteger(0, "somekey", 12345);
+            channelArgs.SetString(1, "somekey", "abcdefghijkl");
+            channelArgs.SetString(2, "somekey", "XYZ");
+            channelArgs.Dispose();
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index 44b610f..d6bfbb7 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -29,6 +29,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endregion
 using System;
+using System.Collections.Generic;
 using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
@@ -50,10 +51,10 @@
         /// </summary>
         /// <param name="host">The DNS name of IP address of the host.</param>
         /// <param name="credentials">Optional credentials to create a secure channel.</param>
-        /// <param name="channelArgs">Optional channel arguments.</param>
-        public Channel(string host, Credentials credentials = null, ChannelArgs channelArgs = null)
+        /// <param name="options">Channel options.</param>
+        public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null)
         {
-            using (ChannelArgsSafeHandle nativeChannelArgs = CreateNativeChannelArgs(channelArgs))
+            using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(options))
             {
                 if (credentials != null)
                 {
@@ -67,7 +68,7 @@
                     this.handle = ChannelSafeHandle.Create(host, nativeChannelArgs);
                 }
             }
-            this.target = GetOverridenTarget(host, channelArgs);
+            this.target = GetOverridenTarget(host, options);
         }
 
         /// <summary>
@@ -76,9 +77,9 @@
         /// <param name="host">DNS name or IP address</param>
         /// <param name="port">the port</param>
         /// <param name="credentials">Optional credentials to create a secure channel.</param>
-        /// <param name="channelArgs">Optional channel arguments.</param>
-        public Channel(string host, int port, Credentials credentials = null, ChannelArgs channelArgs = null) :
-            this(string.Format("{0}:{1}", host, port), credentials, channelArgs)
+        /// <param name="options">Channel options.</param>
+        public Channel(string host, int port, Credentials credentials = null, IEnumerable<ChannelOption> options = null) :
+            this(string.Format("{0}:{1}", host, port), credentials, options)
         {
         }
 
@@ -112,22 +113,25 @@
             }
         }
 
-        private static string GetOverridenTarget(string target, ChannelArgs args)
+        /// <summary>
+        /// Look for SslTargetNameOverride option and return its value instead of originalTarget
+        /// if found.
+        /// </summary>
+        private static string GetOverridenTarget(string originalTarget, IEnumerable<ChannelOption> options)
         {
-            if (args != null && !string.IsNullOrEmpty(args.GetSslTargetNameOverride()))
+            if (options == null)
             {
-                return args.GetSslTargetNameOverride();
+                return originalTarget;
             }
-            return target;
-        }
-
-        private static ChannelArgsSafeHandle CreateNativeChannelArgs(ChannelArgs args)
-        {
-            if (args == null)
+            foreach (var option in options)
             {
-                return ChannelArgsSafeHandle.CreateNull();
+                if (option.Type == ChannelOption.OptionType.String
+                    && option.Name == ChannelOptions.SslTargetNameOverride)
+                {
+                    return option.StringValue;
+                }
             }
-            return args.ToNativeChannelArgs();
+            return originalTarget;
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/ChannelArgs.cs b/src/csharp/Grpc.Core/ChannelArgs.cs
deleted file mode 100644
index 74ab310..0000000
--- a/src/csharp/Grpc.Core/ChannelArgs.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-#region Copyright notice and license
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Grpc.Core.Internal;
-
-namespace Grpc.Core
-{
-    /// <summary>
-    /// gRPC channel options.
-    /// </summary>
-    public class ChannelArgs
-    {
-        public const string SslTargetNameOverrideKey = "grpc.ssl_target_name_override";
-
-        readonly ImmutableDictionary<string, string> stringArgs;
-
-        private ChannelArgs(ImmutableDictionary<string, string> stringArgs)
-        {
-            this.stringArgs = stringArgs;
-        }
-
-        public string GetSslTargetNameOverride()
-        {
-            string result;
-            if (stringArgs.TryGetValue(SslTargetNameOverrideKey, out result))
-            {
-                return result;
-            }
-            return null;
-        }
-
-        public static Builder CreateBuilder()
-        {
-            return new Builder();
-        }
-
-        public class Builder
-        {
-            readonly Dictionary<string, string> stringArgs = new Dictionary<string, string>();
-
-            // TODO: AddInteger not supported yet.
-            public Builder AddString(string key, string value)
-            {
-                stringArgs.Add(key, value);
-                return this;
-            }
-
-            public ChannelArgs Build()
-            {
-                return new ChannelArgs(stringArgs.ToImmutableDictionary());
-            }
-        }
-
-        /// <summary>
-        /// Creates native object for the channel arguments.
-        /// </summary>
-        /// <returns>The native channel arguments.</returns>
-        internal ChannelArgsSafeHandle ToNativeChannelArgs()
-        {
-            ChannelArgsSafeHandle nativeArgs = null;
-            try
-            {
-                nativeArgs = ChannelArgsSafeHandle.Create(stringArgs.Count);
-                int i = 0;
-                foreach (var entry in stringArgs)
-                {
-                    nativeArgs.SetString(i, entry.Key, entry.Value);
-                    i++;
-                }
-                return nativeArgs;
-            }
-            catch (Exception)
-            {
-                if (nativeArgs != null)
-                {
-                    nativeArgs.Dispose();
-                }
-                throw;
-            }
-        }
-    }
-}
diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs
new file mode 100644
index 0000000..4d37b39
--- /dev/null
+++ b/src/csharp/Grpc.Core/ChannelOptions.cs
@@ -0,0 +1,179 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+    /// <summary>
+    /// Channel option specified when creating a channel.
+    /// Corresponds to grpc_channel_args from grpc/grpc.h.
+    /// </summary>
+    public sealed class ChannelOption
+    {
+        public enum OptionType
+        {
+            Integer,
+            String
+        }
+
+        private readonly OptionType type;
+        private readonly string name;
+        private readonly int intValue;
+        private readonly string stringValue;
+
+        /// <summary>
+        /// Creates a channel option with a string value.
+        /// </summary>
+        /// <param name="name">Name.</param>
+        /// <param name="stringValue">String value.</param>
+        public ChannelOption(string name, string stringValue)
+        {
+            this.type = OptionType.String;
+            this.name = Preconditions.CheckNotNull(name);
+            this.stringValue = Preconditions.CheckNotNull(stringValue);
+        }
+
+        /// <summary>
+        /// Creates a channel option with an integer value.
+        /// </summary>
+        /// <param name="name">Name.</param>
+        /// <param name="stringValue">String value.</param>
+        public ChannelOption(string name, int intValue)
+        {
+            this.type = OptionType.Integer;
+            this.name = Preconditions.CheckNotNull(name);
+            this.intValue = intValue;
+        }
+
+        public OptionType Type
+        {
+            get
+            {
+                return type;
+            }
+        }
+
+        public string Name
+        {
+            get
+            {
+                return name;
+            }    
+        }
+
+        public int IntValue
+        {
+            get
+            {
+                Preconditions.CheckState(type == OptionType.Integer);
+                return intValue;
+            }
+        }
+
+        public string StringValue
+        {
+            get
+            {
+                Preconditions.CheckState(type == OptionType.String);
+                return stringValue;
+            }
+        }
+    }
+
+    public static class ChannelOptions
+    {
+        // Override SSL target check. Only to be used for testing.
+        public const string SslTargetNameOverride = "grpc.ssl_target_name_override";
+
+        // Enable census for tracing and stats collection
+        public const string Census = "grpc.census";
+
+        // Maximum number of concurrent incoming streams to allow on a http2 connection
+        public const string MaxConcurrentStreams = "grpc.max_concurrent_streams";
+
+        // Maximum message length that the channel can receive
+        public const string MaxMessageLength = "grpc.max_message_length";
+
+        // Initial sequence number for http2 transports
+        public const string Http2InitialSequenceNumber = "grpc.http2.initial_sequence_number";
+
+        /// <summary>
+        /// Creates native object for a collection of channel options.
+        /// </summary>
+        /// <returns>The native channel arguments.</returns>
+        internal static ChannelArgsSafeHandle CreateChannelArgs(IEnumerable<ChannelOption> options)
+        {
+            if (options == null)
+            {
+                return ChannelArgsSafeHandle.CreateNull();
+            }
+            var optionList = new List<ChannelOption>(options);  // It's better to do defensive copy
+            ChannelArgsSafeHandle nativeArgs = null;
+            try
+            {
+                nativeArgs = ChannelArgsSafeHandle.Create(optionList.Count);
+                for (int i = 0; i < optionList.Count; i++)
+                {
+                    var option = optionList[i];
+                    if (option.Type == ChannelOption.OptionType.Integer)
+                    {
+                        nativeArgs.SetInteger(i, option.Name, option.IntValue);
+                    }
+                    else if (option.Type == ChannelOption.OptionType.String)
+                    {
+                        nativeArgs.SetString(i, option.Name, option.StringValue);
+                    }
+                    else 
+                    {
+                        throw new InvalidOperationException("Unknown option type");
+                    }
+
+                }
+                return nativeArgs;
+            }
+            catch (Exception)
+            {
+                if (nativeArgs != null)
+                {
+                    nativeArgs.Dispose();
+                }
+                throw;
+            }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 5c7b9a8..a36a6a5 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -5,8 +5,6 @@
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>8.0.30703</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
     <ProjectGuid>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</ProjectGuid>
     <OutputType>Library</OutputType>
     <RootNamespace>Grpc.Core</RootNamespace>
@@ -78,7 +76,6 @@
     <Compile Include="Internal\CredentialsSafeHandle.cs" />
     <Compile Include="Credentials.cs" />
     <Compile Include="Internal\ChannelArgsSafeHandle.cs" />
-    <Compile Include="ChannelArgs.cs" />
     <Compile Include="Internal\AsyncCompletion.cs" />
     <Compile Include="Internal\AsyncCallBase.cs" />
     <Compile Include="Internal\AsyncCallServer.cs" />
@@ -103,6 +100,7 @@
     <Compile Include="Internal\CompletionQueueEvent.cs" />
     <Compile Include="Internal\CompletionRegistry.cs" />
     <Compile Include="Internal\BatchContextSafeHandle.cs" />
+    <Compile Include="ChannelOptions.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />
@@ -132,4 +130,4 @@
   </Target>
   <Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" />
   <Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" />
-</Project>
\ No newline at end of file
+</Project>
diff --git a/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs
index c69f1a0..c12aec5 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs
@@ -45,6 +45,9 @@
         [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
         static extern void grpcsharp_channel_args_set_string(ChannelArgsSafeHandle args, UIntPtr index, string key, string value);
 
+        [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
+        static extern void grpcsharp_channel_args_set_integer(ChannelArgsSafeHandle args, UIntPtr index, string key, int value);
+
         [DllImport("grpc_csharp_ext.dll")]
         static extern void grpcsharp_channel_args_destroy(IntPtr args);
 
@@ -67,6 +70,11 @@
             grpcsharp_channel_args_set_string(this, new UIntPtr((uint)index), key, value);
         }
 
+        public void SetInteger(int index, string key, int value)
+        {
+            grpcsharp_channel_args_set_integer(this, new UIntPtr((uint)index), key, value);
+        }
+
         protected override bool ReleaseHandle()
         {
             grpcsharp_channel_args_destroy(handle);
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 66171fa..faee5a8 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -110,14 +110,15 @@
                 credentials = TestCredentials.CreateTestClientCredentials(options.useTestCa);
             }
 
-            ChannelArgs channelArgs = null;
+            List<ChannelOption> channelOptions = null;
             if (!string.IsNullOrEmpty(options.serverHostOverride))
             {
-                channelArgs = ChannelArgs.CreateBuilder()
-                    .AddString(ChannelArgs.SslTargetNameOverrideKey, options.serverHostOverride).Build();
+                channelOptions = new List<ChannelOption> {
+                    new ChannelOption(ChannelOptions.SslTargetNameOverride, options.serverHostOverride)
+                };
             }
 
-            using (Channel channel = new Channel(options.serverHost, options.serverPort.Value, credentials, channelArgs))
+            using (Channel channel = new Channel(options.serverHost, options.serverPort.Value, credentials, channelOptions))
             {
                 var stubConfig = StubConfiguration.Default;
                 if (options.testCase == "service_account_creds" || options.testCase == "compute_engine_creds")
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
index f756dfb..33628ce 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
@@ -62,10 +62,10 @@
             int port = server.AddListeningPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials());
             server.Start();
 
-            var channelArgs = ChannelArgs.CreateBuilder()
-                .AddString(ChannelArgs.SslTargetNameOverrideKey, TestCredentials.DefaultHostOverride).Build();
-
-            channel = new Channel(host, port, TestCredentials.CreateTestClientCredentials(true), channelArgs);
+            var options = new List<ChannelOption> {
+                new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
+            };
+            channel = new Channel(host, port, TestCredentials.CreateTestClientCredentials(true), options);
             client = TestService.NewStub(channel);
         }
 
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 57be445..59b8993 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -355,6 +355,16 @@
 }
 
 GPR_EXPORT void GPR_CALLTYPE
+grpcsharp_channel_args_set_integer(grpc_channel_args *args, size_t index,
+                                  const char *key, int value) {
+  GPR_ASSERT(args);
+  GPR_ASSERT(index < args->num_args);
+  args->args[index].type = GRPC_ARG_INTEGER;
+  args->args[index].key = gpr_strdup(key);
+  args->args[index].value.integer = value;
+}
+
+GPR_EXPORT void GPR_CALLTYPE
 grpcsharp_channel_args_destroy(grpc_channel_args *args) {
   size_t i;
   if (args) {