diff --git a/src/csharp/Grpc.HealthCheck.Tests/.gitignore b/src/csharp/Grpc.HealthCheck.Tests/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..1746e3269ed0fcf5cde6ed13a6543865137868c0
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..61bd70cf7bb6193ef5d79cc21136005cbc6fb116
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Grpc.HealthCheck.Tests</RootNamespace>
+    <AssemblyName>Grpc.HealthCheck.Tests</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Google.ProtocolBuffers">
+      <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.ProtocolBuffers.Serialization">
+      <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll</HintPath>
+    </Reference>
+    <Reference Include="nunit.framework">
+      <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="HealthServiceImplTest.cs" />
+    <Compile Include="HealthClientServerTest.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+      <Project>{ccc4440e-49f7-4790-b0af-feabb0837ae7}</Project>
+      <Name>Grpc.Core</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Grpc.HealthCheck\Grpc.HealthCheck.csproj">
+      <Project>{aa5e328a-8835-49d7-98ed-c29f2b3049f0}</Project>
+      <Name>Grpc.HealthCheck</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0ac1add8e4289c08717e84b3fde662065de62f6c
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
@@ -0,0 +1,97 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Health.V1Alpha;
+using NUnit.Framework;
+
+namespace Grpc.HealthCheck.Tests
+{
+    /// <summary>
+    /// Health client talks to health server.
+    /// </summary>
+    public class HealthClientServerTest
+    {
+        const string Host = "localhost";
+        Server server;
+        Channel channel;
+        Grpc.Health.V1Alpha.Health.IHealthClient client;
+        Grpc.HealthCheck.HealthServiceImpl serviceImpl;
+
+        [TestFixtureSetUp]
+        public void Init()
+        {
+            serviceImpl = new HealthServiceImpl();
+
+            server = new Server();
+            server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl));
+            int port = server.AddListeningPort(Host, Server.PickUnusedPort);
+            server.Start();
+            channel = new Channel(Host, port);
+
+            client = Grpc.Health.V1Alpha.Health.NewStub(channel);
+        }
+
+        [TestFixtureTearDown]
+        public void Cleanup()
+        {
+            channel.Dispose();
+
+            server.ShutdownAsync().Wait();
+            GrpcEnvironment.Shutdown();
+        }
+
+        [Test]
+        public void ServiceIsRunning()
+        {
+            serviceImpl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
+
+            var response = client.Check(HealthCheckRequest.CreateBuilder().SetHost("").SetService("").Build());
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, response.Status);
+        }
+
+        [Test]
+        public void ServiceDoesntExist()
+        {
+            // TODO(jtattermusch): currently, this returns wrong status code, because we don't enable sending arbitrary status code from
+            // server handlers yet.
+            Assert.Throws(typeof(RpcException), () => client.Check(HealthCheckRequest.CreateBuilder().SetHost("").SetService("nonexistent.service").Build()));
+        }
+
+        // TODO(jtattermusch): add test with timeout once timeouts are supported
+    }
+}
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9b7c4f21406ed5593edb5cc19385aaed620b4460
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
@@ -0,0 +1,107 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Health.V1Alpha;
+using NUnit.Framework;
+
+namespace Grpc.HealthCheck.Tests
+{
+    /// <summary>
+    /// Tests for HealthCheckServiceImpl
+    /// </summary>
+    public class HealthServiceImplTest
+    {
+        [Test]
+        public void SetStatus()
+        {
+            var impl = new HealthServiceImpl();
+            impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, "", ""));
+
+            impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.NOT_SERVING);
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.NOT_SERVING, GetStatusHelper(impl, "", ""));
+
+            impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, "virtual-host", ""));
+
+            impl.SetStatus("virtual-host", "grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.SERVING);
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, "virtual-host", "grpc.test.TestService"));
+        }
+
+        [Test]
+        public void ClearStatus()
+        {
+            var impl = new HealthServiceImpl();
+            impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
+            impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
+
+            impl.ClearStatus("", "");
+
+            Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => GetStatusHelper(impl, "", ""));
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, "virtual-host", ""));
+        }
+
+        [Test]
+        public void ClearAll()
+        {
+            var impl = new HealthServiceImpl();
+            impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
+            impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
+
+            impl.ClearAll();
+            Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, "", ""));
+            Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, "virtual-host", ""));
+        }
+
+        [Test]
+        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(NullReferenceException), () => impl.ClearStatus(null, ""));
+            Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus("", null));
+        }
+
+        private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string host, string service)
+        {
+            return impl.Check(null, HealthCheckRequest.CreateBuilder().SetHost(host).SetService(service).Build()).Result.Status;
+        }
+    }
+}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.HealthCheck.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3dfcd51198c6cb5237ca3fab2cb7e8efa8479773
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,12 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.HealthCheck.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("0.6.*")]
diff --git a/src/csharp/Grpc.HealthCheck.Tests/packages.config b/src/csharp/Grpc.HealthCheck.Tests/packages.config
new file mode 100644
index 0000000000000000000000000000000000000000..050c4eaed67c648525a4077234421861658d3db8
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Google.ProtocolBuffers" version="2.4.1.555" targetFramework="net45" />
+  <package id="NUnit" version="2.6.4" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/.gitignore b/src/csharp/Grpc.HealthCheck/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..1746e3269ed0fcf5cde6ed13a6543865137868c0
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..6d37b37deb0f7cf0c0fa4b22c8562b93139a679d
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{AA5E328A-8835-49D7-98ED-C29F2B3049F0}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Grpc.HealthCheck</RootNamespace>
+    <AssemblyName>Grpc.HealthCheck</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Google.ProtocolBuffers">
+      <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.ProtocolBuffers.Serialization">
+      <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Interactive.Async">
+      <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="HealthServiceImpl.cs" />
+    <Compile Include="Health.cs" />
+    <Compile Include="HealthGrpc.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+    <None Include="proto\health.proto" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+      <Project>{ccc4440e-49f7-4790-b0af-feabb0837ae7}</Project>
+      <Name>Grpc.Core</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
new file mode 100644
index 0000000000000000000000000000000000000000..c774133ab06a60a259427eae863a181049304173
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package>
+  <metadata>
+    <id>Grpc.HealthCheck</id>
+    <title>gRPC C# Healthchecking</title>
+    <summary>Implementation of gRPC health service</summary>
+    <description>Example implementation of grpc.health.v1alpha service that can be used for health-checking.</description>
+    <version>0.6.0</version>
+    <authors>Google Inc.</authors>
+    <owners>grpc-packages</owners>
+    <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
+    <projectUrl>https://github.com/grpc/grpc</projectUrl>
+    <requireLicenseAcceptance>false</requireLicenseAcceptance>
+    <copyright>Copyright 2015, Google Inc.</copyright>
+    <tags>gRPC health check</tags>
+	<dependencies>
+	  <dependency id="Google.ProtocolBuffers" version="2.4.1.555" />
+	  <dependency id="Grpc.Core" version="0.6.0" />
+	  <dependency id="Ix-Async" version="1.2.3" />
+    </dependencies>
+  </metadata>
+  <files>
+    <file src="bin/Release/Grpc.HealthCheck.dll" target="lib/net45" />
+	<file src="bin/Release/Grpc.HealthCheck.pdb" target="lib/net45" />
+	<file src="bin/Release/Grpc.HealthCheck.xml" target="lib/net45" />
+	<file src="**\*.cs" target="src" />
+  </files>
+</package>
diff --git a/src/csharp/Grpc.HealthCheck/Health.cs b/src/csharp/Grpc.HealthCheck/Health.cs
new file mode 100644
index 0000000000000000000000000000000000000000..361382d4bd6a5736f7c03cbc8f140e6533805930
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Health.cs
@@ -0,0 +1,687 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: health.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.ProtocolBuffers;
+using pbc = global::Google.ProtocolBuffers.Collections;
+using pbd = global::Google.ProtocolBuffers.Descriptors;
+using scg = global::System.Collections.Generic;
+namespace Grpc.Health.V1Alpha {
+
+  namespace Proto {
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Health {
+
+      #region Extension registration
+      public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {
+      }
+      #endregion
+      #region Static variables
+      internal static pbd::MessageDescriptor internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor;
+      internal static pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckRequest.Builder> internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable;
+      internal static pbd::MessageDescriptor internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor;
+      internal static pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckResponse, global::Grpc.Health.V1Alpha.HealthCheckResponse.Builder> internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable;
+      #endregion
+      #region Descriptor
+      public static pbd::FileDescriptor Descriptor {
+        get { return descriptor; }
+      }
+      private static pbd::FileDescriptor descriptor;
+
+      static Health() {
+        byte[] descriptorData = global::System.Convert.FromBase64String(
+            string.Concat(
+              "CgxoZWFsdGgucHJvdG8SE2dycGMuaGVhbHRoLnYxYWxwaGEiMwoSSGVhbHRo", 
+              "Q2hlY2tSZXF1ZXN0EgwKBGhvc3QYASABKAkSDwoHc2VydmljZRgCIAEoCSKZ", 
+              "AQoTSGVhbHRoQ2hlY2tSZXNwb25zZRJGCgZzdGF0dXMYASABKA4yNi5ncnBj", 
+              "LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVzcG9uc2UuU2VydmluZ1N0", 
+              "YXR1cyI6Cg1TZXJ2aW5nU3RhdHVzEgsKB1VOS05PV04QABILCgdTRVJWSU5H", 
+              "EAESDwoLTk9UX1NFUlZJTkcQAjJkCgZIZWFsdGgSWgoFQ2hlY2sSJy5ncnBj", 
+              "LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVxdWVzdBooLmdycGMuaGVh", 
+              "bHRoLnYxYWxwaGEuSGVhbHRoQ2hlY2tSZXNwb25zZUIWqgITR3JwYy5IZWFs", 
+            "dGguVjFBbHBoYQ=="));
+        pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
+          descriptor = root;
+          internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor = Descriptor.MessageTypes[0];
+          internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable = 
+              new pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckRequest.Builder>(internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor,
+                  new string[] { "Host", "Service", });
+          internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor = Descriptor.MessageTypes[1];
+          internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable = 
+              new pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckResponse, global::Grpc.Health.V1Alpha.HealthCheckResponse.Builder>(internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor,
+                  new string[] { "Status", });
+          pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance();
+          RegisterAllExtensions(registry);
+          return registry;
+        };
+        pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+            new pbd::FileDescriptor[] {
+            }, assigner);
+      }
+      #endregion
+
+    }
+  }
+  #region Messages
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class HealthCheckRequest : pb::GeneratedMessage<HealthCheckRequest, HealthCheckRequest.Builder> {
+    private HealthCheckRequest() { }
+    private static readonly HealthCheckRequest defaultInstance = new HealthCheckRequest().MakeReadOnly();
+    private static readonly string[] _healthCheckRequestFieldNames = new string[] { "host", "service" };
+    private static readonly uint[] _healthCheckRequestFieldTags = new uint[] { 10, 18 };
+    public static HealthCheckRequest DefaultInstance {
+      get { return defaultInstance; }
+    }
+
+    public override HealthCheckRequest DefaultInstanceForType {
+      get { return DefaultInstance; }
+    }
+
+    protected override HealthCheckRequest ThisMessage {
+      get { return this; }
+    }
+
+    public static pbd::MessageDescriptor Descriptor {
+      get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor; }
+    }
+
+    protected override pb::FieldAccess.FieldAccessorTable<HealthCheckRequest, HealthCheckRequest.Builder> InternalFieldAccessors {
+      get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable; }
+    }
+
+    public const int HostFieldNumber = 1;
+    private bool hasHost;
+    private string host_ = "";
+    public bool HasHost {
+      get { return hasHost; }
+    }
+    public string Host {
+      get { return host_; }
+    }
+
+    public const int ServiceFieldNumber = 2;
+    private bool hasService;
+    private string service_ = "";
+    public bool HasService {
+      get { return hasService; }
+    }
+    public string Service {
+      get { return service_; }
+    }
+
+    public override bool IsInitialized {
+      get {
+        return true;
+      }
+    }
+
+    public override void WriteTo(pb::ICodedOutputStream output) {
+      CalcSerializedSize();
+      string[] field_names = _healthCheckRequestFieldNames;
+      if (hasHost) {
+        output.WriteString(1, field_names[0], Host);
+      }
+      if (hasService) {
+        output.WriteString(2, field_names[1], Service);
+      }
+      UnknownFields.WriteTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public override int SerializedSize {
+      get {
+        int size = memoizedSerializedSize;
+        if (size != -1) return size;
+        return CalcSerializedSize();
+      }
+    }
+
+    private int CalcSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (hasHost) {
+        size += pb::CodedOutputStream.ComputeStringSize(1, Host);
+      }
+      if (hasService) {
+        size += pb::CodedOutputStream.ComputeStringSize(2, Service);
+      }
+      size += UnknownFields.SerializedSize;
+      memoizedSerializedSize = size;
+      return size;
+    }
+    public static HealthCheckRequest ParseFrom(pb::ByteString data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(byte[] data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(global::System.IO.Stream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseDelimitedFrom(global::System.IO.Stream input) {
+      return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+    }
+    public static HealthCheckRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(pb::ICodedInputStream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    private HealthCheckRequest MakeReadOnly() {
+      return this;
+    }
+
+    public static Builder CreateBuilder() { return new Builder(); }
+    public override Builder ToBuilder() { return CreateBuilder(this); }
+    public override Builder CreateBuilderForType() { return new Builder(); }
+    public static Builder CreateBuilder(HealthCheckRequest prototype) {
+      return new Builder(prototype);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public sealed partial class Builder : pb::GeneratedBuilder<HealthCheckRequest, Builder> {
+      protected override Builder ThisBuilder {
+        get { return this; }
+      }
+      public Builder() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+      }
+      internal Builder(HealthCheckRequest cloneFrom) {
+        result = cloneFrom;
+        resultIsReadOnly = true;
+      }
+
+      private bool resultIsReadOnly;
+      private HealthCheckRequest result;
+
+      private HealthCheckRequest PrepareBuilder() {
+        if (resultIsReadOnly) {
+          HealthCheckRequest original = result;
+          result = new HealthCheckRequest();
+          resultIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
+
+      protected override HealthCheckRequest MessageBeingBuilt {
+        get { return PrepareBuilder(); }
+      }
+
+      public override Builder Clear() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+        return this;
+      }
+
+      public override Builder Clone() {
+        if (resultIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
+      }
+
+      public override pbd::MessageDescriptor DescriptorForType {
+        get { return global::Grpc.Health.V1Alpha.HealthCheckRequest.Descriptor; }
+      }
+
+      public override HealthCheckRequest DefaultInstanceForType {
+        get { return global::Grpc.Health.V1Alpha.HealthCheckRequest.DefaultInstance; }
+      }
+
+      public override HealthCheckRequest BuildPartial() {
+        if (resultIsReadOnly) {
+          return result;
+        }
+        resultIsReadOnly = true;
+        return result.MakeReadOnly();
+      }
+
+      public override Builder MergeFrom(pb::IMessage other) {
+        if (other is HealthCheckRequest) {
+          return MergeFrom((HealthCheckRequest) other);
+        } else {
+          base.MergeFrom(other);
+          return this;
+        }
+      }
+
+      public override Builder MergeFrom(HealthCheckRequest other) {
+        if (other == global::Grpc.Health.V1Alpha.HealthCheckRequest.DefaultInstance) return this;
+        PrepareBuilder();
+        if (other.HasHost) {
+          Host = other.Host;
+        }
+        if (other.HasService) {
+          Service = other.Service;
+        }
+        this.MergeUnknownFields(other.UnknownFields);
+        return this;
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input) {
+        return MergeFrom(input, pb::ExtensionRegistry.Empty);
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
+        pb::UnknownFieldSet.Builder unknownFields = null;
+        uint tag;
+        string field_name;
+        while (input.ReadTag(out tag, out field_name)) {
+          if(tag == 0 && field_name != null) {
+            int field_ordinal = global::System.Array.BinarySearch(_healthCheckRequestFieldNames, field_name, global::System.StringComparer.Ordinal);
+            if(field_ordinal >= 0)
+              tag = _healthCheckRequestFieldTags[field_ordinal];
+            else {
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              continue;
+            }
+          }
+          switch (tag) {
+            case 0: {
+              throw pb::InvalidProtocolBufferException.InvalidTag();
+            }
+            default: {
+              if (pb::WireFormat.IsEndGroupTag(tag)) {
+                if (unknownFields != null) {
+                  this.UnknownFields = unknownFields.Build();
+                }
+                return this;
+              }
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              break;
+            }
+            case 10: {
+              result.hasHost = input.ReadString(ref result.host_);
+              break;
+            }
+            case 18: {
+              result.hasService = input.ReadString(ref result.service_);
+              break;
+            }
+          }
+        }
+
+        if (unknownFields != null) {
+          this.UnknownFields = unknownFields.Build();
+        }
+        return this;
+      }
+
+
+      public bool HasHost {
+        get { return result.hasHost; }
+      }
+      public string Host {
+        get { return result.Host; }
+        set { SetHost(value); }
+      }
+      public Builder SetHost(string value) {
+        pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
+        result.hasHost = true;
+        result.host_ = value;
+        return this;
+      }
+      public Builder ClearHost() {
+        PrepareBuilder();
+        result.hasHost = false;
+        result.host_ = "";
+        return this;
+      }
+
+      public bool HasService {
+        get { return result.hasService; }
+      }
+      public string Service {
+        get { return result.Service; }
+        set { SetService(value); }
+      }
+      public Builder SetService(string value) {
+        pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
+        result.hasService = true;
+        result.service_ = value;
+        return this;
+      }
+      public Builder ClearService() {
+        PrepareBuilder();
+        result.hasService = false;
+        result.service_ = "";
+        return this;
+      }
+    }
+    static HealthCheckRequest() {
+      object.ReferenceEquals(global::Grpc.Health.V1Alpha.Proto.Health.Descriptor, null);
+    }
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class HealthCheckResponse : pb::GeneratedMessage<HealthCheckResponse, HealthCheckResponse.Builder> {
+    private HealthCheckResponse() { }
+    private static readonly HealthCheckResponse defaultInstance = new HealthCheckResponse().MakeReadOnly();
+    private static readonly string[] _healthCheckResponseFieldNames = new string[] { "status" };
+    private static readonly uint[] _healthCheckResponseFieldTags = new uint[] { 8 };
+    public static HealthCheckResponse DefaultInstance {
+      get { return defaultInstance; }
+    }
+
+    public override HealthCheckResponse DefaultInstanceForType {
+      get { return DefaultInstance; }
+    }
+
+    protected override HealthCheckResponse ThisMessage {
+      get { return this; }
+    }
+
+    public static pbd::MessageDescriptor Descriptor {
+      get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor; }
+    }
+
+    protected override pb::FieldAccess.FieldAccessorTable<HealthCheckResponse, HealthCheckResponse.Builder> InternalFieldAccessors {
+      get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable; }
+    }
+
+    #region Nested types
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      public enum ServingStatus {
+        UNKNOWN = 0,
+        SERVING = 1,
+        NOT_SERVING = 2,
+      }
+
+    }
+    #endregion
+
+    public const int StatusFieldNumber = 1;
+    private bool hasStatus;
+    private global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN;
+    public bool HasStatus {
+      get { return hasStatus; }
+    }
+    public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status {
+      get { return status_; }
+    }
+
+    public override bool IsInitialized {
+      get {
+        return true;
+      }
+    }
+
+    public override void WriteTo(pb::ICodedOutputStream output) {
+      CalcSerializedSize();
+      string[] field_names = _healthCheckResponseFieldNames;
+      if (hasStatus) {
+        output.WriteEnum(1, field_names[0], (int) Status, Status);
+      }
+      UnknownFields.WriteTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public override int SerializedSize {
+      get {
+        int size = memoizedSerializedSize;
+        if (size != -1) return size;
+        return CalcSerializedSize();
+      }
+    }
+
+    private int CalcSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (hasStatus) {
+        size += pb::CodedOutputStream.ComputeEnumSize(1, (int) Status);
+      }
+      size += UnknownFields.SerializedSize;
+      memoizedSerializedSize = size;
+      return size;
+    }
+    public static HealthCheckResponse ParseFrom(pb::ByteString data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(byte[] data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(global::System.IO.Stream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseDelimitedFrom(global::System.IO.Stream input) {
+      return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+    }
+    public static HealthCheckResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(pb::ICodedInputStream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    private HealthCheckResponse MakeReadOnly() {
+      return this;
+    }
+
+    public static Builder CreateBuilder() { return new Builder(); }
+    public override Builder ToBuilder() { return CreateBuilder(this); }
+    public override Builder CreateBuilderForType() { return new Builder(); }
+    public static Builder CreateBuilder(HealthCheckResponse prototype) {
+      return new Builder(prototype);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public sealed partial class Builder : pb::GeneratedBuilder<HealthCheckResponse, Builder> {
+      protected override Builder ThisBuilder {
+        get { return this; }
+      }
+      public Builder() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+      }
+      internal Builder(HealthCheckResponse cloneFrom) {
+        result = cloneFrom;
+        resultIsReadOnly = true;
+      }
+
+      private bool resultIsReadOnly;
+      private HealthCheckResponse result;
+
+      private HealthCheckResponse PrepareBuilder() {
+        if (resultIsReadOnly) {
+          HealthCheckResponse original = result;
+          result = new HealthCheckResponse();
+          resultIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
+
+      protected override HealthCheckResponse MessageBeingBuilt {
+        get { return PrepareBuilder(); }
+      }
+
+      public override Builder Clear() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+        return this;
+      }
+
+      public override Builder Clone() {
+        if (resultIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
+      }
+
+      public override pbd::MessageDescriptor DescriptorForType {
+        get { return global::Grpc.Health.V1Alpha.HealthCheckResponse.Descriptor; }
+      }
+
+      public override HealthCheckResponse DefaultInstanceForType {
+        get { return global::Grpc.Health.V1Alpha.HealthCheckResponse.DefaultInstance; }
+      }
+
+      public override HealthCheckResponse BuildPartial() {
+        if (resultIsReadOnly) {
+          return result;
+        }
+        resultIsReadOnly = true;
+        return result.MakeReadOnly();
+      }
+
+      public override Builder MergeFrom(pb::IMessage other) {
+        if (other is HealthCheckResponse) {
+          return MergeFrom((HealthCheckResponse) other);
+        } else {
+          base.MergeFrom(other);
+          return this;
+        }
+      }
+
+      public override Builder MergeFrom(HealthCheckResponse other) {
+        if (other == global::Grpc.Health.V1Alpha.HealthCheckResponse.DefaultInstance) return this;
+        PrepareBuilder();
+        if (other.HasStatus) {
+          Status = other.Status;
+        }
+        this.MergeUnknownFields(other.UnknownFields);
+        return this;
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input) {
+        return MergeFrom(input, pb::ExtensionRegistry.Empty);
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
+        pb::UnknownFieldSet.Builder unknownFields = null;
+        uint tag;
+        string field_name;
+        while (input.ReadTag(out tag, out field_name)) {
+          if(tag == 0 && field_name != null) {
+            int field_ordinal = global::System.Array.BinarySearch(_healthCheckResponseFieldNames, field_name, global::System.StringComparer.Ordinal);
+            if(field_ordinal >= 0)
+              tag = _healthCheckResponseFieldTags[field_ordinal];
+            else {
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              continue;
+            }
+          }
+          switch (tag) {
+            case 0: {
+              throw pb::InvalidProtocolBufferException.InvalidTag();
+            }
+            default: {
+              if (pb::WireFormat.IsEndGroupTag(tag)) {
+                if (unknownFields != null) {
+                  this.UnknownFields = unknownFields.Build();
+                }
+                return this;
+              }
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              break;
+            }
+            case 8: {
+              object unknown;
+              if(input.ReadEnum(ref result.status_, out unknown)) {
+                result.hasStatus = true;
+              } else if(unknown is int) {
+                if (unknownFields == null) {
+                  unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+                }
+                unknownFields.MergeVarintField(1, (ulong)(int)unknown);
+              }
+              break;
+            }
+          }
+        }
+
+        if (unknownFields != null) {
+          this.UnknownFields = unknownFields.Build();
+        }
+        return this;
+      }
+
+
+      public bool HasStatus {
+       get { return result.hasStatus; }
+      }
+      public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status {
+        get { return result.Status; }
+        set { SetStatus(value); }
+      }
+      public Builder SetStatus(global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus value) {
+        PrepareBuilder();
+        result.hasStatus = true;
+        result.status_ = value;
+        return this;
+      }
+      public Builder ClearStatus() {
+        PrepareBuilder();
+        result.hasStatus = false;
+        result.status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN;
+        return this;
+      }
+    }
+    static HealthCheckResponse() {
+      object.ReferenceEquals(global::Grpc.Health.V1Alpha.Proto.Health.Descriptor, null);
+    }
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ed9fc4ed77493e0592677293af83d2449fcc6cc9
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -0,0 +1,78 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: health.proto
+#region Designer generated code
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+
+namespace Grpc.Health.V1Alpha {
+  public static class Health
+  {
+    static readonly string __ServiceName = "grpc.health.v1alpha.Health";
+
+    static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckRequest> __Marshaller_HealthCheckRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::Grpc.Health.V1Alpha.HealthCheckRequest.ParseFrom);
+    static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckResponse> __Marshaller_HealthCheckResponse = Marshallers.Create((arg) => arg.ToByteArray(), global::Grpc.Health.V1Alpha.HealthCheckResponse.ParseFrom);
+
+    static readonly Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse> __Method_Check = new Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse>(
+        MethodType.Unary,
+        "Check",
+        __Marshaller_HealthCheckRequest,
+        __Marshaller_HealthCheckResponse);
+
+    // client-side stub interface
+    public interface IHealthClient
+    {
+      global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CancellationToken token = default(CancellationToken));
+      Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CancellationToken token = default(CancellationToken));
+    }
+
+    // server-side interface
+    public interface IHealth
+    {
+      Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> Check(ServerCallContext context, global::Grpc.Health.V1Alpha.HealthCheckRequest request);
+    }
+
+    // client stub
+    public class HealthClient : AbstractStub<HealthClient, StubConfiguration>, IHealthClient
+    {
+      public HealthClient(Channel channel) : this(channel, StubConfiguration.Default)
+      {
+      }
+      public HealthClient(Channel channel, StubConfiguration config) : base(channel, config)
+      {
+      }
+      public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CancellationToken token = default(CancellationToken))
+      {
+        var call = CreateCall(__ServiceName, __Method_Check);
+        return Calls.BlockingUnaryCall(call, request, token);
+      }
+      public Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CancellationToken token = default(CancellationToken))
+      {
+        var call = CreateCall(__ServiceName, __Method_Check);
+        return Calls.AsyncUnaryCall(call, request, token);
+      }
+    }
+
+    // creates service definition that can be registered with a server
+    public static ServerServiceDefinition BindService(IHealth serviceImpl)
+    {
+      return ServerServiceDefinition.CreateBuilder(__ServiceName)
+          .AddMethod(__Method_Check, serviceImpl.Check).Build();
+    }
+
+    // creates a new client stub
+    public static IHealthClient NewStub(Channel channel)
+    {
+      return new HealthClient(channel);
+    }
+
+    // creates a new client stub
+    public static IHealthClient NewStub(Channel channel, StubConfiguration config)
+    {
+      return new HealthClient(channel, config);
+    }
+  }
+}
+#endregion
diff --git a/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
new file mode 100644
index 0000000000000000000000000000000000000000..db3a2a09420dda5173bc6c7bc1d8e1d058cdad9e
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
@@ -0,0 +1,132 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Health.V1Alpha;
+
+namespace Grpc.HealthCheck
+{
+    /// <summary>
+    /// Implementation of a simple Health service. Useful for health checking.
+    /// 
+    /// Registering service with a server:
+    /// <code>
+    /// var serviceImpl = new HealthServiceImpl();
+    /// server = new Server();
+    /// server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl));
+    /// </code>
+    /// </summary>
+    public class HealthServiceImpl : Grpc.Health.V1Alpha.Health.IHealth
+    {
+        private readonly object myLock = new object();
+        private readonly Dictionary<Key, HealthCheckResponse.Types.ServingStatus> statusMap = 
+            new Dictionary<Key, HealthCheckResponse.Types.ServingStatus>();
+
+        /// <summary>
+        /// Sets the health status for given host and service.
+        /// </summary>
+        /// <param name="host">The host. Cannot be null.</param>
+        /// <param name="service">The service. Cannot be null.</param>
+        /// <param name="status">the health status</param>
+        public void SetStatus(string host, string service, HealthCheckResponse.Types.ServingStatus status)
+        {
+            lock (myLock)
+            {
+                statusMap[CreateKey(host, service)] = status;
+            }
+        }
+
+        /// <summary>
+        /// Clears health status for given host and service.
+        /// </summary>
+        /// <param name="host">The host. Cannot be null.</param>
+        /// <param name="service">The service. Cannot be null.</param>
+        public void ClearStatus(string host, string service)
+        {
+            lock (myLock)
+            {
+                statusMap.Remove(CreateKey(host, service));
+            }
+        }
+        
+        /// <summary>
+        /// Clears statuses for all hosts and services.
+        /// </summary>
+        public void ClearAll()
+        {
+            lock (myLock)
+            {
+                statusMap.Clear();
+            }
+        }
+
+        public Task<HealthCheckResponse> Check(ServerCallContext context, HealthCheckRequest request)
+        {
+            lock (myLock)
+            {
+                var host = request.HasHost ? request.Host : "";
+                var service = request.HasService ? request.Service : "";
+
+                HealthCheckResponse.Types.ServingStatus status;
+                if (!statusMap.TryGetValue(CreateKey(host, service), out status))
+                {
+                    // TODO(jtattermusch): returning specific status from server handler is not supported yet.
+                    throw new RpcException(new Status(StatusCode.NotFound, ""));
+                }
+                return Task.FromResult(HealthCheckResponse.CreateBuilder().SetStatus(status).Build());
+            }
+        }
+
+        private static Key CreateKey(string host, string service)
+        {
+            return new Key(host, service);
+        }
+
+        private struct Key
+        {
+            public Key(string host, string service)
+            {
+                this.Host = Preconditions.CheckNotNull(host);
+                this.Service = Preconditions.CheckNotNull(service);
+            }
+
+            readonly string Host;
+            readonly string Service;
+        }
+    }
+}
diff --git a/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs b/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6cfdb7e6e2cda008f24d057657fefed7a18d1eeb
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs
@@ -0,0 +1,12 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.HealthCheck")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("0.6.*")]
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/packages.config b/src/csharp/Grpc.HealthCheck/packages.config
new file mode 100644
index 0000000000000000000000000000000000000000..094a30981e442a11559f9e8e69b21370942f0307
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Google.ProtocolBuffers" version="2.4.1.555" targetFramework="net45" />
+  <package id="Ix-Async" version="1.2.3" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/proto/health.proto b/src/csharp/Grpc.HealthCheck/proto/health.proto
new file mode 100644
index 0000000000000000000000000000000000000000..08df7e104e10ae6080e2b206c52fce34710b36ce
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/proto/health.proto
@@ -0,0 +1,52 @@
+// 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.
+
+// TODO(jtattermusch): switch to proto3 once C# supports that.
+syntax = "proto2";
+
+package grpc.health.v1alpha;
+option csharp_namespace = "Grpc.Health.V1Alpha";
+
+message HealthCheckRequest {
+  optional string host = 1;
+  optional string service = 2;
+}
+
+message HealthCheckResponse {
+  enum ServingStatus {
+    UNKNOWN = 0;
+    SERVING = 1;
+    NOT_SERVING = 2;
+  }
+  optional ServingStatus status = 1;
+}
+
+service Health {
+  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+}
\ No newline at end of file
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 978739f23aa68e2a923b37f211a9f68c5325053f..705e4fb1c215b39b826428c3efe185e30cbf5cac 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -28,57 +28,68 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{B5B871
 		.nuget\packages.config = .nuget\packages.config
 	EndProjectSection
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck", "Grpc.HealthCheck\Grpc.HealthCheck.csproj", "{AA5E328A-8835-49D7-98ED-C29F2B3049F0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck.Tests", "Grpc.HealthCheck.Tests\Grpc.HealthCheck.Tests.csproj", "{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|x86 = Debug|x86
 		Release|x86 = Release|x86
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.Build.0 = Debug|Any CPU
-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.ActiveCfg = Release|Any CPU
-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.Build.0 = Release|Any CPU
-		{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
-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{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
 		{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
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.Build.0 = Release|x86
-		{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
 		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.ActiveCfg = Debug|x86
 		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.Build.0 = Debug|x86
 		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.ActiveCfg = Release|x86
 		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.Build.0 = Release|x86
+		{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
+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.Build.0 = Release|x86
+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.Build.0 = Debug|Any CPU
+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.ActiveCfg = Release|Any CPU
+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.Build.0 = Release|Any CPU
+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{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
 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.ActiveCfg = Debug|x86
 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.Build.0 = Debug|x86
 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.ActiveCfg = Release|x86
 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.Build.0 = Release|x86
-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86
-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86
-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86
-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|x86.Build.0 = Debug|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|x86.ActiveCfg = Release|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|x86.Build.0 = Release|Any CPU
 		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.ActiveCfg = Debug|Any CPU
 		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.Build.0 = Debug|Any CPU
 		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.ActiveCfg = Release|Any CPU
 		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.Build.0 = Release|Any CPU
+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86
+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86
+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86
+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86
+		{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
+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|x86.Build.0 = Debug|Any CPU
+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|x86.ActiveCfg = Release|Any CPU
+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
-	GlobalSection(MonoDevelopProperties) = preSolution
-		StartupItem = Grpc.Examples\Grpc.Examples.csproj
-	EndGlobalSection
 EndGlobal
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index 3412129fb2b1c2fedaf2914942fb5ad988c5b8de..4db286ed0a60c7e8d0a6f67e1616d5a343bf5c1c 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -11,8 +11,9 @@ endlocal
 @call buildall.bat || goto :error
 
 %NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec || goto :error
-%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols || goto :error
 %NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols || goto :error
+%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols || goto :error
+%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols || goto :error
 %NUGET% pack Grpc.Tools.nuspec || goto :error
 %NUGET% pack Grpc.nuspec || goto :error
 
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
index f980787bb70ff2f133e45a6b248f713a2140afbf..6eb3887ea109f12513d2ad967b83a8611cae00c3 100755
--- a/src/csharp/generate_proto_csharp.sh
+++ b/src/csharp/generate_proto_csharp.sh
@@ -35,9 +35,13 @@ cd $(dirname $0)
 PLUGIN=protoc-gen-grpc=../../bins/opt/grpc_csharp_plugin
 EXAMPLES_DIR=Grpc.Examples
 INTEROP_DIR=Grpc.IntegrationTesting
+HEALTHCHECK_DIR=Grpc.HealthCheck
 
 protoc --plugin=$PLUGIN --grpc_out=$EXAMPLES_DIR \
     -I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto
 
 protoc --plugin=$PLUGIN --grpc_out=$INTEROP_DIR \
     -I $INTEROP_DIR/proto $INTEROP_DIR/proto/test.proto
+	
+protoc --plugin=$PLUGIN --grpc_out=$HEALTHCHECK_DIR \
+    -I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto