diff --git a/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs b/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
index df09857efe361af1c692100446873ac03f23fbe8..52be77c8466e4801c3d79ed859ea50e4dc916621 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
@@ -67,9 +67,9 @@ namespace Grpc.Core.Internal.Tests
         [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); });
+            Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption(null, "abc"); });
+            Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption(null, 1); });
+            Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption("abc", null); });
         }
 
         [Test]
diff --git a/src/csharp/Grpc.Core.Tests/ChannelTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
index 60b45176e561c7f10bbf7bcf186b57c5dde5c1f2..90f6e570c4cf81da87852774be2e103a186c867f 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
@@ -50,7 +50,7 @@ namespace Grpc.Core.Tests
         [Test]
         public void Constructor_RejectsInvalidParams()
         {
-            Assert.Throws(typeof(NullReferenceException), () => new Channel(null, Credentials.Insecure));
+            Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, Credentials.Insecure));
         }
 
         [Test]
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index c5fc85b3fe7465236ee33c6a02a206b4390cfba4..e49fdb5268c6cfa65a33e27e1baac4a5d110caa5 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -138,7 +138,7 @@ namespace Grpc.Core.Tests
             helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
             {
                 string result = "";
-                await requestStream.ForEach(async (request) =>
+                await requestStream.ForEachAsync(async (request) =>
                 {
                     result += request;
                 });
@@ -147,7 +147,7 @@ namespace Grpc.Core.Tests
             });
 
             var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
-            await call.RequestStream.WriteAll(new string[] { "A", "B", "C" });
+            await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" });
             Assert.AreEqual("ABC", await call.ResponseAsync);
         }
 
@@ -159,7 +159,7 @@ namespace Grpc.Core.Tests
             helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
             {
                 barrier.SetResult(null);
-                await requestStream.ToList();
+                await requestStream.ToListAsync();
                 return "";
             });
 
diff --git a/src/csharp/Grpc.Core.Tests/CompressionTest.cs b/src/csharp/Grpc.Core.Tests/CompressionTest.cs
index ac0c3d6b5f16f60fe770b8f7d2fb112f254212f3..9547683f60fb5f3d5b55018bea53d6f997e42ad2 100644
--- a/src/csharp/Grpc.Core.Tests/CompressionTest.cs
+++ b/src/csharp/Grpc.Core.Tests/CompressionTest.cs
@@ -90,7 +90,7 @@ namespace Grpc.Core.Tests
         {
             helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) =>
             {
-                await requestStream.ToList();
+                await requestStream.ToListAsync();
 
                 context.WriteOptions = new WriteOptions(WriteFlags.NoCompress);
 
@@ -122,7 +122,7 @@ namespace Grpc.Core.Tests
 
             await call.RequestStream.CompleteAsync();
 
-            await call.ResponseStream.ToList();
+            await call.ResponseStream.ToListAsync();
         }
     }
 }
diff --git a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
index a7f5075874daba81dfbc834d00fc7ac201e17eb6..db5f953b0e1371b50e502711b27b5f6384f24241 100644
--- a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
@@ -110,6 +110,14 @@ namespace Grpc.Core.Tests
 
             helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
             {
+                Assert.Throws(typeof(ArgumentException), () =>
+                {
+                    // Trying to override deadline while propagating deadline from parent call will throw.
+                    Calls.BlockingUnaryCall(helper.CreateUnaryCall(
+                        new CallOptions(deadline: DateTime.UtcNow.AddDays(8),
+                                        propagationToken: context.CreatePropagationToken())), "");
+                });
+
                 var callOptions = new CallOptions(propagationToken: context.CreatePropagationToken());
                 return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz");
             });
@@ -118,5 +126,28 @@ namespace Grpc.Core.Tests
             await call.RequestStream.CompleteAsync();
             Assert.AreEqual("PASS", await call);
         }
+
+        [Test]
+        public async Task SuppressDeadlinePropagation()
+        {
+            helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
+            {
+                Assert.AreEqual(DateTime.MaxValue, context.Deadline);
+                return "PASS";
+            });
+
+            helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
+            {
+                Assert.IsTrue(context.CancellationToken.CanBeCanceled);
+
+                var callOptions = new CallOptions(propagationToken: context.CreatePropagationToken(new ContextPropagationOptions(propagateDeadline: false)));
+                return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz");
+            });
+
+            var cts = new CancellationTokenSource();
+            var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(deadline: DateTime.UtcNow.AddDays(7))));
+            await call.RequestStream.CompleteAsync();
+            Assert.AreEqual("PASS", await call);
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
index b642286b11654b5091a53411cbf09140037b96fc..bb69648d8bf01177d35839c6a61dcfe6ee255435 100644
--- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
+++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
@@ -153,27 +153,23 @@ namespace Grpc.Core.Tests
             return channel;
         }
 
-        public CallInvocationDetails<string, string> CreateUnaryCall(CallOptions options = null)
+        public CallInvocationDetails<string, string> CreateUnaryCall(CallOptions options = default(CallOptions))
         {
-            options = options ?? new CallOptions();
             return new CallInvocationDetails<string, string>(channel, UnaryMethod, options);
         }
 
-        public CallInvocationDetails<string, string> CreateClientStreamingCall(CallOptions options = null)
+        public CallInvocationDetails<string, string> CreateClientStreamingCall(CallOptions options = default(CallOptions))
         {
-            options = options ?? new CallOptions();
             return new CallInvocationDetails<string, string>(channel, ClientStreamingMethod, options);
         }
 
-        public CallInvocationDetails<string, string> CreateServerStreamingCall(CallOptions options = null)
+        public CallInvocationDetails<string, string> CreateServerStreamingCall(CallOptions options = default(CallOptions))
         {
-            options = options ?? new CallOptions();
             return new CallInvocationDetails<string, string>(channel, ServerStreamingMethod, options);
         }
 
-        public CallInvocationDetails<string, string> CreateDuplexStreamingCall(CallOptions options = null)
+        public CallInvocationDetails<string, string> CreateDuplexStreamingCall(CallOptions options = default(CallOptions))
         {
-            options = options ?? new CallOptions();
             return new CallInvocationDetails<string, string>(channel, DuplexStreamingMethod, options);
         }
 
diff --git a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs
index 8925041ba4750ca167b963d9ecb95901750504a5..981b8ea3c8ea397727653a898ad57ab892e41b87 100644
--- a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs
@@ -84,7 +84,7 @@ namespace Grpc.Core.Tests
         {
             helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
             {
-                Assert.Throws(typeof(NullReferenceException), async () => await context.WriteResponseHeadersAsync(null));
+                Assert.Throws(typeof(ArgumentNullException), async () => await context.WriteResponseHeadersAsync(null));
                 return "PASS";
             });
 
@@ -129,7 +129,7 @@ namespace Grpc.Core.Tests
             });
 
             var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
-            var responses = await call.ResponseStream.ToList();
+            var responses = await call.ResponseStream.ToListAsync();
             CollectionAssert.AreEqual(new[] { "A", "B" }, responses);
         }
     }
diff --git a/src/csharp/Grpc.Core/CallInvocationDetails.cs b/src/csharp/Grpc.Core/CallInvocationDetails.cs
index eb23a3a209ba2ce9e74514fc6f54eed809520042..6565073fc5ed14df9cdeecb821a08a782d0c5619 100644
--- a/src/csharp/Grpc.Core/CallInvocationDetails.cs
+++ b/src/csharp/Grpc.Core/CallInvocationDetails.cs
@@ -40,30 +40,60 @@ namespace Grpc.Core
     /// <summary>
     /// Details about a client-side call to be invoked.
     /// </summary>
