diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index c46c4d67620d14875fd434dd76f396a2142477bb..2fd10cb94affc8517e13bddc60cf68069a02acf7 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -1,8 +1,6 @@
 
 Microsoft Visual Studio Solution File, Format Version 11.00
 # Visual Studio 2010
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcDemo", "GrpcDemo\GrpcDemo.csproj", "{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcApi", "GrpcApi\GrpcApi.csproj", "{7DC1433E-3225-42C7-B7EA-546D56E27A4B}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcCore", "GrpcCore\GrpcCore.csproj", "{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}"
@@ -11,6 +9,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcCoreTests", "GrpcCoreTe
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcApiTests", "GrpcApiTests\GrpcApiTests.csproj", "{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MathClient", "MathClient\MathClient.csproj", "{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InteropClient", "InteropClient\InteropClient.csproj", "{C61154BA-DD4A-4838-8420-0162A28925E0}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|x86 = Debug|x86
@@ -33,12 +35,16 @@ Global
 		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.Build.0 = Debug|Any CPU
 		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.ActiveCfg = Release|Any CPU
 		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.Build.0 = Release|Any CPU
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.Build.0 = Release|x86
 		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.ActiveCfg = Debug|Any CPU
 		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.Build.0 = Debug|Any CPU
 		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.ActiveCfg = Release|Any CPU
 		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(MonoDevelopProperties) = preSolution
-		StartupItem = GrpcDemo\GrpcDemo.csproj
+		StartupItem = GrpcApi\GrpcApi.csproj
 	EndGlobalSection
 EndGlobal
diff --git a/src/csharp/GrpcApi/GrpcApi.csproj b/src/csharp/GrpcApi/GrpcApi.csproj
index bf457a1e6b536303003716eea5707c23ff02e800..f0f11de2167bb87396aa871e9933dac558eef211 100644
--- a/src/csharp/GrpcApi/GrpcApi.csproj
+++ b/src/csharp/GrpcApi/GrpcApi.csproj
@@ -47,13 +47,13 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Examples.cs" />
     <Compile Include="Math.cs" />
     <Compile Include="MathGrpc.cs" />
     <Compile Include="MathServiceImpl.cs" />
     <Compile Include="Empty.cs" />
     <Compile Include="Messages.cs" />
     <Compile Include="TestServiceGrpc.cs" />
+    <Compile Include="MathExamples.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
diff --git a/src/csharp/GrpcApi/Examples.cs b/src/csharp/GrpcApi/MathExamples.cs
similarity index 98%
rename from src/csharp/GrpcApi/Examples.cs
rename to src/csharp/GrpcApi/MathExamples.cs
index d2a6cc01fdbe7b2103760d7d5c87e3c7346b0681..43f0cedef6e928ff68dcccc76f1a1361598f2242 100644
--- a/src/csharp/GrpcApi/Examples.cs
+++ b/src/csharp/GrpcApi/MathExamples.cs
@@ -6,7 +6,7 @@ using Google.GRPC.Core.Utils;
 
 namespace math
 {
-	public class Examples
+	public static class MathExamples
 	{
 		public static void DivExample(MathGrpc.IMathServiceClient stub)
 		{
diff --git a/src/csharp/GrpcDemo/.gitignore b/src/csharp/InteropClient/.gitignore
similarity index 100%
rename from src/csharp/GrpcDemo/.gitignore
rename to src/csharp/InteropClient/.gitignore
diff --git a/src/csharp/InteropClient/InteropClient.cs b/src/csharp/InteropClient/InteropClient.cs
new file mode 100644
index 0000000000000000000000000000000000000000..62091c5fdc384f3979bd9250fd314be14e6d0a9e
--- /dev/null
+++ b/src/csharp/InteropClient/InteropClient.cs
@@ -0,0 +1,172 @@
+using System;
+using NUnit.Framework;
+using System.Text.RegularExpressions;
+using Google.GRPC.Core;
+using Google.ProtocolBuffers;
+using grpc.testing;
+
+namespace InteropClient
+{
+    class InteropClient
+    {
+        private class ClientOptions
+        {
+            public bool help;
+            public string serverHost;
+            public string serverHostOverride;
+            public int? serverPort;
+            public string testCase;
+            public bool useTls;
+            public bool useTestCa;
+        }
+
+        ClientOptions options;
+
+        private InteropClient(ClientOptions options) {
+            this.options = options;
+        }
+
+        public static void Main(string[] args)
+        {
+            Console.WriteLine("gRPC C# interop testing client");
+            ClientOptions options = ParseArguments(args);
+
+            if (options.serverHost == null || !options.serverPort.HasValue || options.testCase == null)
+            {
+                Console.WriteLine("Missing required argument.");
+                Console.WriteLine();
+                options.help = true;
+            }
+
+            if (options.help)
+            {
+                Console.WriteLine("Usage:");
+                Console.WriteLine("  --server_host=HOSTNAME");
+                Console.WriteLine("  --server_host_override=HOSTNAME");
+                Console.WriteLine("  --server_port=PORT");
+                Console.WriteLine("  --test_case=TESTCASE");
+                Console.WriteLine("  --use_tls=BOOLEAN");
+                Console.WriteLine("  --use_test_ca=BOOLEAN");
+                Console.WriteLine();  
+                Environment.Exit(1);
+            }
+
+            var interopClient = new InteropClient(options);
+            interopClient.Run();
+        }
+
+        private void Run()
+        {
+            string addr = string.Format("{0}:{1}", options.serverHost, options.serverPort);
+            using (Channel channel = new Channel(addr))
+            {
+                TestServiceGrpc.ITestServiceClient client = new TestServiceGrpc.TestServiceClientStub(channel);
+
+                RunTestCase(options.testCase, client);
+            }
+
+            GrpcEnvironment.Shutdown();
+        }
+
+        private void RunTestCase(string testCase, TestServiceGrpc.ITestServiceClient client)
+        {
+            switch (testCase)
+            {
+                case "empty_unary":
+                    RunEmptyUnary(client);
+                    break;
+                case "large_unary":
+                    RunLargeUnary(client);
+                    break;
+                default:
+                    throw new ArgumentException("Unknown test case " + testCase);
+            }
+        }
+
+        private void RunEmptyUnary(TestServiceGrpc.ITestServiceClient client)
+        {
+            Console.WriteLine("running empty_unary");
+            var response = client.EmptyCall(Empty.DefaultInstance);
+            Assert.IsNotNull(response);
+        }
+
+        private void RunLargeUnary(TestServiceGrpc.ITestServiceClient client)
+        {
+            Console.WriteLine("running large_unary");
+            var request = SimpleRequest.CreateBuilder()
+                    .SetResponseType(PayloadType.COMPRESSABLE)
+                    .SetResponseSize(314159)
+                    .SetPayload(Payload.CreateBuilder().SetBody(ByteString.CopyFrom(new byte[271828])))
+                    .Build();
+             
+            var response = client.UnaryCall(request);
+
+            Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
+            Assert.AreEqual(314159, response.Payload.Body.Length);
+            // TODO: assert that the response is all zeros...
+        }
+
+        private static ClientOptions ParseArguments(string[] args)
+        {
+            var options = new ClientOptions();
+            foreach(string arg in args)
+            {
+                ParseArgument(arg, options);
+                if (options.help)
+                {
+                    break;
+                }
+            }
+            return options;
+        }
+
+        private static void ParseArgument(string arg, ClientOptions options)
+        {
+            Match match;
+            match = Regex.Match(arg, "--server_host=(.*)");
+            if (match.Success)
+            {
+                options.serverHost = match.Groups[1].Value.Trim();
+                return;
+            }
+
+            match = Regex.Match(arg, "--server_host_override=(.*)");
+            if (match.Success)
+            {
+                options.serverHostOverride = match.Groups[1].Value.Trim();
+                return;
+            }
+
+            match = Regex.Match(arg, "--server_port=(.*)");
+            if (match.Success)
+            {
+                options.serverPort = int.Parse(match.Groups[1].Value.Trim());
+                return;
+            }
+
+            match = Regex.Match(arg, "--test_case=(.*)");
+            if (match.Success)
+            {
+                options.testCase = match.Groups[1].Value.Trim();
+                return;
+            }
+
+            match = Regex.Match(arg, "--use_tls=(.*)");
+            if (match.Success)
+            {
+                options.useTls = bool.Parse(match.Groups[1].Value.Trim());
+                return;
+            }
+
+            match = Regex.Match(arg, "--use_test_ca=(.*)");
+            if (match.Success)
+            {
+                options.useTestCa = bool.Parse(match.Groups[1].Value.Trim());
+                return;
+            }
+
+            Console.WriteLine(string.Format("Unrecognized argument \"{0}\"", arg));
+            options.help = true;
+        }
+    }
+}
diff --git a/src/csharp/InteropClient/InteropClient.csproj b/src/csharp/InteropClient/InteropClient.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..ecc1c1087597f2f73b5e34735d2126620b5f261c
--- /dev/null
+++ b/src/csharp/InteropClient/InteropClient.csproj
@@ -0,0 +1,59 @@
+<?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)' == '' ">x86</Platform>
+    <ProductVersion>10.0.0</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{C61154BA-DD4A-4838-8420-0162A28925E0}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>InteropClient</RootNamespace>
+    <AssemblyName>InteropClient</AssemblyName>
+    <StartupObject>InteropClient.InteropClient</StartupObject>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG;</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Externalconsole>true</Externalconsole>
+    <PlatformTarget>x86</PlatformTarget>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>full</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Externalconsole>true</Externalconsole>
+    <PlatformTarget>x86</PlatformTarget>
+  </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="InteropClient.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <ProjectReference Include="..\GrpcCore\GrpcCore.csproj">
+      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
+      <Name>GrpcCore</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\GrpcApi\GrpcApi.csproj">
+      <Project>{7DC1433E-3225-42C7-B7EA-546D56E27A4B}</Project>
+      <Name>GrpcApi</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/csharp/InteropClient/Properties/AssemblyInfo.cs b/src/csharp/InteropClient/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1f3cc19a9def7df199ad97752baaa2cc67a75be9
--- /dev/null
+++ b/src/csharp/InteropClient/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("InteropClient")]
+[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/MathClient/.gitignore b/src/csharp/MathClient/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..ba077a4031add5b3a04384f8b9cfc414efbf47dd
--- /dev/null
+++ b/src/csharp/MathClient/.gitignore
@@ -0,0 +1 @@
+bin
diff --git a/src/csharp/GrpcDemo/Program.cs b/src/csharp/MathClient/MathClient.cs
similarity index 65%
rename from src/csharp/GrpcDemo/Program.cs
rename to src/csharp/MathClient/MathClient.cs
index c442c32193e237949f2ab548f8f1e736647fa120..45222abb79b07045c621447894c5777136a04097 100644
--- a/src/csharp/GrpcDemo/Program.cs
+++ b/src/csharp/MathClient/MathClient.cs
@@ -2,25 +2,23 @@ using System;
 using System.Runtime.InteropServices;
 using Google.GRPC.Core;
 using System.Threading;
-using math;
 
-namespace Google.GRPC.Demo
+namespace math
 {
-	class MainClass
+	class MathClient
     {
 		public static void Main (string[] args)
 		{
 			using (Channel channel = new Channel("127.0.0.1:23456"))
 			{
-
 				MathGrpc.IMathServiceClient stub = new MathGrpc.MathServiceClientStub(channel);
-				Examples.DivExample(stub);
+				MathExamples.DivExample(stub);
 
-                Examples.FibExample(stub);
+                MathExamples.FibExample(stub);
 
-				Examples.SumExample(stub);
+				MathExamples.SumExample(stub);
 
-				Examples.DivManyExample(stub);
+				MathExamples.DivManyExample(stub);
 			}
            
             GrpcEnvironment.Shutdown();
diff --git a/src/csharp/GrpcDemo/GrpcDemo.csproj b/src/csharp/MathClient/MathClient.csproj
similarity index 98%
rename from src/csharp/GrpcDemo/GrpcDemo.csproj
rename to src/csharp/MathClient/MathClient.csproj
index 31ce7f133b3a69f427a8f88a45aa7a1861eac377..74213653d21dc9252dd2d78e8962038d221051cd 100644
--- a/src/csharp/GrpcDemo/GrpcDemo.csproj
+++ b/src/csharp/MathClient/MathClient.csproj
@@ -35,8 +35,8 @@
     <Reference Include="System" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="MathClient.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
diff --git a/src/csharp/GrpcDemo/Properties/AssemblyInfo.cs b/src/csharp/MathClient/Properties/AssemblyInfo.cs
similarity index 95%
rename from src/csharp/GrpcDemo/Properties/AssemblyInfo.cs
rename to src/csharp/MathClient/Properties/AssemblyInfo.cs
index b8e1406da7c6a90f72c8f0900fb5623398b097b7..f521cd63f0c6bf1a18559f524e8d504a2990e434 100644
--- a/src/csharp/GrpcDemo/Properties/AssemblyInfo.cs
+++ b/src/csharp/MathClient/Properties/AssemblyInfo.cs
@@ -3,7 +3,7 @@ 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 ("GrpcDemo")]
+[assembly: AssemblyTitle ("MathClient")]
 [assembly: AssemblyDescription ("")]
 [assembly: AssemblyConfiguration ("")]
 [assembly: AssemblyCompany ("")]