diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 5890617acf5ef0f88090e7e130bd364ff63e818c..c46c4d67620d14875fd434dd76f396a2142477bb 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -9,12 +9,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcCore", "GrpcCore\GrpcCo
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcCoreTests", "GrpcCoreTests\GrpcCoreTests.csproj", "{86EC5CB4-4EA2-40A2-8057-86542A0353BB}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcApiTests", "GrpcApiTests\GrpcApiTests.csproj", "{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|x86 = Debug|x86
 		Release|x86 = Release|x86
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.Build.0 = Debug|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.ActiveCfg = Release|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.Build.0 = Release|Any CPU
 		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.ActiveCfg = Debug|x86
 		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.Build.0 = Debug|x86
 		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.ActiveCfg = Release|x86
diff --git a/src/csharp/GrpcApi/DummyMathServiceClient.cs b/src/csharp/GrpcApi/DummyMathServiceClient.cs
deleted file mode 100644
index 6799109be42af262867790922875e56a4794f96b..0000000000000000000000000000000000000000
--- a/src/csharp/GrpcApi/DummyMathServiceClient.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Collections.Generic;
-using System.Reactive.Linq;
-
-namespace math
-{
-//	/// <summary>
-//	/// Dummy local implementation of math service.
-//	/// </summary>
-//	public class DummyMathServiceClient : IMathServiceClient
-//	{
-//		public DivReply Div(DivArgs args, CancellationToken token = default(CancellationToken))
-//		{
-//			// TODO: cancellation...
-//			return DivInternal(args);
-//		}
-//		
-//		public Task<DivReply> DivAsync(DivArgs args, CancellationToken token = default(CancellationToken))
-//		{
-//			return Task.Factory.StartNew(() => DivInternal(args), token);
-//		}
-//
-//		public IObservable<Num> Fib(FibArgs args, CancellationToken token = default(CancellationToken))
-//		{
-//			if (args.Limit > 0)
-//			{
-//				// TODO: cancellation
-//				return FibInternal(args.Limit).ToObservable();
-//			}
-//
-//			throw new NotImplementedException("Not implemented yet");
-//		}
-//
-//		public Task<Num> Sum(IObservable<Num> inputs, CancellationToken token = default(CancellationToken))
-//		{
-//			// TODO: implement
-//			inputs = null;
-//			return Task.Factory.StartNew(() => Num.CreateBuilder().Build(), token);
-//		}
-//
-//		public IObservable<DivReply> DivMany(IObservable<DivArgs> inputs, CancellationToken token = default(CancellationToken))
-//		{
-//			// TODO: implement
-//			inputs = null;
-//			return new List<DivReply> { }.ToObservable ();
-//		}
-//
-//
-//		DivReply DivInternal(DivArgs args)
-//		{
-//			long quotient = args.Dividend / args.Divisor;
-//			long remainder = args.Dividend % args.Divisor;
-//			return new DivReply.Builder{ Quotient = quotient, Remainder = remainder }.Build();
-//		}
-//
-//		IEnumerable<Num> FibInternal(long n)
-//		{
-//			long a = 0;
-//			yield return new Num.Builder{Num_=a}.Build();
-//
-//			long b = 1;
-//			for (long i = 0; i < n - 1; i++)
-//			{
-//				long temp = a;
-//				a = b;
-//				b = temp + b;
-//				yield return new Num.Builder{Num_=a}.Build();
-//			}
-//		}
-//	}
-}
-
diff --git a/src/csharp/GrpcApi/Examples.cs b/src/csharp/GrpcApi/Examples.cs
index d45b702708e0afd66959cfc2afc295a509034380..d2a6cc01fdbe7b2103760d7d5c87e3c7346b0681 100644
--- a/src/csharp/GrpcApi/Examples.cs
+++ b/src/csharp/GrpcApi/Examples.cs
@@ -2,32 +2,33 @@ using System;
 using System.Threading.Tasks;
 using System.Collections.Generic;
 using System.Reactive.Linq;
+using Google.GRPC.Core.Utils;
 
 namespace math
 {
 	public class Examples
 	{
-		public static void DivExample(IMathServiceClient stub)
+		public static void DivExample(MathGrpc.IMathServiceClient stub)
 		{
 			DivReply result = stub.Div(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
 			Console.WriteLine("Div Result: " + result);
 		}
 
-		public static void DivAsyncExample(IMathServiceClient stub)
+		public static void DivAsyncExample(MathGrpc.IMathServiceClient stub)
 		{
 			Task<DivReply> call = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
 			DivReply result = call.Result;
 			Console.WriteLine(result);
 		}
 
-		public static void DivAsyncWithCancellationExample(IMathServiceClient stub)
+		public static void DivAsyncWithCancellationExample(MathGrpc.IMathServiceClient stub)
 		{
 			Task<DivReply> call = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
 			DivReply result = call.Result;
 			Console.WriteLine(result);
 		}
 
-		public static void FibExample(IMathServiceClient stub)
+		public static void FibExample(MathGrpc.IMathServiceClient stub)
 		{
             var recorder = new RecordingObserver<Num>();
             stub.Fib(new FibArgs.Builder { Limit = 5 }.Build(), recorder);
@@ -36,7 +37,7 @@ namespace math
             Console.WriteLine("Fib Result: " + string.Join("|", recorder.ToList().Result));
 		}
 
-		public static void SumExample(IMathServiceClient stub)
+		public static void SumExample(MathGrpc.IMathServiceClient stub)
 		{
 			List<Num> numbers = new List<Num>{new Num.Builder { Num_ = 1 }.Build(), 
 				new Num.Builder { Num_ = 2 }.Build(),
@@ -51,7 +52,7 @@ namespace math
 			Console.WriteLine("Sum Result: " + res.Task.Result);
 		}
 
-		public static void DivManyExample(IMathServiceClient stub)
+		public static void DivManyExample(MathGrpc.IMathServiceClient stub)
 		{
 			List<DivArgs> divArgsList = new List<DivArgs>{
 				new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
@@ -71,7 +72,7 @@ namespace math
 			Console.WriteLine("DivMany Result: " + string.Join("|", recorder.ToList().Result));
 		}
 
-		public static void DependendRequestsExample(IMathServiceClient stub)
+		public static void DependendRequestsExample(MathGrpc.IMathServiceClient stub)
 		{
 			var numberList = new List<Num>
 			{ new Num.Builder{ Num_ = 1 }.Build(), 
diff --git a/src/csharp/GrpcApi/GrpcApi.csproj b/src/csharp/GrpcApi/GrpcApi.csproj
index d0377828b5463547a2e6c723ed6d94695452d0b7..07bd6f6efbe54a0bd399eff8469dac4ae8235162 100644
--- a/src/csharp/GrpcApi/GrpcApi.csproj
+++ b/src/csharp/GrpcApi/GrpcApi.csproj
@@ -48,11 +48,9 @@
   <ItemGroup>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Examples.cs" />
-    <Compile Include="IMathServiceClient.cs" />
     <Compile Include="Math.cs" />
-    <Compile Include="DummyMathServiceClient.cs" />
-    <Compile Include="MathServiceClientStub.cs" />
-    <Compile Include="RecordingObserver.cs" />
+    <Compile Include="MathGrpc.cs" />
+    <Compile Include="MathServiceImpl.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
diff --git a/src/csharp/GrpcApi/IMathServiceClient.cs b/src/csharp/GrpcApi/IMathServiceClient.cs
deleted file mode 100644
index 51385a328f49a20991a88607c6418fc28b714071..0000000000000000000000000000000000000000
--- a/src/csharp/GrpcApi/IMathServiceClient.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Collections.Generic;
-using System.Reactive.Linq;
-using Google.GRPC.Core;
-
-namespace math
-{
-	/// <summary>
-	/// Hand-written stub for MathService defined in math.proto.
-	/// This code will be generated by gRPC codegen in the future.
-	/// </summary>
-	public interface IMathServiceClient
-	{
-		DivReply Div(DivArgs args, CancellationToken token = default(CancellationToken));
-
-		Task<DivReply> DivAsync(DivArgs args, CancellationToken token = default(CancellationToken));
-
-		Task Fib(FibArgs args, IObserver<Num> outputs, CancellationToken token = default(CancellationToken));
-
-		ClientStreamingAsyncResult<Num, Num> Sum(CancellationToken token = default(CancellationToken));
-
-		IObserver<DivArgs> DivMany(IObserver<DivReply> outputs, CancellationToken token = default(CancellationToken));
-	}
-}
\ No newline at end of file
diff --git a/src/csharp/GrpcApi/MathGrpc.cs b/src/csharp/GrpcApi/MathGrpc.cs
new file mode 100644
index 0000000000000000000000000000000000000000..520fec437aba90bac3e6354caada181e45ae7fc2
--- /dev/null
+++ b/src/csharp/GrpcApi/MathGrpc.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Reactive.Linq;
+using Google.GRPC.Core;
+
+namespace math
+{
+    /// <summary>
+    /// Math service definitions (this is handwritten version of code that will normally be generated).
+    /// </summary>
+    public class MathGrpc
+    {
+        readonly static Marshaller<DivArgs> divArgsMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), DivArgs.ParseFrom);
+        readonly static Marshaller<DivReply> divReplyMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), DivReply.ParseFrom);
+        readonly static Marshaller<Num> numMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), Num.ParseFrom);
+        readonly static Marshaller<FibArgs> fibArgsMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), FibArgs.ParseFrom);
+
+        readonly static Method<DivArgs, DivReply> divMethod = new Method<DivArgs, DivReply>(
+            MethodType.Unary,
+            "/math.Math/Div",
+            divArgsMarshaller,
+            divReplyMarshaller
+        );
+        readonly static Method<FibArgs, Num> fibMethod = new Method<FibArgs, Num>(
+            MethodType.ServerStreaming,
+            "/math.Math/Fib",
+            fibArgsMarshaller,
+            numMarshaller
+        );
+        readonly static Method<Num, Num> sumMethod = new Method<Num, Num>(
+            MethodType.ClientStreaming,
+            "/math.Math/Sum",
+            numMarshaller,
+            numMarshaller
+        );
+        readonly static Method<DivArgs, DivReply> divManyMethod = new Method<DivArgs, DivReply>(
+            MethodType.DuplexStreaming,
+            "/math.Math/DivMany",
+            divArgsMarshaller,
+            divReplyMarshaller
+        );
+
+        public interface IMathServiceClient
+        {
+            DivReply Div(DivArgs request, CancellationToken token = default(CancellationToken));
+
+            Task<DivReply> DivAsync(DivArgs request, CancellationToken token = default(CancellationToken));
+
+            Task Fib(FibArgs request, IObserver<Num> responseObserver, CancellationToken token = default(CancellationToken));
+
+            ClientStreamingAsyncResult<Num, Num> Sum(CancellationToken token = default(CancellationToken));
+
+            IObserver<DivArgs> DivMany(IObserver<DivReply> responseObserver, CancellationToken token = default(CancellationToken));
+        }
+
+        public class MathServiceClientStub : IMathServiceClient
+        {
+            readonly Channel channel;
+
+            public MathServiceClientStub(Channel channel)
+            {
+                this.channel = channel;
+            }
+
+            public DivReply Div(DivArgs request, CancellationToken token = default(CancellationToken))
+            {
+                var call = new Google.GRPC.Core.Call<DivArgs, DivReply>(divMethod, channel);
+                return Calls.BlockingUnaryCall(call, request, token);
+            }
+
+            public Task<DivReply> DivAsync(DivArgs request, CancellationToken token = default(CancellationToken))
+            {
+                var call = new Google.GRPC.Core.Call<DivArgs, DivReply>(divMethod, channel);
+                return Calls.AsyncUnaryCall(call, request, token);
+            }
+
+            public Task Fib(FibArgs request, IObserver<Num> responseObserver, CancellationToken token = default(CancellationToken))
+            {
+                var call = new Google.GRPC.Core.Call<FibArgs, Num>(fibMethod, channel);
+                return Calls.AsyncServerStreamingCall(call, request, responseObserver, token);
+            }
+
+            public ClientStreamingAsyncResult<Num, Num> Sum(CancellationToken token = default(CancellationToken))
+            {
+                var call = new Google.GRPC.Core.Call<Num, Num>(sumMethod, channel);
+                return Calls.AsyncClientStreamingCall(call, token);
+            }
+
+            public IObserver<DivArgs> DivMany(IObserver<DivReply> responseObserver, CancellationToken token = default(CancellationToken))
+            {
+                var call = new Google.GRPC.Core.Call<DivArgs, DivReply>(divManyMethod, channel);
+                return Calls.DuplexStreamingCall(call, responseObserver, token);
+            }
+        }
+
+        // server-side interface
+        public interface IMathService
+        {
+            void Div(DivArgs request, IObserver<DivReply> responseObserver);
+
+            void Fib(FibArgs request, IObserver<Num> responseObserver);
+
+            IObserver<Num> Sum(IObserver<Num> responseObserver);
+
+            IObserver<DivArgs> DivMany(IObserver<DivReply> responseObserver);
+        }
+
+        public static ServerServiceDefinition BindService(IMathService serviceImpl)
+        {
+            return ServerServiceDefinition.CreateBuilder("/math.Math/")
+                .AddMethod(divMethod, serviceImpl.Div)
+                .AddMethod(fibMethod, serviceImpl.Fib)
+                .AddMethod(sumMethod, serviceImpl.Sum)
+                .AddMethod(divManyMethod, serviceImpl.DivMany).Build();
+        }
+
+        public static IMathServiceClient NewStub(Channel channel)
+        {
+            return new MathServiceClientStub(channel);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/csharp/GrpcApi/MathServiceClientStub.cs b/src/csharp/GrpcApi/MathServiceClientStub.cs
deleted file mode 100644
index 493c186b8e5fd748f9056986000f9a890e497c9b..0000000000000000000000000000000000000000
--- a/src/csharp/GrpcApi/MathServiceClientStub.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Collections.Generic;
-using System.Reactive.Linq;
-using Google.GRPC.Core;
-
-namespace math
-{
-	/// <summary>
-	/// Implementation of math service stub (this is handwritten version of code 
-	/// that will normally be generated).
-	/// </summary>
-	public class MathServiceClientStub : IMathServiceClient
-	{
-		readonly Channel channel;
-        readonly TimeSpan methodTimeout;
-
-		public MathServiceClientStub(Channel channel, TimeSpan methodTimeout)
-		{
-			this.channel = channel;
-            this.methodTimeout = methodTimeout;
-		}
-
-		public DivReply Div(DivArgs args, CancellationToken token = default(CancellationToken))
-		{
-            var call = new Google.GRPC.Core.Call<DivArgs, DivReply>("/math.Math/Div", Serialize_DivArgs, Deserialize_DivReply, methodTimeout, channel);
-            return Calls.BlockingUnaryCall(call, args, token);
-		}
-
-		public Task<DivReply> DivAsync(DivArgs args, CancellationToken token = default(CancellationToken))
-		{
-            var call = new Google.GRPC.Core.Call<DivArgs, DivReply>("/math.Math/Div", Serialize_DivArgs, Deserialize_DivReply, methodTimeout, channel);
-            return Calls.AsyncUnaryCall(call, args, token);
-		}
-
-        public Task Fib(FibArgs args, IObserver<Num> outputs, CancellationToken token = default(CancellationToken))
-		{
-            var call = new Google.GRPC.Core.Call<FibArgs, Num>("/math.Math/Fib", Serialize_FibArgs, Deserialize_Num, methodTimeout, channel);
-            return Calls.AsyncServerStreamingCall(call, args, outputs, token);
-		}
-
-        public ClientStreamingAsyncResult<Num, Num> Sum(CancellationToken token = default(CancellationToken)) 
-		{
-            var call = new Google.GRPC.Core.Call<Num, Num>("/math.Math/Sum", Serialize_Num, Deserialize_Num, methodTimeout, channel);
-            return Calls.AsyncClientStreamingCall(call, token);
-		}
-
-        public IObserver<DivArgs> DivMany(IObserver<DivReply> outputs, CancellationToken token = default(CancellationToken))
-		{
-            var call = new Google.GRPC.Core.Call<DivArgs, DivReply>("/math.Math/DivMany", Serialize_DivArgs, Deserialize_DivReply, methodTimeout, channel);
-            return Calls.DuplexStreamingCall(call, outputs, token);
-		}
-
-        private static byte[] Serialize_DivArgs(DivArgs arg) {
-            return arg.ToByteArray();
-        }
-
-        private static byte[] Serialize_FibArgs(FibArgs arg) {
-            return arg.ToByteArray();
-        }
-
-        private static byte[] Serialize_Num(Num arg) {
-            return arg.ToByteArray();
-        }
-
-        private static DivReply Deserialize_DivReply(byte[] payload) {
-            return DivReply.CreateBuilder().MergeFrom(payload).Build();
-        }
-
-        private static Num Deserialize_Num(byte[] payload) {
-            return Num.CreateBuilder().MergeFrom(payload).Build();
-        }
-	}
-}
\ No newline at end of file
diff --git a/src/csharp/GrpcApi/MathServiceImpl.cs b/src/csharp/GrpcApi/MathServiceImpl.cs
new file mode 100644
index 0000000000000000000000000000000000000000..27abc4ce17c620cfc54af9b8626b8ba1106bf119
--- /dev/null
+++ b/src/csharp/GrpcApi/MathServiceImpl.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Reactive.Linq;
+using Google.GRPC.Core.Utils;
+
+namespace math
+{
+    /// <summary>
+    /// Implementation of MathService server
+    /// </summary>
+    public class MathServiceImpl : MathGrpc.IMathService
+    {
+        public void Div(DivArgs request, IObserver<DivReply> responseObserver)
+        {
+            var response = DivInternal(request);
+            responseObserver.OnNext(response);
+            responseObserver.OnCompleted();
+        }
+
+        public void Fib(FibArgs request, IObserver<Num> responseObserver)
+        {
+            if (request.Limit <= 0)
+            {
+                // TODO: support cancellation....
+                throw new NotImplementedException("Not implemented yet");
+            }
+                                  
+            if (request.Limit > 0)
+            {
+                foreach (var num in FibInternal(request.Limit))
+                {
+                    responseObserver.OnNext(num);
+                }
+                responseObserver.OnCompleted();
+            }
+        }
+
+        public IObserver<Num> Sum(IObserver<Num> responseObserver)
+        {
+            var recorder = new RecordingObserver<Num>();
+            Task.Factory.StartNew(() => {
+
+                List<Num> inputs = recorder.ToList().Result;
+
+                long sum = 0;
+                foreach (Num num in inputs)
+                {
+                    sum += num.Num_;
+                }
+
+                responseObserver.OnNext(Num.CreateBuilder().SetNum_(sum).Build());
+                responseObserver.OnCompleted();
+            });
+            return recorder;
+        }
+
+        public IObserver<DivArgs> DivMany(IObserver<DivReply> responseObserver)
+        {
+            return new DivObserver(responseObserver);
+        }
+
+        static DivReply DivInternal(DivArgs args)
+        {
+            long quotient = args.Dividend / args.Divisor;
+            long remainder = args.Dividend % args.Divisor;
+            return new DivReply.Builder { Quotient = quotient, Remainder = remainder }.Build();
+        }
+
+        static IEnumerable<Num> FibInternal(long n)
+        {
+            long a = 1;
+            yield return new Num.Builder { Num_=a }.Build();
+
+            long b = 1;
+            for (long i = 0; i < n - 1; i++)
+            {
+                long temp = a;
+                a = b;
+                b = temp + b;
+                yield return new Num.Builder { Num_=a }.Build();
+            }
+        }
+
+        private class DivObserver : IObserver<DivArgs> {
+
+            readonly IObserver<DivReply> responseObserver;
+
+            public DivObserver(IObserver<DivReply> responseObserver)
+            {
+                this.responseObserver = responseObserver;
+            }
+            
+            public void OnCompleted()
+            {
+                Task.Factory.StartNew(() =>
+                    responseObserver.OnCompleted());
+            }
+
+            public void OnError(Exception error)
+            {
+                throw new NotImplementedException();
+            }
+
+            public void OnNext(DivArgs value)
+            {
+                // TODO: currently we need this indirection because
+                // responseObserver waits for write to finish, this
+                // callback is called from grpc threadpool which
+                // currently only has one thread.
+                // Same story for OnCompleted().
+                Task.Factory.StartNew(() => 
+                responseObserver.OnNext(DivInternal(value)));
+            }
+        }
+    }
+}
+
diff --git a/src/csharp/GrpcApiTests/.gitignore b/src/csharp/GrpcApiTests/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..2cc8cca52d01ba50f6398e7cb7a147161dad578c
--- /dev/null
+++ b/src/csharp/GrpcApiTests/.gitignore
@@ -0,0 +1,2 @@
+test-results
+bin
diff --git a/src/csharp/GrpcApiTests/GrpcApiTests.csproj b/src/csharp/GrpcApiTests/GrpcApiTests.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..d0aac2b7533a3a6f66aee65074a597d2f8c0d105
--- /dev/null
+++ b/src/csharp/GrpcApiTests/GrpcApiTests.csproj
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>10.0.0</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <RootNamespace>GrpcApiTests</RootNamespace>
+    <AssemblyName>GrpcApiTests</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG;</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>full</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="nunit.framework, Version=2.6.0.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Google.ProtocolBuffers">
+      <HintPath>..\lib\Google.ProtocolBuffers.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="MathClientServerTests.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <ProjectReference Include="..\GrpcApi\GrpcApi.csproj">
+      <Project>{7DC1433E-3225-42C7-B7EA-546D56E27A4B}</Project>
+      <Name>GrpcApi</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\GrpcCore\GrpcCore.csproj">
+      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
+      <Name>GrpcCore</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/csharp/GrpcApiTests/MathClientServerTests.cs b/src/csharp/GrpcApiTests/MathClientServerTests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..aa78b698e85b7b832d07646151837c881942d7c9
--- /dev/null
+++ b/src/csharp/GrpcApiTests/MathClientServerTests.cs
@@ -0,0 +1,115 @@
+using System;
+using NUnit.Framework;
+using Google.GRPC.Core;
+using System.Threading;
+using System.Threading.Tasks;
+using Google.GRPC.Core.Utils;
+using System.Collections.Generic;
+
+namespace math.Tests
+{
+    /// <summary>
+    /// Math client talks to local math server.
+    /// </summary>
+    public class MathClientServerTest
+    {
+        string serverAddr = "localhost:" + PortPicker.PickUnusedPort();
+        Server server;
+        Channel channel;
+        MathGrpc.IMathServiceClient client;
+
+        [TestFixtureSetUp]
+        public void Init()
+        {
+            server = new Server();
+            server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl()));
+            server.AddPort(serverAddr);
+            server.Start();
+            channel = new Channel(serverAddr);
+            client = MathGrpc.NewStub(channel);
+        }
+
+        [Test]
+        public void Div1()
+        {
+            DivReply response = client.Div(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
+            Assert.AreEqual(3, response.Quotient);
+            Assert.AreEqual(1, response.Remainder);
+        }
+
+        [Test]
+        public void Div2()
+        {
+            DivReply response = client.Div(new DivArgs.Builder { Dividend = 0, Divisor = 1 }.Build());
+            Assert.AreEqual(0, response.Quotient);
+            Assert.AreEqual(0, response.Remainder);
+        }
+
+        // TODO: test division by zero
+
+        [Test]
+        public void DivAsync()
+        {
+            DivReply response = client.DivAsync(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build()).Result;
+            Assert.AreEqual(3, response.Quotient);
+            Assert.AreEqual(1, response.Remainder);
+        }
+
+        [Test]
+        public void Fib()
+        {
+            var recorder = new RecordingObserver<Num>();
+            client.Fib(new FibArgs.Builder { Limit = 6 }.Build(), recorder);
+
+            CollectionAssert.AreEqual(new List<long>{1, 1, 2, 3, 5, 8}, 
+                recorder.ToList().Result.ConvertAll((n) => n.Num_));
+        }
+
+        // TODO: test Fib with limit=0 and cancellation
+        [Test]
+        public void Sum()
+        {
+            var res = client.Sum();
+            foreach (var num in new long[] { 10, 20, 30 }) {
+                res.Inputs.OnNext(Num.CreateBuilder().SetNum_(num).Build());
+            }
+            res.Inputs.OnCompleted();
+
+            Assert.AreEqual(60, res.Task.Result.Num_);
+        }
+
+        [Test]
+        public void DivMany()
+        {
+            List<DivArgs> divArgsList = new List<DivArgs>{
+                new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
+                new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
+                new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build()
+            };
+
+            var recorder = new RecordingObserver<DivReply>();
+            var requestObserver = client.DivMany(recorder);
+
+            foreach (var arg in divArgsList)
+            {
+                requestObserver.OnNext(arg);
+            }
+            requestObserver.OnCompleted();
+
+            var result = recorder.ToList().Result;
+
+            CollectionAssert.AreEqual(new long[] {3, 4, 3}, result.ConvertAll((divReply) => divReply.Quotient));
+            CollectionAssert.AreEqual(new long[] {1, 16, 1}, result.ConvertAll((divReply) => divReply.Remainder));
+        }
+
+        [TestFixtureTearDown]
+        public void Cleanup()
+        {
+            channel.Dispose();
+
+            server.ShutdownAsync().Wait();
+            GrpcEnvironment.Shutdown();
+        }
+    }
+}
+
diff --git a/src/csharp/GrpcApiTests/Properties/AssemblyInfo.cs b/src/csharp/GrpcApiTests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0928404429fe045ddea1a75e796abb2c227eefed
--- /dev/null
+++ b/src/csharp/GrpcApiTests/Properties/AssemblyInfo.cs
@@ -0,0 +1,22 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes. 
+// Change them to the values specific to your project.
+[assembly: AssemblyTitle("GrpcApiTests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("jtattermusch")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+[assembly: AssemblyVersion("1.0.*")]
+// The following attributes are used to specify the signing key for the assembly, 
+// if desired. See the Mono documentation for more information about signing.
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/src/csharp/GrpcCore/Call.cs b/src/csharp/GrpcCore/Call.cs
index d3847a800917d6fae1ceca33338cb77b9e37eaa0..66e70041805cc5a2543411f41789a9614a46e586 100644
--- a/src/csharp/GrpcCore/Call.cs
+++ b/src/csharp/GrpcCore/Call.cs
@@ -24,8 +24,8 @@ namespace Google.GRPC.Core
         public Call(Method<TRequest, TResponse> method, Channel channel)
         {
             this.methodName = method.Name;
-            this.requestSerializer = method.RequestMarshaller.Serialize;
-            this.responseDeserializer = method.ResponseMarshaller.Deserialize;
+            this.requestSerializer = method.RequestMarshaller.Serializer;
+            this.responseDeserializer = method.ResponseMarshaller.Deserializer;
             this.channel = channel;
         }
 
diff --git a/src/csharp/GrpcCore/GrpcCore.csproj b/src/csharp/GrpcCore/GrpcCore.csproj
index 2ad0f9154cc00e98563b06c6c7e25ec865f5d39d..fbfe50e4d88e29bd8fe44a18c7590bae9a721c37 100644
--- a/src/csharp/GrpcCore/GrpcCore.csproj
+++ b/src/csharp/GrpcCore/GrpcCore.csproj
@@ -55,13 +55,17 @@
     <Compile Include="Internal\ServerSafeHandle.cs" />
     <Compile Include="Internal\StreamingInputObserver.cs" />
     <Compile Include="Method.cs" />
-    <Compile Include="IMarshaller.cs" />
     <Compile Include="ServerCalls.cs" />
     <Compile Include="ServerCallHandler.cs" />
     <Compile Include="Internal\ServerWritingObserver.cs" />
+    <Compile Include="Marshaller.cs" />
+    <Compile Include="ServerServiceDefinition.cs" />
+    <Compile Include="Utils\RecordingObserver.cs" />
+    <Compile Include="Utils\PortPicker.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
     <Folder Include="Internal\" />
+    <Folder Include="Utils\" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/GrpcCore/IMarshaller.cs b/src/csharp/GrpcCore/IMarshaller.cs
deleted file mode 100644
index eb08d8d3860dfb95238ca2f68075524cf23574f1..0000000000000000000000000000000000000000
--- a/src/csharp/GrpcCore/IMarshaller.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System;
-
-namespace Google.GRPC.Core
-{
-    /// <summary>
-    /// For serializing and deserializing messages.
-    /// </summary>
-    public interface IMarshaller<T>
-    {
-        byte[] Serialize(T value);
-
-        T Deserialize(byte[] payload);
-    }
-
-    /// <summary>
-    /// UTF-8 Marshalling for string. Useful for testing.
-    /// </summary>
-    internal class StringMarshaller : IMarshaller<string> {
-
-        public byte[] Serialize(string value)
-        {
-            return System.Text.Encoding.UTF8.GetBytes(value);
-        }
-
-        public string Deserialize(byte[] payload)
-        {
-            return System.Text.Encoding.UTF8.GetString(payload);
-        }
-    }
-}
-
diff --git a/src/csharp/GrpcCore/Marshaller.cs b/src/csharp/GrpcCore/Marshaller.cs
new file mode 100644
index 0000000000000000000000000000000000000000..242524063c76185e9e6b0eb2cf9bd679089f4af6
--- /dev/null
+++ b/src/csharp/GrpcCore/Marshaller.cs
@@ -0,0 +1,54 @@
+using System;
+
+namespace Google.GRPC.Core
+{
+    /// <summary>
+    /// For serializing and deserializing messages.
+    /// </summary>
+    public struct Marshaller<T>
+    {
+        readonly Func<T,byte[]> serializer;
+        readonly Func<byte[],T> deserializer;
+
+        public Marshaller(Func<T, byte[]> serializer, Func<byte[], T> deserializer)
+        {
+            this.serializer = serializer;
+            this.deserializer = deserializer;
+        }
+
+        public Func<T, byte[]> Serializer
+        {
+            get
+            {
+                return this.serializer;
+            }
+        }
+
+        public Func<byte[], T> Deserializer
+        {
+            get
+            {
+                return this.deserializer;
+            }
+        }
+    }
+
+    public static class Marshallers {
+
+        public static Marshaller<T> Create<T>(Func<T,byte[]> serializer, Func<byte[],T> deserializer)
+        {
+            return new Marshaller<T>(serializer, deserializer);
+        }
+
+        public static Marshaller<string> StringMarshaller
+        {
+            get
+            {
+                return new Marshaller<string>(System.Text.Encoding.UTF8.GetBytes, 
+                                              System.Text.Encoding.UTF8.GetString);
+            }
+        }
+
+    }
+}
+
diff --git a/src/csharp/GrpcCore/Method.cs b/src/csharp/GrpcCore/Method.cs
index 27901156950edc954016178627f0a545132e37e1..9067ae8c9474bcb41616c8481fd390e913e92aa1 100644
--- a/src/csharp/GrpcCore/Method.cs
+++ b/src/csharp/GrpcCore/Method.cs
@@ -17,10 +17,10 @@ namespace Google.GRPC.Core
     {
         readonly MethodType type;
         readonly string name;
-        readonly IMarshaller<TRequest> requestMarshaller;
-        readonly IMarshaller<TResponse> responseMarshaller;
+        readonly Marshaller<TRequest> requestMarshaller;
+        readonly Marshaller<TResponse> responseMarshaller;
 
-        public Method(MethodType type, string name, IMarshaller<TRequest> requestMarshaller, IMarshaller<TResponse> responseMarshaller)
+        public Method(MethodType type, string name, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller)
         {
             this.type = type;
             this.name = name;
@@ -44,7 +44,7 @@ namespace Google.GRPC.Core
             }
         }
 
-        public IMarshaller<TRequest> RequestMarshaller
+        public Marshaller<TRequest> RequestMarshaller
         {
             get
             {
@@ -52,7 +52,7 @@ namespace Google.GRPC.Core
             }
         }
 
-        public IMarshaller<TResponse> ResponseMarshaller
+        public Marshaller<TResponse> ResponseMarshaller
         {
             get
             {
diff --git a/src/csharp/GrpcCore/Server.cs b/src/csharp/GrpcCore/Server.cs
index 4e9d114f850af8ab1acc35608a9cd79aa6d82d19..d3bc81e5744ac015af4461867a5eb970063267d1 100644
--- a/src/csharp/GrpcCore/Server.cs
+++ b/src/csharp/GrpcCore/Server.cs
@@ -38,10 +38,14 @@ namespace Google.GRPC.Core
             this.serverShutdownHandler = HandleServerShutdown;
         }
 
-        // only call before Start(), this will be in server builder in the future.
-        internal void AddCallHandler(string methodName, IServerCallHandler handler) {
-            callHandlers.Add(methodName, handler);
+        // only call this before Start()
+        public void AddServiceDefinition(ServerServiceDefinition serviceDefinition) {
+            foreach(var entry in serviceDefinition.CallHandlers)
+            {
+                callHandlers.Add(entry.Key, entry.Value);
+            }
         }
+
         // only call before Start()
         public int AddPort(string addr) {
             return handle.AddPort(addr);
@@ -113,7 +117,12 @@ namespace Google.GRPC.Core
             try
             {
                 var ev = new EventSafeHandleNotOwned(eventPtr);
-                newRpcQueue.Add(new NewRpcInfo(ev.GetCall(), ev.GetServerRpcNewMethod()));
+                var rpcInfo = new NewRpcInfo(ev.GetCall(), ev.GetServerRpcNewMethod());
+
+                // after server shutdown, the callback returns with null call
+                if (!rpcInfo.Call.IsInvalid) {
+                    newRpcQueue.Add(rpcInfo);
+                }
             }
             catch (Exception e)
             {
diff --git a/src/csharp/GrpcCore/ServerCallHandler.cs b/src/csharp/GrpcCore/ServerCallHandler.cs
index 08d527a019f991842d201d1d13981f19f95404be..67103791b431d14c667e015b3aaa5363ff5348b0 100644
--- a/src/csharp/GrpcCore/ServerCallHandler.cs
+++ b/src/csharp/GrpcCore/ServerCallHandler.cs
@@ -22,8 +22,8 @@ namespace Google.GRPC.Core
         public void StartCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
         {
             var asyncCall = new AsyncCall<TResponse, TRequest>(
-                (msg) => method.ResponseMarshaller.Serialize(msg),
-                (payload) => method.RequestMarshaller.Deserialize(payload));
+                method.ResponseMarshaller.Serializer,
+                method.RequestMarshaller.Deserializer);
 
             asyncCall.InitializeServer(call);
             asyncCall.Accept(cq);
@@ -34,9 +34,6 @@ namespace Google.GRPC.Core
             handler(request, responseObserver);
 
             asyncCall.Halfclosed.Wait();
-            // TODO: wait until writing is finished
-
-            asyncCall.WriteStatusAsync(new Status(StatusCode.GRPC_STATUS_OK, "")).Wait();
             asyncCall.Finished.Wait();
         }
     }
@@ -55,8 +52,8 @@ namespace Google.GRPC.Core
         public void StartCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
         {
             var asyncCall = new AsyncCall<TResponse, TRequest>(
-                (msg) => method.ResponseMarshaller.Serialize(msg),
-                (payload) => method.RequestMarshaller.Deserialize(payload));
+                method.ResponseMarshaller.Serializer,
+                method.RequestMarshaller.Deserializer);
 
             asyncCall.InitializeServer(call);
             asyncCall.Accept(cq);
@@ -68,8 +65,6 @@ namespace Google.GRPC.Core
             asyncCall.StartReadingToStream(requestObserver);
 
             asyncCall.Halfclosed.Wait();
-
-            asyncCall.WriteStatusAsync(new Status(StatusCode.GRPC_STATUS_OK, "")).Wait();
             asyncCall.Finished.Wait();
         }
     }
diff --git a/src/csharp/GrpcCore/ServerServiceDefinition.cs b/src/csharp/GrpcCore/ServerServiceDefinition.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7f1cc6284e4ea68641e8a22b306846fa29a56065
--- /dev/null
+++ b/src/csharp/GrpcCore/ServerServiceDefinition.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+
+namespace Google.GRPC.Core
+{
+    public class ServerServiceDefinition
+    {
+        readonly string serviceName;
+        // TODO: we would need an immutable dictionary here...
+        readonly Dictionary<string, IServerCallHandler> callHandlers;
+
+        private ServerServiceDefinition(string serviceName, Dictionary<string, IServerCallHandler> callHandlers)
+        {
+            this.serviceName = serviceName;
+            this.callHandlers = new Dictionary<string, IServerCallHandler>(callHandlers);
+        }
+
+        internal Dictionary<string, IServerCallHandler> CallHandlers
+        {
+            get
+            {
+                return this.callHandlers;
+            }
+        }
+
+
+        public static Builder CreateBuilder(String serviceName)
+        {
+            return new Builder(serviceName);
+        }
+
+        public class Builder
+        {
+            readonly string serviceName;
+            readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<String, IServerCallHandler>();
+
+            public Builder(string serviceName)
+            {
+                this.serviceName = serviceName;
+            }
+
+            public Builder AddMethod<TRequest, TResponse>(
+                Method<TRequest, TResponse> method, 
+                UnaryRequestServerMethod<TRequest, TResponse> handler)
+            {
+                callHandlers.Add(method.Name, ServerCalls.UnaryRequestCall(method, handler));
+                return this;
+            }
+
+            public Builder AddMethod<TRequest, TResponse>(
+                Method<TRequest, TResponse> method, 
+                StreamingRequestServerMethod<TRequest, TResponse> handler)
+            {
+                callHandlers.Add(method.Name, ServerCalls.StreamingRequestCall(method, handler));
+                return this;
+            }
+
+            public ServerServiceDefinition Build()
+            {
+                return new ServerServiceDefinition(serviceName, callHandlers);
+            }
+        }
+    }
+}
+
diff --git a/src/csharp/GrpcCoreTests/Utils.cs b/src/csharp/GrpcCore/Utils/PortPicker.cs
similarity index 90%
rename from src/csharp/GrpcCoreTests/Utils.cs
rename to src/csharp/GrpcCore/Utils/PortPicker.cs
index b0c0a7b6205ed5061c309120db377a561b017003..7c83bf3886df21c81d39ef6a2b0998fecc6b5b9b 100644
--- a/src/csharp/GrpcCoreTests/Utils.cs
+++ b/src/csharp/GrpcCore/Utils/PortPicker.cs
@@ -2,14 +2,12 @@ using System;
 using System.Net;
 using System.Net.Sockets;
 
-namespace Google.GRPC.Core.Tests
+namespace Google.GRPC.Core.Utils
 {
-    /// <summary>
-    /// Testing utils.
-    /// </summary>
-    public class Utils
+    public class PortPicker
     {
         static Random random = new Random();
+
         // TODO: cleanup this code a bit
         public static int PickUnusedPort()
         {
@@ -21,6 +19,7 @@ namespace Google.GRPC.Core.Tests
             } while(!IsPortAvailable(port));
             return port;
         }
+
         // TODO: cleanup this code a bit
         public static bool IsPortAvailable(int port)
         {
diff --git a/src/csharp/GrpcApi/RecordingObserver.cs b/src/csharp/GrpcCore/Utils/RecordingObserver.cs
similarity index 94%
rename from src/csharp/GrpcApi/RecordingObserver.cs
rename to src/csharp/GrpcCore/Utils/RecordingObserver.cs
index 8ba3787905a28bb06dd38f24854b9761456d5625..ca11cc4aa2384a625a561d98dbd57976bd27d291 100644
--- a/src/csharp/GrpcApi/RecordingObserver.cs
+++ b/src/csharp/GrpcCore/Utils/RecordingObserver.cs
@@ -2,7 +2,7 @@ using System;
 using System.Threading.Tasks;
 using System.Collections.Generic;
 
-namespace math
+namespace Google.GRPC.Core.Utils
 {
     public class RecordingObserver<T> : IObserver<T>
     {
diff --git a/src/csharp/GrpcCoreTests/ClientServerTest.cs b/src/csharp/GrpcCoreTests/ClientServerTest.cs
index 511683b00386b88ee610fa70cba244aa4c663027..c700ffbe7ba06a09b9d39eb2fb3295bc7cacf814 100644
--- a/src/csharp/GrpcCoreTests/ClientServerTest.cs
+++ b/src/csharp/GrpcCoreTests/ClientServerTest.cs
@@ -1,35 +1,37 @@
 using System;
 using NUnit.Framework;
+using Google.GRPC.Core;
 using Google.GRPC.Core.Internal;
 using System.Threading;
 using System.Threading.Tasks;
+using Google.GRPC.Core.Utils;
 
 namespace Google.GRPC.Core.Tests
 {
     public class ClientServerTest
     {
-        string serverAddr = "localhost:" + Utils.PickUnusedPort();
+        string serverAddr = "localhost:" + PortPicker.PickUnusedPort();
 
-        private Method<string, string> unaryEchoStringMethod = new Method<string, string>(
+        Method<string, string> unaryEchoStringMethod = new Method<string, string>(
             MethodType.Unary,
             "/tests.Test/UnaryEchoString",
-            new StringMarshaller(),
-            new StringMarshaller());
+            Marshallers.StringMarshaller,
+            Marshallers.StringMarshaller);
 
         [Test]
         public void EmptyCall()
         {
             Server server = new Server();
-
-            server.AddCallHandler(unaryEchoStringMethod.Name, 
-                                  ServerCalls.UnaryRequestCall(unaryEchoStringMethod, HandleUnaryEchoString));
+            server.AddServiceDefinition(
+                ServerServiceDefinition.CreateBuilder("someService")
+                    .AddMethod(unaryEchoStringMethod, HandleUnaryEchoString).Build());
 
             server.AddPort(serverAddr);
             server.Start();
 
             using (Channel channel = new Channel(serverAddr))
             {
-                var call = CreateUnaryEchoStringCall(channel);
+                var call = new Call<string, string>(unaryEchoStringMethod, channel);
 
                 Assert.AreEqual("ABC", Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken)));
                 Assert.AreEqual("abcdef", Calls.BlockingUnaryCall(call, "abcdef", default(CancellationToken)));
@@ -40,11 +42,6 @@ namespace Google.GRPC.Core.Tests
             GrpcEnvironment.Shutdown();
         }
 
-        private Call<string, string> CreateUnaryEchoStringCall(Channel channel)
-        {
-            return new Call<string, string>(unaryEchoStringMethod, channel);
-        }
-
         private void HandleUnaryEchoString(string request, IObserver<string> responseObserver) {
             responseObserver.OnNext(request);
             responseObserver.OnCompleted();
diff --git a/src/csharp/GrpcCoreTests/GrpcCoreTests.csproj b/src/csharp/GrpcCoreTests/GrpcCoreTests.csproj
index 3de0f585cda057e42d72301e09cfaf79234a627a..111f0883db0e28cb0404b79518395a57f8daa742 100644
--- a/src/csharp/GrpcCoreTests/GrpcCoreTests.csproj
+++ b/src/csharp/GrpcCoreTests/GrpcCoreTests.csproj
@@ -39,7 +39,6 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ClientServerTest.cs" />
     <Compile Include="ServerTest.cs" />
-    <Compile Include="Utils.cs" />
     <Compile Include="GrpcEnvironmentTest.cs" />
     <Compile Include="TimespecTest.cs" />
   </ItemGroup>
diff --git a/src/csharp/GrpcCoreTests/ServerTest.cs b/src/csharp/GrpcCoreTests/ServerTest.cs
index e6de95c3363292aada89742d61293d27f0f79f93..6e13bc735f6ec6b0e31e64b8dd9591dc89b337e5 100644
--- a/src/csharp/GrpcCoreTests/ServerTest.cs
+++ b/src/csharp/GrpcCoreTests/ServerTest.cs
@@ -1,6 +1,8 @@
 using System;
 using NUnit.Framework;
 using Google.GRPC.Core.Internal;
+using Google.GRPC.Core;
+using Google.GRPC.Core.Utils;
 
 namespace Google.GRPC.Core.Tests
 {
@@ -10,7 +12,7 @@ namespace Google.GRPC.Core.Tests
         public void StartAndShutdownServer() {
 
             Server server = new Server();
-            server.AddPort("localhost:" + Utils.PickUnusedPort());
+            server.AddPort("localhost:" + PortPicker.PickUnusedPort());
             server.Start();
             server.ShutdownAsync().Wait();
 
diff --git a/src/csharp/GrpcDemo/Program.cs b/src/csharp/GrpcDemo/Program.cs
index 258762dbb99d39440eb3806a503a50b29def85dd..c442c32193e237949f2ab548f8f1e736647fa120 100644
--- a/src/csharp/GrpcDemo/Program.cs
+++ b/src/csharp/GrpcDemo/Program.cs
@@ -12,7 +12,8 @@ namespace Google.GRPC.Demo
 		{
 			using (Channel channel = new Channel("127.0.0.1:23456"))
 			{
-				IMathServiceClient stub = new MathServiceClientStub(channel, Timeout.InfiniteTimeSpan);
+
+				MathGrpc.IMathServiceClient stub = new MathGrpc.MathServiceClientStub(channel);
 				Examples.DivExample(stub);
 
                 Examples.FibExample(stub);