-    public class CallInvocationDetails<TRequest, TResponse>
+    public struct CallInvocationDetails<TRequest, TResponse>
     {
         readonly Channel channel;
         readonly string method;
         readonly string host;
         readonly Marshaller<TRequest> requestMarshaller;
         readonly Marshaller<TResponse> responseMarshaller;
-        readonly CallOptions options;
+        CallOptions options;
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Grpc.Core.CallInvocationDetails`2"/> struct.
+        /// </summary>
+        /// <param name="channel">Channel to use for this call.</param>
+        /// <param name="method">Method to call.</param>
+        /// <param name="options">Call options.</param>
         public CallInvocationDetails(Channel channel, Method<TRequest, TResponse> method, CallOptions options) :
-            this(channel, method.FullName, null, method.RequestMarshaller, method.ResponseMarshaller, options)
+            this(channel, method, null, options)
         {
         }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Grpc.Core.CallInvocationDetails`2"/> struct.
+        /// </summary>
+        /// <param name="channel">Channel to use for this call.</param>
+        /// <param name="method">Method to call.</param>
+        /// <param name="host">Host that contains the method. if <c>null</c>, default host will be used.</param>
+        /// <param name="options">Call options.</param>
+        public CallInvocationDetails(Channel channel, Method<TRequest, TResponse> method, string host, CallOptions options) :
+            this(channel, method.FullName, host, method.RequestMarshaller, method.ResponseMarshaller, options)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Grpc.Core.CallInvocationDetails`2"/> struct.
+        /// </summary>
+        /// <param name="channel">Channel to use for this call.</param>
+        /// <param name="method">Qualified method name.</param>
+        /// <param name="host">Host that contains the method.</param>
+        /// <param name="requestMarshaller">Request marshaller.</param>
+        /// <param name="responseMarshaller">Response marshaller.</param>
+        /// <param name="options">Call options.</param>
         public CallInvocationDetails(Channel channel, string method, string host, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller, CallOptions options)
         {
-            this.channel = Preconditions.CheckNotNull(channel);
-            this.method = Preconditions.CheckNotNull(method);
+            this.channel = Preconditions.CheckNotNull(channel, "channel");
+            this.method = Preconditions.CheckNotNull(method, "method");
             this.host = host;
-            this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller);
-            this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller);
-            this.options = Preconditions.CheckNotNull(options);
+            this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller, "requestMarshaller");
+            this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller, "responseMarshaller");
+            this.options = options;
         }
 
+        /// <summary>
+        /// Get channel associated with this call.
+        /// </summary>
         public Channel Channel
         {
             get
@@ -72,6 +102,9 @@ namespace Grpc.Core
             }
         }
 
+        /// <summary>
+        /// Gets name of method to be called.
+        /// </summary>
         public string Method
         {
             get
@@ -80,6 +113,9 @@ namespace Grpc.Core
             }
         }
 
+        /// <summary>
+        /// Get name of host.
+        /// </summary>
         public string Host
         {
             get
@@ -88,6 +124,9 @@ namespace Grpc.Core
             }
         }
 
+        /// <summary>
+        /// Gets marshaller used to serialize requests.
+        /// </summary>
         public Marshaller<TRequest> RequestMarshaller
         {
             get
@@ -96,6 +135,9 @@ namespace Grpc.Core
             }
         }
 
+        /// <summary>
+        /// Gets marshaller used to deserialized responses.
+        /// </summary>
         public Marshaller<TResponse> ResponseMarshaller
         {
             get
@@ -104,6 +146,9 @@ namespace Grpc.Core
             }
         }
             
+        /// <summary>
+        /// Gets the call options.
+        /// </summary>
         public CallOptions Options
         {
             get
@@ -111,5 +156,16 @@ namespace Grpc.Core
                 return options;
             }
         }
+
+        /// <summary>
+        /// Returns new instance of <see cref="CallInvocationDetails"/> with
+        /// <c>Options</c> set to the value provided. Values of all other fields are preserved.
+        /// </summary>
+        public CallInvocationDetails<TRequest, TResponse> WithOptions(CallOptions options)
+        {
+            var newDetails = this;
+            newDetails.options = options;
+            return newDetails;
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs
index 0d82b5a28ee022a95a2b2d1c2b0f74cf40f40f8a..3dfe80b48ce3e48c3d2e0fb187d078c8d016689e 100644
--- a/src/csharp/Grpc.Core/CallOptions.cs
+++ b/src/csharp/Grpc.Core/CallOptions.cs
@@ -42,29 +42,28 @@ namespace Grpc.Core
     /// <summary>
     /// Options for calls made by client.
     /// </summary>
-    public class CallOptions
+    public struct CallOptions
     {
-        readonly Metadata headers;
-        readonly DateTime deadline;
-        readonly CancellationToken cancellationToken;
-        readonly WriteOptions writeOptions;
-        readonly ContextPropagationToken propagationToken;
+        Metadata headers;
+        DateTime? deadline;
+        CancellationToken cancellationToken;
+        WriteOptions writeOptions;
+        ContextPropagationToken propagationToken;
 
         /// <summary>
-        /// Creates a new instance of <c>CallOptions</c>.
+        /// Creates a new instance of <c>CallOptions</c> struct.
         /// </summary>
         /// <param name="headers">Headers to be sent with the call.</param>
         /// <param name="deadline">Deadline for the call to finish. null means no deadline.</param>
         /// <param name="cancellationToken">Can be used to request cancellation of the call.</param>
         /// <param name="writeOptions">Write options that will be used for this call.</param>
         /// <param name="propagationToken">Context propagation token obtained from <see cref="ServerCallContext"/>.</param>
-        public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken? cancellationToken = null,
+        public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken),
                            WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null)
         {
-            // TODO(jtattermusch): consider only creating metadata object once it's really needed.
-            this.headers = headers ?? new Metadata();
-            this.deadline = deadline ?? (propagationToken != null ? propagationToken.Deadline : DateTime.MaxValue);
-            this.cancellationToken = cancellationToken ?? (propagationToken != null ? propagationToken.CancellationToken : CancellationToken.None);
+            this.headers = headers;
+            this.deadline = deadline;
+            this.cancellationToken = cancellationToken;
             this.writeOptions = writeOptions;
             this.propagationToken = propagationToken;
         }
@@ -80,7 +79,7 @@ namespace Grpc.Core
         /// <summary>
         /// Call deadline.
         /// </summary>
-        public DateTime Deadline
+        public DateTime? Deadline
         {
             get { return deadline; }
         }
@@ -114,5 +113,66 @@ namespace Grpc.Core
                 return this.propagationToken;
             }
         }
+
+        /// <summary>
+        /// Returns new instance of <see cref="CallOptions"/> with
+        /// <c>Headers</c> set to the value provided. Values of all other fields are preserved.
+        /// </summary>
+        public CallOptions WithHeaders(Metadata headers)
+        {
+            var newOptions = this;
+            newOptions.headers = headers;
+            return newOptions;
+        }
+
+        /// <summary>
+        /// Returns new instance of <see cref="CallOptions"/> with
+        /// <c>Deadline</c> set to the value provided. Values of all other fields are preserved.
+        /// </summary>
+        public CallOptions WithDeadline(DateTime deadline)
+        {
+            var newOptions = this;
+            newOptions.deadline = deadline;
+            return newOptions;
+        }
+
+        /// <summary>
+        /// Returns new instance of <see cref="CallOptions"/> with
+        /// <c>CancellationToken</c> set to the value provided. Values of all other fields are preserved.
+        /// </summary>
+        public CallOptions WithCancellationToken(CancellationToken cancellationToken)
+        {
+            var newOptions = this;
+            newOptions.cancellationToken = cancellationToken;
+            return newOptions;
+        }
+
+        /// <summary>
+        /// Returns a new instance of <see cref="CallOptions"/> with 
+        /// all previously unset values set to their defaults and deadline and cancellation
+        /// token propagated when appropriate.
+        /// </summary>
+        internal CallOptions Normalize()
+        {
+            var newOptions = this;
+            if (propagationToken != null)
+            {
+                if (propagationToken.Options.IsPropagateDeadline)
+                {
+                    Preconditions.CheckArgument(!newOptions.deadline.HasValue,
+                        "Cannot propagate deadline from parent call. The deadline has already been set explicitly.");
+                    newOptions.deadline = propagationToken.ParentDeadline;
+                }
+                if (propagationToken.Options.IsPropagateCancellation)
+                {
+                    Preconditions.CheckArgument(!newOptions.cancellationToken.CanBeCanceled,
+                        "Cannot propagate cancellation token from parent call. The cancellation token has already been set to a non-default value.");
+                }
+            }
+                
+            newOptions.headers = newOptions.headers ?? Metadata.Empty;
+            newOptions.deadline = newOptions.deadline ?? DateTime.MaxValue;
+            return newOptions;
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs
index 00a8cabf82a364958d125f0d697b97333f934ecd..7067456638a59f46a73f3aac054c4688acf27a54 100644
--- a/src/csharp/Grpc.Core/Calls.cs
+++ b/src/csharp/Grpc.Core/Calls.cs
@@ -31,8 +31,6 @@
 
 #endregion
 
-using System;
-using System.Threading;
 using System.Threading.Tasks;
 using Grpc.Core.Internal;
 
@@ -40,9 +38,20 @@ namespace Grpc.Core
 {
     /// <summary>
     /// Helper methods for generated clients to make RPC calls.
+    /// Most users will use this class only indirectly and will be 
+    /// making calls using client object generated from protocol
+    /// buffer definition files.
     /// </summary>
     public static class Calls
     {
+        /// <summary>
+        /// Invokes a simple remote call in a blocking fashion.
+        /// </summary>
+        /// <returns>The response.</returns>
+        /// <param name="call">The call defintion.</param>
+        /// <param name="req">Request message.</param>
+        /// <typeparam name="TRequest">Type of request message.</typeparam>
+        /// <typeparam name="TResponse">The of response message.</typeparam>
         public static TResponse BlockingUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req)
             where TRequest : class
             where TResponse : class
@@ -51,6 +60,14 @@ namespace Grpc.Core
             return asyncCall.UnaryCall(req);
         }
 
+        /// <summary>
+        /// Invokes a simple remote call asynchronously.
+        /// </summary>
+        /// <returns>An awaitable call object providing access to the response.</returns>
+        /// <param name="call">The call defintion.</param>
+        /// <param name="req">Request message.</param>
+        /// <typeparam name="TRequest">Type of request message.</typeparam>
+        /// <typeparam name="TResponse">The of response message.</typeparam>
         public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req)
             where TRequest : class
             where TResponse : class
@@ -60,6 +77,15 @@ namespace Grpc.Core
             return new AsyncUnaryCall<TResponse>(asyncResult, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
         }
 
+        /// <summary>
+        /// Invokes a server streaming call asynchronously.
+        /// In server streaming scenario, client sends on request and server responds with a stream of responses.
+        /// </summary>
+        /// <returns>A call object providing access to the asynchronous response stream.</returns>
+        /// <param name="call">The call defintion.</param>
+        /// <param name="req">Request message.</param>
+        /// <typeparam name="TRequest">Type of request message.</typeparam>
+        /// <typeparam name="TResponse">The of response messages.</typeparam>
         public static AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req)
             where TRequest : class
             where TResponse : class
@@ -70,6 +96,13 @@ namespace Grpc.Core
             return new AsyncServerStreamingCall<TResponse>(responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
         }
 
+        /// <summary>
+        /// Invokes a client streaming call asynchronously.
+        /// In client streaming scenario, client sends a stream of requests and server responds with a single response.
+        /// </summary>
+        /// <returns>An awaitable call object providing access to the response.</returns>
+        /// <typeparam name="TRequest">Type of request messages.</typeparam>
+        /// <typeparam name="TResponse">The of response message.</typeparam>
         public static AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call)
             where TRequest : class
             where TResponse : class
@@ -80,6 +113,15 @@ namespace Grpc.Core
             return new AsyncClientStreamingCall<TRequest, TResponse>(requestStream, resultTask, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
         }
 
+        /// <summary>
+        /// Invokes a duplex streaming call asynchronously.
+        /// In duplex streaming scenario, client sends a stream of requests and server responds with a stream of responses.
+        /// The response stream is completely independent and both side can be sending messages at the same time.
+        /// </summary>
+        /// <returns>A call object providing access to the asynchronous request and response streams.</returns>
+        /// <param name="call">The call definition.</param>
+        /// <typeparam name="TRequest">Type of request messages.</typeparam>
+        /// <typeparam name="TResponse">Type of reponse messages.</typeparam>
         public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call)
             where TRequest : class
             where TResponse : class
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index 9273ea4582c2853c738b8c62798ac42ce46f56a3..f8cbe08466c032171e42c32625d3541b8d98a830 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -63,7 +63,7 @@ namespace Grpc.Core
         /// <param name="options">Channel options.</param>
         public Channel(string host, Credentials credentials, IEnumerable<ChannelOption> options = null)
         {
-            Preconditions.CheckNotNull(host);
+            Preconditions.CheckNotNull(host, "host");
             this.environment = GrpcEnvironment.GetInstance();
             this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
 
diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs
index 1e0f90287a0eb00910549afee0e4e0854a864ac7..0cb2953f2c2bcf85dfbf4cc5c59be68461054a14 100644
--- a/src/csharp/Grpc.Core/ChannelOptions.cs
+++ b/src/csharp/Grpc.Core/ChannelOptions.cs
@@ -63,8 +63,8 @@ namespace Grpc.Core
         public ChannelOption(string name, string stringValue)
         {
             this.type = OptionType.String;
-            this.name = Preconditions.CheckNotNull(name);
-            this.stringValue = Preconditions.CheckNotNull(stringValue);
+            this.name = Preconditions.CheckNotNull(name, "name");
+            this.stringValue = Preconditions.CheckNotNull(stringValue, "stringValue");
         }
 
         /// <summary>
@@ -75,7 +75,7 @@ namespace Grpc.Core
         public ChannelOption(string name, int intValue)
         {
             this.type = OptionType.Integer;
-            this.name = Preconditions.CheckNotNull(name);
+            this.name = Preconditions.CheckNotNull(name, "name");
             this.intValue = intValue;
         }
 
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index 88494bb4ac8041b2f6ad94d57e94d60a1066d075..48fc7ed34a52f77d7d32b6ea0a41c846b7c6a7ba 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -62,6 +62,18 @@ namespace Grpc.Core
             set;
         }
 
+        /// <summary>
+        /// gRPC supports multiple "hosts" being served by a single server. 
+        /// This property can be used to set the target host explicitly.
+        /// By default, this will be set to <c>null</c> with the meaning
+        /// "use default host".
+        /// </summary>
+        public string Host
+        {
+            get;
+            set;
+        }
+
         /// <summary>
         /// Channel associated with this client.
         /// </summary>
@@ -83,10 +95,14 @@ namespace Grpc.Core
             var interceptor = HeaderInterceptor;
             if (interceptor != null)
             {
+                if (options.Headers == null)
+                {
+                    options = options.WithHeaders(new Metadata());
+                }
                 interceptor(options.Headers);
                 options.Headers.Freeze();
             }
-            return new CallInvocationDetails<TRequest, TResponse>(channel, method, options);
+            return new CallInvocationDetails<TRequest, TResponse>(channel, method, Host, options);
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/ContextPropagationToken.cs b/src/csharp/Grpc.Core/ContextPropagationToken.cs
index b6ea5115a4fef71ae10aa7f95c2e1e25e71eaf40..2e4bfc9e4776877699e405ed6d5bbd24856d1fd9 100644
--- a/src/csharp/Grpc.Core/ContextPropagationToken.cs
+++ b/src/csharp/Grpc.Core/ContextPropagationToken.cs
@@ -52,7 +52,7 @@ namespace Grpc.Core
         /// <summary>
         /// Default propagation mask used by C core.
         /// </summary>
-        const ContextPropagationFlags DefaultCoreMask = (ContextPropagationFlags)0xffff;
+        private const ContextPropagationFlags DefaultCoreMask = (ContextPropagationFlags)0xffff;
 
         /// <summary>
         /// Default propagation mask used by C# - we want to propagate deadline 
@@ -74,6 +74,9 @@ namespace Grpc.Core
             this.options = options ?? ContextPropagationOptions.Default;
         }
 
+        /// <summary>
+        /// Gets the native handle of the parent call.
+        /// </summary>
         internal CallSafeHandle ParentCall
         {
             get
@@ -82,7 +85,10 @@ namespace Grpc.Core
             }
         }
 
-        internal DateTime Deadline
+        /// <summary>
+        /// Gets the parent call's deadline.
+        /// </summary>
+        internal DateTime ParentDeadline
         {
             get
             {
@@ -90,7 +96,10 @@ namespace Grpc.Core
             }
         }
 
-        internal CancellationToken CancellationToken
+        /// <summary>
+        /// Gets the parent call's cancellation token.
+        /// </summary>
+        internal CancellationToken ParentCancellationToken
         {
             get
             {
@@ -98,6 +107,9 @@ namespace Grpc.Core
             }
         }
 
+        /// <summary>
+        /// Get the context propagation options.
+        /// </summary>
         internal ContextPropagationOptions Options
         {
             get
@@ -105,16 +117,6 @@ namespace Grpc.Core
                 return this.options;
             }
         }
-
-        internal bool IsPropagateDeadline
-        {
-            get { return false; }
-        }
-
-        internal bool IsPropagateCancellation
-        {
-            get { return false; }
-        }
     }
 
     /// <summary>
@@ -122,7 +124,37 @@ namespace Grpc.Core
     /// </summary>
     public class ContextPropagationOptions
     {
+        /// <summary>
+        /// The context propagation options that will be used by default.
+        /// </summary>
         public static readonly ContextPropagationOptions Default = new ContextPropagationOptions();
+
+        bool propagateDeadline;
+        bool propagateCancellation;
+
+
+        /// <summary>
+        /// Creates new context propagation options.
+        /// </summary>
+        /// <param name="propagateDeadline">If set to <c>true</c> parent call's deadline will be propagated to the child call.</param>
+        /// <param name="propagateCancellation">If set to <c>true</c> parent call's cancellation token will be propagated to the child call.</param>
+        public ContextPropagationOptions(bool propagateDeadline = true, bool propagateCancellation = true)
+        {
+            this.propagateDeadline = propagateDeadline;
+            this.propagateCancellation = propagateCancellation;
+        }
+            
+        /// <value><c>true</c> if parent call's deadline should be propagated to the child call.</value>
+        public bool IsPropagateDeadline
+        {
+            get { return this.propagateDeadline; }
+        }
+
+        /// <value><c>true</c> if parent call's cancellation token should be propagated to the child call.</value>
+        public bool IsPropagateCancellation
+        {
+            get { return this.propagateCancellation; }
+        }
     }
 
     /// <summary>
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index e535c47f550c0901e517a3aac0614b4b034b75c9..9a8195e9d099e3848e41f98bd4f810a47a275c2f 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -77,7 +77,6 @@
     <Compile Include="ServerServiceDefinition.cs" />
     <Compile Include="Utils\AsyncStreamExtensions.cs" />
     <Compile Include="Utils\BenchmarkUtil.cs" />
-    <Compile Include="Utils\ExceptionHelper.cs" />
     <Compile Include="Internal\CredentialsSafeHandle.cs" />
     <Compile Include="Credentials.cs" />
     <Compile Include="Internal\ChannelArgsSafeHandle.cs" />
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index 1bb83c9962d25b94f911d946407925538ac7ecb5..30d8c802355c72cbf485fd5bd4f9225e82755325 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -115,7 +115,7 @@ namespace Grpc.Core
         /// </summary>
         public static void SetLogger(ILogger customLogger)
         {
-            Preconditions.CheckNotNull(customLogger);
+            Preconditions.CheckNotNull(customLogger, "customLogger");
             logger = customLogger;
         }
 
@@ -192,23 +192,5 @@ namespace Grpc.Core
 
             Logger.Info("gRPC shutdown.");
         }
-
-        /// <summary>
-        /// Shuts down this environment asynchronously.
-        /// </summary>
-        private Task CloseAsync()
-        {
-            return Task.Run(() =>
-            {
-                try
-                {
-                    Close();
-                }
-                catch (Exception e)
-                {
-                    Logger.Error(e, "Error occured while shutting down GrpcEnvironment.");
-                }
-            });
-        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 0db9d2a51514a7bf5fa01b9867807b7d13896ef6..2c3e3d75eae356916cabdd1e9d66471282da5a36 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -63,7 +63,7 @@ namespace Grpc.Core.Internal
         public AsyncCall(CallInvocationDetails<TRequest, TResponse> callDetails)
             : base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer)
         {
-            this.details = callDetails;
+            this.details = callDetails.WithOptions(callDetails.Options.Normalize());
             this.initialMetadataSent = true;  // we always send metadata at the very beginning of the call.
         }
 
@@ -109,15 +109,9 @@ namespace Grpc.Core.Internal
                     }
                 }
 
-                try
-                {
-                    // Once the blocking call returns, the result should be available synchronously.
-                    return unaryResponseTcs.Task.Result;
-                }
-                catch (AggregateException ae)
-                {
-                    throw ExceptionHelper.UnwrapRpcException(ae);
-                }
+                // Once the blocking call returns, the result should be available synchronously.
+                // Note that GetAwaiter().GetResult() doesn't wrap exceptions in AggregateException.
+                return unaryResponseTcs.Task.GetAwaiter().GetResult();
             }
         }
 
@@ -324,12 +318,11 @@ namespace Grpc.Core.Internal
 
         private void Initialize(CompletionQueueSafeHandle cq)
         {
-            var propagationToken = details.Options.PropagationToken;
-            var parentCall = propagationToken != null ? propagationToken.ParentCall : CallSafeHandle.NullInstance;
+            var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance;
 
             var call = details.Channel.Handle.CreateCall(details.Channel.Environment.CompletionRegistry,
                 parentCall, ContextPropagationToken.DefaultMask, cq,
-                details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline));
+                details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value));
             details.Channel.Environment.DebugStats.ActiveClientCalls.Increment();
             InitializeInternal(call);
             RegisterCancellationCallback();
diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs
index e83d21f4a4a98f390632f5c2bb0b41b2e5af5e0a..daf85d5f61d29d0fc8e5f093b305696fef4bd8f9 100644
--- a/src/csharp/Grpc.Core/Internal/Timespec.cs
+++ b/src/csharp/Grpc.Core/Internal/Timespec.cs
@@ -211,7 +211,7 @@ namespace Grpc.Core.Internal
                 return Timespec.InfPast;
             }
 
-            Preconditions.CheckArgument(dateTime.Kind == DateTimeKind.Utc, "dateTime");
+            Preconditions.CheckArgument(dateTime.Kind == DateTimeKind.Utc, "dateTime needs of kind DateTimeKind.Utc or be equal to DateTime.MaxValue or DateTime.MinValue.");
 
             try
             {
diff --git a/src/csharp/Grpc.Core/KeyCertificatePair.cs b/src/csharp/Grpc.Core/KeyCertificatePair.cs
index 5def15a656bc624fe28d036d5b833915a57898c4..6f691975e997f2d5ef3adfd50ce7df918ffee9a4 100644
--- a/src/csharp/Grpc.Core/KeyCertificatePair.cs
+++ b/src/csharp/Grpc.Core/KeyCertificatePair.cs
@@ -54,8 +54,8 @@ namespace Grpc.Core
         /// <param name="privateKey">PEM encoded private key.</param>
         public KeyCertificatePair(string certificateChain, string privateKey)
         {
-            this.certificateChain = Preconditions.CheckNotNull(certificateChain);
-            this.privateKey = Preconditions.CheckNotNull(privateKey);
+            this.certificateChain = Preconditions.CheckNotNull(certificateChain, "certificateChain");
+            this.privateKey = Preconditions.CheckNotNull(privateKey, "privateKey");
         }
 
         /// <summary>
diff --git a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
index c67765c78d5164ac77fdc69deb7762ea023c930d..382481d8716294d3c531b23444c0fac8cf196f38 100644
--- a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
+++ b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
@@ -42,16 +42,21 @@ namespace Grpc.Core.Logging
         readonly Type forType;
         readonly string forTypeString;
 
+        /// <summary>Creates a console logger not associated to any specific type.</summary>
         public ConsoleLogger() : this(null)
         {
         }
 
+        /// <summary>Creates a console logger that logs messsage specific for given type.</summary>
         private ConsoleLogger(Type forType)
         {
             this.forType = forType;
             this.forTypeString = forType != null ? forType.FullName + " " : "";
         }
-
+ 
+        /// <summary>
+        /// Returns a logger associated with the specified type.
+        /// </summary>
         public ILogger ForType<T>()
         {
             if (typeof(T) == forType)
@@ -61,31 +66,37 @@ namespace Grpc.Core.Logging
             return new ConsoleLogger(typeof(T));
         }
 
+        /// <summary>Logs a message with severity Debug.</summary>
         public void Debug(string message, params object[] formatArgs)
         {
             Log("D", message, formatArgs);
         }
 
+        /// <summary>Logs a message with severity Info.</summary>
         public void Info(string message, params object[] formatArgs)
         {
             Log("I", message, formatArgs);
         }
 
+        /// <summary>Logs a message with severity Warning.</summary>
         public void Warning(string message, params object[] formatArgs)
         {
             Log("W", message, formatArgs);
         }
 
+        /// <summary>Logs a message and an associated exception with severity Warning.</summary>
         public void Warning(Exception exception, string message, params object[] formatArgs)
         {
             Log("W", message + " " + exception, formatArgs);
         }
 
+        /// <summary>Logs a message with severity Error.</summary>
         public void Error(string message, params object[] formatArgs)
         {
             Log("E", message, formatArgs);
         }
 
+        /// <summary>Logs a message and an associated exception with severity Error.</summary>
         public void Error(Exception exception, string message, params object[] formatArgs)
         {
             Log("E", message + " " + exception, formatArgs);
diff --git a/src/csharp/Grpc.Core/Logging/ILogger.cs b/src/csharp/Grpc.Core/Logging/ILogger.cs
index 0d58f133e3a53fc1e17417fcf7207c74c6ef19dc..61e0c91388bafbd2182e880f9a7f962e4fafefd2 100644
--- a/src/csharp/Grpc.Core/Logging/ILogger.cs
+++ b/src/csharp/Grpc.Core/Logging/ILogger.cs
@@ -42,16 +42,22 @@ namespace Grpc.Core.Logging
         /// <summary>Returns a logger associated with the specified type.</summary>
         ILogger ForType<T>();
 
+        /// <summary>Logs a message with severity Debug.</summary>
         void Debug(string message, params object[] formatArgs);
 
+        /// <summary>Logs a message with severity Info.</summary>
         void Info(string message, params object[] formatArgs);
 
+        /// <summary>Logs a message with severity Warning.</summary>
         void Warning(string message, params object[] formatArgs);
 
+        /// <summary>Logs a message and an associated exception with severity Warning.</summary>
         void Warning(Exception exception, string message, params object[] formatArgs);
 
+        /// <summary>Logs a message with severity Error.</summary>
         void Error(string message, params object[] formatArgs);
 
+        /// <summary>Logs a message and an associated exception with severity Error.</summary>
         void Error(Exception exception, string message, params object[] formatArgs);
     }
 }
diff --git a/src/csharp/Grpc.Core/Marshaller.cs b/src/csharp/Grpc.Core/Marshaller.cs
index 8b1a9290741945b77d7dc023ca8b946852daa80c..f38cb0863ffe0099475d200428a53ef0b573c548 100644
--- a/src/csharp/Grpc.Core/Marshaller.cs
+++ b/src/csharp/Grpc.Core/Marshaller.cs
@@ -37,19 +37,27 @@ using Grpc.Core.Utils;
 namespace Grpc.Core
 {
     /// <summary>
-    /// For serializing and deserializing messages.
+    /// Encapsulates the logic for serializing and deserializing messages.
     /// </summary>
     public struct Marshaller<T>
     {
         readonly Func<T, byte[]> serializer;
         readonly Func<byte[], T> deserializer;
 
+        /// <summary>
+        /// Initializes a new marshaller.
+        /// </summary>
+        /// <param name="serializer">Function that will be used to serialize messages.</param>
+        /// <param name="deserializer">Function that will be used to deserialize messages.</param>
         public Marshaller(Func<T, byte[]> serializer, Func<byte[], T> deserializer)
         {
-            this.serializer = Preconditions.CheckNotNull(serializer);
-            this.deserializer = Preconditions.CheckNotNull(deserializer);
+            this.serializer = Preconditions.CheckNotNull(serializer, "serializer");
+            this.deserializer = Preconditions.CheckNotNull(deserializer, "deserializer");
         }
 
+        /// <summary>
+        /// Gets the serializer function.
+        /// </summary>
         public Func<T, byte[]> Serializer
         {
             get
@@ -58,6 +66,9 @@ namespace Grpc.Core
             }
         }
 
+        /// <summary>
+        /// Gets the deserializer function.
+        /// </summary>
         public Func<byte[], T> Deserializer
         {
             get
@@ -72,11 +83,17 @@ namespace Grpc.Core
     /// </summary>
     public static class Marshallers
     {
+        /// <summary>
+        /// Creates a marshaller from specified serializer and deserializer.
+        /// </summary>
         public static Marshaller<T> Create<T>(Func<T, byte[]> serializer, Func<byte[], T> deserializer)
         {
             return new Marshaller<T>(serializer, deserializer);
         }
 
+        /// <summary>
+        /// Returns a marshaller for <c>string</c> type. This is useful for testing.
+        /// </summary>
         public static Marshaller<string> StringMarshaller
         {
             get
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
index a58dbdbc93b6927d06ab8c07ab6f25e247d1443e..9db2abf46ef8f7eae14ee908d2014611c666a151 100644
--- a/src/csharp/Grpc.Core/Metadata.cs
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -186,15 +186,15 @@ namespace Grpc.Core
 
             public Entry(string key, byte[] valueBytes)
             {
-                this.key = Preconditions.CheckNotNull(key);
+                this.key = Preconditions.CheckNotNull(key, "key");
                 this.value = null;
-                this.valueBytes = Preconditions.CheckNotNull(valueBytes);
+                this.valueBytes = Preconditions.CheckNotNull(valueBytes, "valueBytes");
             }
 
             public Entry(string key, string value)
             {
-                this.key = Preconditions.CheckNotNull(key);
-                this.value = Preconditions.CheckNotNull(value);
+                this.key = Preconditions.CheckNotNull(key, "key");
+                this.value = Preconditions.CheckNotNull(value, "value");
                 this.valueBytes = null;
             }
 
diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs
index cc047ac9f8fb86e6676e7dca0b442344a4cf98d4..4c208b4a263068b52529238a816781263b913267 100644
--- a/src/csharp/Grpc.Core/Method.cs
+++ b/src/csharp/Grpc.Core/Method.cs
@@ -41,14 +41,21 @@ namespace Grpc.Core
     /// </summary>
     public enum MethodType
     {
-        Unary,  // Unary request, unary response.
-        ClientStreaming,  // Streaming request, unary response.
-        ServerStreaming,  // Unary request, streaming response.
-        DuplexStreaming  // Streaming request, streaming response.
+        /// <summary>Single request sent from client, single response received from server.</summary>
+        Unary,
+
+        /// <summary>Stream of request sent from client, single response received from server.</summary>
+        ClientStreaming,
+
+        /// <summary>Single request sent from client, stream of responses received from server.</summary>
+        ServerStreaming,
+
+        /// <summary>Both server and client can stream arbitrary number of requests and responses simultaneously.</summary>
+        DuplexStreaming
     }
 
     /// <summary>
-    /// A description of a service method.
+    /// A description of a remote method.
     /// </summary>
     public class Method<TRequest, TResponse>
     {
@@ -59,16 +66,27 @@ namespace Grpc.Core
         readonly Marshaller<TResponse> responseMarshaller;
         readonly string fullName;
 
+        /// <summary>
+        /// Initializes a new instance of the <c>Method</c> class.
+        /// </summary>
+        /// <param name="type">Type of method.</param>
+        /// <param name="serviceName">Name of service this method belongs to.</param>
+        /// <param name="name">Unqualified name of the method.</param>
+        /// <param name="requestMarshaller">Marshaller used for request messages.</param>
+        /// <param name="responseMarshaller">Marshaller used for response messages.</param>
         public Method(MethodType type, string serviceName, string name, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller)
         {
             this.type = type;
-            this.serviceName = Preconditions.CheckNotNull(serviceName);
-            this.name = Preconditions.CheckNotNull(name);
-            this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller);
-            this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller);
-            this.fullName = GetFullName(serviceName);
+            this.serviceName = Preconditions.CheckNotNull(serviceName, "serviceName");
+            this.name = Preconditions.CheckNotNull(name, "name");
+            this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller, "requestMarshaller");
+            this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller, "responseMarshaller");
+            this.fullName = GetFullName(serviceName, name);
         }
 
+        /// <summary>
+        /// Gets the type of the method.
+        /// </summary>
         public MethodType Type
         {
             get
@@ -77,6 +95,9 @@ namespace Grpc.Core
             }
         }
             
+        /// <summary>
+        /// Gets the name of the service to which this method belongs.
+        /// </summary>
         public string ServiceName
         {
             get
@@ -85,6 +106,9 @@ namespace Grpc.Core
             }
         }
 
+        /// <summary>
+        /// Gets the unqualified name of the method.
+        /// </summary>
         public string Name
         {
             get
@@ -93,6 +117,9 @@ namespace Grpc.Core
             }
         }
 
+        /// <summary>
+        /// Gets the marshaller used for request messages.
+        /// </summary>
         public Marshaller<TRequest> RequestMarshaller
         {
             get
@@ -101,6 +128,9 @@ namespace Grpc.Core
             }
         }
 
+        /// <summary>
+        /// Gets the marshaller used for response messages.
+        /// </summary>
         public Marshaller<TResponse> ResponseMarshaller
         {
             get
@@ -108,7 +138,11 @@ namespace Grpc.Core
                 return this.responseMarshaller;
             }
         }
-
+            
+        /// <summary>
+        /// Gets the fully qualified name of the method. On the server side, methods are dispatched
+        /// based on this name.
+        /// </summary>
         public string FullName
         {
             get
@@ -120,9 +154,9 @@ namespace Grpc.Core
         /// <summary>
         /// Gets full name of the method including the service name.
         /// </summary>
-        internal string GetFullName(string serviceName)
+        internal static string GetFullName(string serviceName, string methodName)
         {
-            return "/" + Preconditions.CheckNotNull(serviceName) + "/" + this.Name;
+            return "/" + serviceName + "/" + methodName;
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/RpcException.cs b/src/csharp/Grpc.Core/RpcException.cs
index c58578286b3e886cc3f950e8fd07dfb3d0ae4e4a..cac417e62614ed606a1bcbc0df9940ad9a76c68b 100644
--- a/src/csharp/Grpc.Core/RpcException.cs
+++ b/src/csharp/Grpc.Core/RpcException.cs
@@ -36,22 +36,34 @@ using System;
 namespace Grpc.Core
 {
     /// <summary>
-    /// Thrown when remote procedure call fails.
+    /// Thrown when remote procedure call fails. Every <c>RpcException</c> is associated with a resulting <see cref="Status"/> of the call.
     /// </summary>
     public class RpcException : Exception
     {
         private readonly Status status;
 
+        /// <summary>
+        /// Creates a new <c>RpcException</c> associated with given status.
+        /// </summary>
+        /// <param name="status">Resulting status of a call.</param>
         public RpcException(Status status) : base(status.ToString())
         {
             this.status = status;
         }
 
+        /// <summary>
+        /// Creates a new <c>RpcException</c> associated with given status and message.
+        /// </summary>
+        /// <param name="status">Resulting status of a call.</param>
+        /// <param name="message">The exception message.</param> 
         public RpcException(Status status, string message) : base(message)
         {
             this.status = status;
         }
 
+        /// <summary>
+        /// Resulting status of the call.
+        /// </summary>
         public Status Status
         {
             get
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index eb5b043d1c516f328cc0c1d7bd859f5b64ee13e0..c76f126026f16370c164a98305e23eab72c50a33 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -192,7 +192,7 @@ namespace Grpc.Core
         {
             lock (myLock)
             {
-                Preconditions.CheckNotNull(serverPort.Credentials);
+                Preconditions.CheckNotNull(serverPort.Credentials, "serverPort");
                 Preconditions.CheckState(!startRequested);
                 var address = string.Format("{0}:{1}", serverPort.Host, serverPort.Port);
                 int boundPort;
diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs
index c11a1ede085b5d9c60efe56aa4a00958912ac40c..3c6703d30e518fd398318bbddd523861e7e920d9 100644
--- a/src/csharp/Grpc.Core/ServerCredentials.cs
+++ b/src/csharp/Grpc.Core/ServerCredentials.cs
@@ -91,7 +91,7 @@ namespace Grpc.Core
         {
             this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly();
             Preconditions.CheckArgument(this.keyCertificatePairs.Count > 0,
-                "At least one KeyCertificatePair needs to be provided");
+                "At least one KeyCertificatePair needs to be provided.");
             if (forceClientAuth)
             {
                 Preconditions.CheckNotNull(rootCertificates,
diff --git a/src/csharp/Grpc.Core/ServerMethods.cs b/src/csharp/Grpc.Core/ServerMethods.cs
index d45777020374b5f9eded1364d0ecda11d150064f..1f119a80ffe243737147f7c97300ea78eebeb7ff 100644
--- a/src/csharp/Grpc.Core/ServerMethods.cs
+++ b/src/csharp/Grpc.Core/ServerMethods.cs
@@ -31,12 +31,8 @@
 
 #endregion
 
-using System;
-using System.Threading;
 using System.Threading.Tasks;
 
-using Grpc.Core.Internal;
-
 namespace Grpc.Core
 {
     /// <summary>
diff --git a/src/csharp/Grpc.Core/ServerPort.cs b/src/csharp/Grpc.Core/ServerPort.cs
index 55e4bd006210d2d1975ece45873ce54d23f57fb9..598404d04592f12d7f542588da425f6b9ab8d190 100644
--- a/src/csharp/Grpc.Core/ServerPort.cs
+++ b/src/csharp/Grpc.Core/ServerPort.cs
@@ -62,9 +62,9 @@ namespace Grpc.Core
         /// <param name="credentials">credentials to use to secure this port.</param>
         public ServerPort(string host, int port, ServerCredentials credentials)
         {
-            this.host = Preconditions.CheckNotNull(host);
+            this.host = Preconditions.CheckNotNull(host, "host");
             this.port = port;
-            this.credentials = Preconditions.CheckNotNull(credentials);
+            this.credentials = Preconditions.CheckNotNull(credentials, "credentials");
         }
 
         /// <summary>
diff --git a/src/csharp/Grpc.Core/ServerServiceDefinition.cs b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
index a00d156e52750fe1dc09ca31ee0b5072ca8cfc95..94b0a320c3006a8419a67f566bf6dd31ac29df74 100644
--- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs
+++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
@@ -79,7 +79,7 @@ namespace Grpc.Core
                     where TRequest : class
                     where TResponse : class
             {
-                callHandlers.Add(method.GetFullName(serviceName), ServerCalls.UnaryCall(method, handler));
+                callHandlers.Add(method.FullName, ServerCalls.UnaryCall(method, handler));
                 return this;
             }
 
@@ -89,7 +89,7 @@ namespace Grpc.Core
                     where TRequest : class
                     where TResponse : class
             {
-                callHandlers.Add(method.GetFullName(serviceName), ServerCalls.ClientStreamingCall(method, handler));
+                callHandlers.Add(method.FullName, ServerCalls.ClientStreamingCall(method, handler));
                 return this;
             }
 
@@ -99,7 +99,7 @@ namespace Grpc.Core
                     where TRequest : class
                     where TResponse : class
             {
-                callHandlers.Add(method.GetFullName(serviceName), ServerCalls.ServerStreamingCall(method, handler));
+                callHandlers.Add(method.FullName, ServerCalls.ServerStreamingCall(method, handler));
                 return this;
             }
 
@@ -109,7 +109,7 @@ namespace Grpc.Core
                     where TRequest : class
                     where TResponse : class
             {
-                callHandlers.Add(method.GetFullName(serviceName), ServerCalls.DuplexStreamingCall(method, handler));
+                callHandlers.Add(method.FullName, ServerCalls.DuplexStreamingCall(method, handler));
                 return this;
             }
 
diff --git a/src/csharp/Grpc.Core/Status.cs b/src/csharp/Grpc.Core/Status.cs
index 754f6cb3cabcac84686962419a130a135a2727ec..6bd8dc820bede9c8eadab9e4970cecc48723d373 100644
--- a/src/csharp/Grpc.Core/Status.cs
+++ b/src/csharp/Grpc.Core/Status.cs
@@ -29,13 +29,12 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endregion
 
-using System;
-using System.Runtime.InteropServices;
+using Grpc.Core.Utils;
 
 namespace Grpc.Core
 {
     /// <summary>
-    /// Represents RPC result.
+    /// Represents RPC result, which consists of <see cref="StatusCode"/> and an optional detail string. 
     /// </summary>
     public struct Status
     {
@@ -52,6 +51,11 @@ namespace Grpc.Core
         readonly StatusCode statusCode;
         readonly string detail;
 
+        /// <summary>
+        /// Creates a new instance of <c>Status</c>.
+        /// </summary>
+        /// <param name="statusCode">Status code.</param>
+        /// <param name="detail">Detail.</param>
         public Status(StatusCode statusCode, string detail)
         {
             this.statusCode = statusCode;
@@ -80,6 +84,9 @@ namespace Grpc.Core
             }
         }
 
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents the current <see cref="Grpc.Core.Status"/>.
+        /// </summary>
         public override string ToString()
         {
             return string.Format("Status(StatusCode={0}, Detail=\"{1}\")", statusCode, detail);
diff --git a/src/csharp/Grpc.Core/StatusCode.cs b/src/csharp/Grpc.Core/StatusCode.cs
index a9696fa46904174f8d590e524776d9c6ec48ee15..90606955afbe2cf389bf175f0ea18f7517e56918 100644
--- a/src/csharp/Grpc.Core/StatusCode.cs
+++ b/src/csharp/Grpc.Core/StatusCode.cs
@@ -31,8 +31,6 @@
 
 #endregion
 
-using System;
-
 namespace Grpc.Core
 {
     /// <summary>
@@ -41,101 +39,101 @@ namespace Grpc.Core
     /// </summary>
     public enum StatusCode
     {
-        /* Not an error; returned on success */
+        /// <summary>Not an error; returned on success.</summary>
         OK = 0,
-        /* The operation was cancelled (typically by the caller). */
+
+        /// <summary>The operation was cancelled (typically by the caller).</summary>
         Cancelled = 1,
-        /* Unknown error.  An example of where this error may be returned is
-     if a Status value received from another address space belongs to
-     an error-space that is not known in this address space.  Also
-     errors raised by APIs that do not return enough error information
-     may be converted to this error. */
+
+        /// <summary>
+        /// Unknown error.  An example of where this error may be returned is
+        /// if a Status value received from another address space belongs to
+        /// an error-space that is not known in this address space.  Also
+        /// errors raised by APIs that do not return enough error information
+        /// may be converted to this error.
+        /// </summary>
         Unknown = 2,
-        /* Client specified an invalid argument.  Note that this differs
-     from FAILED_PRECONDITION.  INVALID_ARGUMENT indicates arguments
-     that are problematic regardless of the state of the system
-     (e.g., a malformed file name). */
+
+        /// <summary>
+        /// Client specified an invalid argument.  Note that this differs
+        /// from FAILED_PRECONDITION.  INVALID_ARGUMENT indicates arguments
+        /// that are problematic regardless of the state of the system
+        /// (e.g., a malformed file name).
+        /// </summary>
         InvalidArgument = 3,
-        /* Deadline expired before operation could complete.  For operations
-     that change the state of the system, this error may be returned
-     even if the operation has completed successfully.  For example, a
-     successful response from a server could have been delayed long
-     enough for the deadline to expire. */
+
+        /// <summary>
+        /// Deadline expired before operation could complete.  For operations
+        /// that change the state of the system, this error may be returned
+        /// even if the operation has completed successfully.  For example, a
+        /// successful response from a server could have been delayed long
+        /// enough for the deadline to expire.
+        /// </summary>
         DeadlineExceeded = 4,
-        /* Some requested entity (e.g., file or directory) was not found. */
+
+        /// <summary>Some requested entity (e.g., file or directory) was not found.</summary>
         NotFound = 5,
-        /* Some entity that we attempted to create (e.g., file or directory)
-     already exists. */
+
+        /// <summary>Some entity that we attempted to create (e.g., file or directory) already exists.</summary>
         AlreadyExists = 6,
-        /* The caller does not have permission to execute the specified
-     operation.  PERMISSION_DENIED must not be used for rejections
-     caused by exhausting some resource (use RESOURCE_EXHAUSTED
-     instead for those errors).  PERMISSION_DENIED must not be
-     used if the caller can not be identified (use UNAUTHENTICATED
-     instead for those errors). */
+
+        /// <summary>
+        /// The caller does not have permission to execute the specified
+        /// operation.  PERMISSION_DENIED must not be used for rejections
+        /// caused by exhausting some resource (use RESOURCE_EXHAUSTED
+        /// instead for those errors).  PERMISSION_DENIED must not be
+        /// used if the caller can not be identified (use UNAUTHENTICATED
+        /// instead for those errors).
+        /// </summary>
         PermissionDenied = 7,
-        /* The request does not have valid authentication credentials for the
-     operation. */
+
+        /// <summary>The request does not have valid authentication credentials for the operation.</summary>
         Unauthenticated = 16,
-        /* Some resource has been exhausted, perhaps a per-user quota, or
-     perhaps the entire file system is out of space. */
+
+        /// <summary>
+        /// Some resource has been exhausted, perhaps a per-user quota, or
+        /// perhaps the entire file system is out of space.
+        /// </summary>
         ResourceExhausted = 8,
-        /* Operation was rejected because the system is not in a state
-     required for the operation's execution.  For example, directory
-     to be deleted may be non-empty, an rmdir operation is applied to
-     a non-directory, etc.
-
-     A litmus test that may help a service implementor in deciding
-     between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
-      (a) Use UNAVAILABLE if the client can retry just the failing call.
-      (b) Use ABORTED if the client should retry at a higher-level
-          (e.g., restarting a read-modify-write sequence).
-      (c) Use FAILED_PRECONDITION if the client should not retry until
-          the system state has been explicitly fixed.  E.g., if an "rmdir"
-          fails because the directory is non-empty, FAILED_PRECONDITION
-          should be returned since the client should not retry unless
-          they have first fixed up the directory by deleting files from it.
-      (d) Use FAILED_PRECONDITION if the client performs conditional
-          REST Get/Update/Delete on a resource and the resource on the
-          server does not match the condition. E.g., conflicting
-          read-modify-write on the same resource. */
+
+        /// <summary>
+        /// Operation was rejected because the system is not in a state
+        /// required for the operation's execution.  For example, directory
+        /// to be deleted may be non-empty, an rmdir operation is applied to
+        /// a non-directory, etc.
+        /// </summary>
         FailedPrecondition = 9,
-        /* The operation was aborted, typically due to a concurrency issue
-     like sequencer check failures, transaction aborts, etc.
 
-     See litmus test above for deciding between FAILED_PRECONDITION,
-     ABORTED, and UNAVAILABLE. */
+        /// <summary>
+        /// The operation was aborted, typically due to a concurrency issue
+        /// like sequencer check failures, transaction aborts, etc.
+        /// </summary>
         Aborted = 10,
-        /* Operation was attempted past the valid range.  E.g., seeking or
-     reading past end of file.
-
-     Unlike INVALID_ARGUMENT, this error indicates a problem that may
-     be fixed if the system state changes. For example, a 32-bit file
-     system will generate INVALID_ARGUMENT if asked to read at an
-     offset that is not in the range [0,2^32-1], but it will generate
-     OUT_OF_RANGE if asked to read from an offset past the current
-     file size.
-
-     There is a fair bit of overlap between FAILED_PRECONDITION and
-     OUT_OF_RANGE.  We recommend using OUT_OF_RANGE (the more specific
-     error) when it applies so that callers who are iterating through
-     a space can easily look for an OUT_OF_RANGE error to detect when
-     they are done. */
+
+        /// <summary>
+        /// Operation was attempted past the valid range.  E.g., seeking or
+        /// reading past end of file.
+        /// </summary>
         OutOfRange = 11,
-        /* Operation is not implemented or not supported/enabled in this service. */
+
+        /// <summary>Operation is not implemented or not supported/enabled in this service.</summary>
         Unimplemented = 12,
-        /* Internal errors.  Means some invariants expected by underlying
-     system has been broken.  If you see one of these errors,
-     something is very broken. */
+
+        /// <summary>
+        /// Internal errors.  Means some invariants expected by underlying
+        /// system has been broken.  If you see one of these errors,
+        /// something is very broken.
+        /// </summary>
         Internal = 13,
-        /* The service is currently unavailable.  This is a most likely a
-     transient condition and may be corrected by retrying with
-     a backoff.
 
-     See litmus test above for deciding between FAILED_PRECONDITION,
-     ABORTED, and UNAVAILABLE. */
+        /// <summary>
+        /// The service is currently unavailable.  This is a most likely a
+        /// transient condition and may be corrected by retrying with
+        /// a backoff.
+        /// </summary>
         Unavailable = 14,
-        /* Unrecoverable data loss or corruption. */
+
+        /// <summary>Unrecoverable data loss or corruption.</summary>
         DataLoss = 15
     }
 }
diff --git a/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs b/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs
index 8a748b45a81fd761759f96ea934551bb79abb0c8..cdf1e510261e9d9b593987e590b83bbd93a1e450 100644
--- a/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs
+++ b/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs
@@ -33,7 +33,6 @@
 
 using System;
 using System.Collections.Generic;
-using System.Linq;
 using System.Threading.Tasks;
 
 namespace Grpc.Core.Utils
@@ -46,7 +45,7 @@ namespace Grpc.Core.Utils
         /// <summary>
         /// Reads the entire stream and executes an async action for each element.
         /// </summary>
-        public static async Task ForEach<T>(this IAsyncStreamReader<T> streamReader, Func<T, Task> asyncAction)
+        public static async Task ForEachAsync<T>(this IAsyncStreamReader<T> streamReader, Func<T, Task> asyncAction)
             where T : class
         {
             while (await streamReader.MoveNext())
@@ -58,7 +57,7 @@ namespace Grpc.Core.Utils
         /// <summary>
         /// Reads the entire stream and creates a list containing all the elements read.
         /// </summary>
-        public static async Task<List<T>> ToList<T>(this IAsyncStreamReader<T> streamReader)
+        public static async Task<List<T>> ToListAsync<T>(this IAsyncStreamReader<T> streamReader)
             where T : class
         {
             var result = new List<T>();
@@ -73,7 +72,7 @@ namespace Grpc.Core.Utils
         /// Writes all elements from given enumerable to the stream.
         /// Completes the stream afterwards unless close = false.
         /// </summary>
-        public static async Task WriteAll<T>(this IClientStreamWriter<T> streamWriter, IEnumerable<T> elements, bool complete = true)
+        public static async Task WriteAllAsync<T>(this IClientStreamWriter<T> streamWriter, IEnumerable<T> elements, bool complete = true)
             where T : class
         {
             foreach (var element in elements)
@@ -89,7 +88,7 @@ namespace Grpc.Core.Utils
         /// <summary>
         /// Writes all elements from given enumerable to the stream.
         /// </summary>
-        public static async Task WriteAll<T>(this IServerStreamWriter<T> streamWriter, IEnumerable<T> elements)
+        public static async Task WriteAllAsync<T>(this IServerStreamWriter<T> streamWriter, IEnumerable<T> elements)
             where T : class
         {
             foreach (var element in elements)
diff --git a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
index 82653c3a1f587d12547104180cbd39072ffd3a89..eb3a5b16e3c2544a92a74d5cd578838e071a3b6f 100644
--- a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
+++ b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
@@ -39,6 +39,9 @@ using System.Threading.Tasks;
 
 namespace Grpc.Core.Utils
 {
+    /// <summary>
+    /// Utility methods to run microbenchmarks.
+    /// </summary>
     public static class BenchmarkUtil
     {
         /// <summary>
diff --git a/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs b/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs
deleted file mode 100644
index c4d6bee05807437d2905804fbc793121119028c4..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs
+++ /dev/null
@@ -1,57 +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;
-
-namespace Grpc.Core.Utils
-{
-    public static class ExceptionHelper
-    {
-        /// <summary>
-        /// If inner exceptions contain RpcException, rethrows it.
-        /// Otherwise, rethrows the original aggregate exception.
-        /// Always throws, the exception return type is here only to make the.
-        /// </summary>
-        public static Exception UnwrapRpcException(AggregateException ae)
-        {
-            foreach (var e in ae.InnerExceptions)
-            {
-                if (e is RpcException)
-                {
-                    throw e;
-                }
-            }
-            throw ae;
-        }
-    }
-}
diff --git a/src/csharp/Grpc.Core/Utils/Preconditions.cs b/src/csharp/Grpc.Core/Utils/Preconditions.cs
index aeb5d210a79f286fa754b4e898df4e9a96cc62bf..374262f87ad5e2cdd870826af49e2fcfddd00e60 100644
--- a/src/csharp/Grpc.Core/Utils/Preconditions.cs
+++ b/src/csharp/Grpc.Core/Utils/Preconditions.cs
@@ -32,17 +32,16 @@
 #endregion
 
 using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Threading.Tasks;
 
 namespace Grpc.Core.Utils
 {
+    /// <summary>
+    /// Utility methods to simplify checking preconditions in the code.
+    /// </summary>
     public static class Preconditions
     {
         /// <summary>
-        /// Throws ArgumentException if condition is false.
+        /// Throws <see cref="ArgumentException"/> if condition is false.
         /// </summary>
         public static void CheckArgument(bool condition)
         {
@@ -53,7 +52,7 @@ namespace Grpc.Core.Utils
         }
 
         /// <summary>
-        /// Throws ArgumentException with given message if condition is false.
+        /// Throws <see cref="ArgumentException"/> with given message if condition is false.
         /// </summary>
         public static void CheckArgument(bool condition, string errorMessage)
         {
@@ -64,31 +63,31 @@ namespace Grpc.Core.Utils
         }
 
         /// <summary>
-        /// Throws NullReferenceException if reference is null.
+        /// Throws <see cref="ArgumentNullException"/> if reference is null.
         /// </summary>
         public static T CheckNotNull<T>(T reference)
         {
             if (reference == null)
             {
-                throw new NullReferenceException();
+                throw new ArgumentNullException();
             }
             return reference;
         }
 
         /// <summary>
-        /// Throws NullReferenceException with given message if reference is null.
+        /// Throws <see cref="ArgumentNullException"/> if reference is null.
         /// </summary>
-        public static T CheckNotNull<T>(T reference, string errorMessage)
+        public static T CheckNotNull<T>(T reference, string paramName)
         {
             if (reference == null)
             {
-                throw new NullReferenceException(errorMessage);
+                throw new ArgumentNullException(paramName);
             }
             return reference;
         }
 
         /// <summary>
-        /// Throws InvalidOperationException if condition is false.
+        /// Throws <see cref="InvalidOperationException"/> if condition is false.
         /// </summary>
         public static void CheckState(bool condition)
         {
@@ -99,7 +98,7 @@ namespace Grpc.Core.Utils
         }
 
         /// <summary>
-        /// Throws InvalidOperationException with given message if condition is false.
+        /// Throws <see cref="InvalidOperationException"/> with given message if condition is false.
         /// </summary>
         public static void CheckState(bool condition, string errorMessage)
         {
diff --git a/src/csharp/Grpc.Core/Version.cs b/src/csharp/Grpc.Core/Version.cs
index d2a029fbb4d1e504f0e65371391e94dfb144be61..d02b301cac75c1ce2c3b0088129727fea132d16f 100644
--- a/src/csharp/Grpc.Core/Version.cs
+++ b/src/csharp/Grpc.Core/Version.cs
@@ -1,5 +1,37 @@
+#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.Reflection;
-using System.Runtime.CompilerServices;
 
 // The current version of gRPC C#.
 [assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentVersion + ".0")]
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index 939372e2370f2b1faa316297a88b288d71348e39..b6dbd3b49c030409bfa516399a8f5dbff426ddef 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -1,8 +1,41 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
+#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
 
 namespace Grpc.Core
 {
+    /// <summary>
+    /// Provides info about current version of gRPC.
+    /// </summary>
     public static class VersionInfo
     {
         /// <summary>
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index 73d2a1ca9bb463868235eacf9f072d1454a349bd..fdef950f09d8d8ae596307b95a1d403ef6dc42c6 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -109,7 +109,7 @@ namespace math.Tests
         {
             using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build()))
             {
-                var responses = await call.ResponseStream.ToList();
+                var responses = await call.ResponseStream.ToListAsync();
                 CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 },
                     responses.ConvertAll((n) => n.Num_));
             }
@@ -151,7 +151,7 @@ namespace math.Tests
             using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), 
                 deadline: DateTime.UtcNow.AddMilliseconds(500)))
             {
-                var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.ToList());
+                var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.ToListAsync());
 
                 // We can't guarantee the status code always DeadlineExceeded. See issue #2685.
                 Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal });
@@ -167,7 +167,7 @@ namespace math.Tests
                 var numbers = new List<long> { 10, 20, 30 }.ConvertAll(
                             n => Num.CreateBuilder().SetNum_(n).Build());
 
-                await call.RequestStream.WriteAll(numbers);
+                await call.RequestStream.WriteAllAsync(numbers);
                 var result = await call.ResponseAsync;
                 Assert.AreEqual(60, result.Num_);
             }
@@ -185,8 +185,8 @@ namespace math.Tests
 
             using (var call = client.DivMany())
             {
-                await call.RequestStream.WriteAll(divArgsList);
-                var result = await call.ResponseStream.ToList();
+                await call.RequestStream.WriteAllAsync(divArgsList);
+                var result = await call.ResponseStream.ToListAsync();
 
                 CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient));
                 CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder));
diff --git a/src/csharp/Grpc.Examples/MathExamples.cs b/src/csharp/Grpc.Examples/MathExamples.cs
index 06d81a4d83d5095a6b39096af4ed47b93235170d..dc1bf439950f9edb92655a44d0c3713c4da7ab1b 100644
--- a/src/csharp/Grpc.Examples/MathExamples.cs
+++ b/src/csharp/Grpc.Examples/MathExamples.cs
@@ -54,7 +54,7 @@ namespace math
         {
             using (var call = client.Fib(new FibArgs.Builder { Limit = 5 }.Build()))
             {
-                List<Num> result = await call.ResponseStream.ToList();
+                List<Num> result = await call.ResponseStream.ToListAsync();
                 Console.WriteLine("Fib Result: " + string.Join("|", result));
             }
         }
@@ -70,7 +70,7 @@ namespace math
 
             using (var call = client.Sum())
             {
-                await call.RequestStream.WriteAll(numbers);
+                await call.RequestStream.WriteAllAsync(numbers);
                 Console.WriteLine("Sum Result: " + await call.ResponseAsync);
             }
         }
@@ -85,8 +85,8 @@ namespace math
             };
             using (var call = client.DivMany())
             { 
-                await call.RequestStream.WriteAll(divArgsList);
-                Console.WriteLine("DivMany Result: " + string.Join("|", await call.ResponseStream.ToList()));
+                await call.RequestStream.WriteAllAsync(divArgsList);
+                Console.WriteLine("DivMany Result: " + string.Join("|", await call.ResponseStream.ToListAsync()));
             }
         }
 
@@ -102,7 +102,7 @@ namespace math
             Num sum;
             using (var sumCall = client.Sum())
             {
-                await sumCall.RequestStream.WriteAll(numbers);
+                await sumCall.RequestStream.WriteAllAsync(numbers);
                 sum = await sumCall.ResponseAsync;
             }
 
diff --git a/src/csharp/Grpc.Examples/MathServiceImpl.cs b/src/csharp/Grpc.Examples/MathServiceImpl.cs
index dd26b1d35010c2ebff840f163c229fd4488f9c58..7b2684615c6eae41ea248c35df143df034d1531f 100644
--- a/src/csharp/Grpc.Examples/MathServiceImpl.cs
+++ b/src/csharp/Grpc.Examples/MathServiceImpl.cs
@@ -75,7 +75,7 @@ namespace math
         public async Task<Num> Sum(IAsyncStreamReader<Num> requestStream, ServerCallContext context)
         {
             long sum = 0;
-            await requestStream.ForEach(async num =>
+            await requestStream.ForEachAsync(async num =>
             {
                 sum += num.Num_;
             });
@@ -84,10 +84,7 @@ namespace math
 
         public async Task DivMany(IAsyncStreamReader<DivArgs> requestStream, IServerStreamWriter<DivReply> responseStream, ServerCallContext context)
         {
-            await requestStream.ForEach(async divArgs =>
-            {
-                await responseStream.WriteAsync(DivInternal(divArgs));
-            });
+            await requestStream.ForEachAsync(async divArgs => await responseStream.WriteAsync(DivInternal(divArgs)));
         }
 
         static DivReply DivInternal(DivArgs args)
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
index 71844156556b5921bd552b5dc1e97b360ab79a27..c4caa3b57aa99982dd71a660d973ca0ab3476988 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
@@ -92,11 +92,11 @@ namespace Grpc.HealthCheck.Tests
         public void NullsRejected()
         {
             var impl = new HealthServiceImpl();
-            Assert.Throws(typeof(NullReferenceException), () => impl.SetStatus(null, "", HealthCheckResponse.Types.ServingStatus.SERVING));
-            Assert.Throws(typeof(NullReferenceException), () => impl.SetStatus("", null, HealthCheckResponse.Types.ServingStatus.SERVING));
+            Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus(null, "", HealthCheckResponse.Types.ServingStatus.SERVING));
+            Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus("", null, HealthCheckResponse.Types.ServingStatus.SERVING));
 
-            Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus(null, ""));
-            Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus("", null));
+            Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus(null, ""));
+            Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus("", null));
         }
 
         private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string host, string service)
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 6802de489dcbe220d9a061559c5926a6d366eae2..c918f60127a9f216bf675886d47eebfadeaa2e93 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -215,7 +215,7 @@ namespace Grpc.IntegrationTesting
 
             using (var call = client.StreamingInputCall())
             {
-                await call.RequestStream.WriteAll(bodySizes);
+                await call.RequestStream.WriteAllAsync(bodySizes);
 
                 var response = await call.ResponseAsync;
                 Assert.AreEqual(74922, response.AggregatedPayloadSize);
@@ -237,7 +237,7 @@ namespace Grpc.IntegrationTesting
 
             using (var call = client.StreamingOutputCall(request))
             {
-                var responseList = await call.ResponseStream.ToList();
+                var responseList = await call.ResponseStream.ToListAsync();
                 foreach (var res in responseList)
                 {
                     Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type);
@@ -303,7 +303,7 @@ namespace Grpc.IntegrationTesting
             {
                 await call.RequestStream.CompleteAsync();
 
-                var responseList = await call.ResponseStream.ToList();
+                var responseList = await call.ResponseStream.ToListAsync();
                 Assert.AreEqual(0, responseList.Count);
             }
             Console.WriteLine("Passed!");
diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
index ccf9fe6ced673b0b6afcb084b55b02b485c150b4..ceebd5dd8c1ade593c611eda2931ca2ff182b894 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
@@ -71,7 +71,7 @@ namespace grpc.testing
         public async Task<StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<StreamingInputCallRequest> requestStream, ServerCallContext context)
         {
             int sum = 0;
-            await requestStream.ForEach(async request =>
+            await requestStream.ForEachAsync(async request =>
             {
                 sum += request.Payload.Body.Length;
             });
@@ -80,7 +80,7 @@ namespace grpc.testing
 
         public async Task FullDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
         {
-            await requestStream.ForEach(async request =>
+            await requestStream.ForEachAsync(async request =>
             {
                 foreach (var responseParam in request.ResponseParametersList)
                 {