Added simplified TestService for interop testing
diff --git a/src/csharp/GrpcApi/Empty.cs b/src/csharp/GrpcApi/Empty.cs
new file mode 100644
index 0000000..dadfd15
--- /dev/null
+++ b/src/csharp/GrpcApi/Empty.cs
@@ -0,0 +1,282 @@
+// Generated by ProtoGen, Version=2.4.1.521, Culture=neutral, PublicKeyToken=17b3b1f090c3ea48.  DO NOT EDIT!
+#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.testing {
+  
+  namespace Proto {
+    
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Empty {
+    
+      #region Extension registration
+      public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {
+      }
+      #endregion
+      #region Static variables
+      internal static pbd::MessageDescriptor internal__static_grpc_testing_Empty__Descriptor;
+      internal static pb::FieldAccess.FieldAccessorTable<global::grpc.testing.Empty, global::grpc.testing.Empty.Builder> internal__static_grpc_testing_Empty__FieldAccessorTable;
+      #endregion
+      #region Descriptor
+      public static pbd::FileDescriptor Descriptor {
+        get { return descriptor; }
+      }
+      private static pbd::FileDescriptor descriptor;
+      
+      static Empty() {
+        byte[] descriptorData = global::System.Convert.FromBase64String(
+            string.Concat(
+            "CgtlbXB0eS5wcm90bxIMZ3JwYy50ZXN0aW5nIgcKBUVtcHR5"));
+        pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
+          descriptor = root;
+          internal__static_grpc_testing_Empty__Descriptor = Descriptor.MessageTypes[0];
+          internal__static_grpc_testing_Empty__FieldAccessorTable = 
+              new pb::FieldAccess.FieldAccessorTable<global::grpc.testing.Empty, global::grpc.testing.Empty.Builder>(internal__static_grpc_testing_Empty__Descriptor,
+                  new string[] { });
+          return null;
+        };
+        pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+            new pbd::FileDescriptor[] {
+            }, assigner);
+      }
+      #endregion
+      
+    }
+  }
+  #region Messages
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Empty : pb::GeneratedMessage<Empty, Empty.Builder> {
+    private Empty() { }
+    private static readonly Empty defaultInstance = new Empty().MakeReadOnly();
+    private static readonly string[] _emptyFieldNames = new string[] {  };
+    private static readonly uint[] _emptyFieldTags = new uint[] {  };
+    public static Empty DefaultInstance {
+      get { return defaultInstance; }
+    }
+    
+    public override Empty DefaultInstanceForType {
+      get { return DefaultInstance; }
+    }
+    
+    protected override Empty ThisMessage {
+      get { return this; }
+    }
+    
+    public static pbd::MessageDescriptor Descriptor {
+      get { return global::grpc.testing.Proto.Empty.internal__static_grpc_testing_Empty__Descriptor; }
+    }
+    
+    protected override pb::FieldAccess.FieldAccessorTable<Empty, Empty.Builder> InternalFieldAccessors {
+      get { return global::grpc.testing.Proto.Empty.internal__static_grpc_testing_Empty__FieldAccessorTable; }
+    }
+    
+    public override bool IsInitialized {
+      get {
+        return true;
+      }
+    }
+    
+    public override void WriteTo(pb::ICodedOutputStream output) {
+      int size = SerializedSize;
+      string[] field_names = _emptyFieldNames;
+      UnknownFields.WriteTo(output);
+    }
+    
+    private int memoizedSerializedSize = -1;
+    public override int SerializedSize {
+      get {
+        int size = memoizedSerializedSize;
+        if (size != -1) return size;
+        
+        size = 0;
+        size += UnknownFields.SerializedSize;
+        memoizedSerializedSize = size;
+        return size;
+      }
+    }
+    
+    public static Empty ParseFrom(pb::ByteString data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static Empty ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static Empty ParseFrom(byte[] data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static Empty ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static Empty ParseFrom(global::System.IO.Stream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static Empty ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static Empty ParseDelimitedFrom(global::System.IO.Stream input) {
+      return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+    }
+    public static Empty ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+    }
+    public static Empty ParseFrom(pb::ICodedInputStream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static Empty ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    private Empty 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(Empty prototype) {
+      return new Builder(prototype);
+    }
+    
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public sealed partial class Builder : pb::GeneratedBuilder<Empty, Builder> {
+      protected override Builder ThisBuilder {
+        get { return this; }
+      }
+      public Builder() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+      }
+      internal Builder(Empty cloneFrom) {
+        result = cloneFrom;
+        resultIsReadOnly = true;
+      }
+      
+      private bool resultIsReadOnly;
+      private Empty result;
+      
+      private Empty PrepareBuilder() {
+        if (resultIsReadOnly) {
+          Empty original = result;
+          result = new Empty();
+          resultIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
+      
+      protected override Empty 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.testing.Empty.Descriptor; }
+      }
+      
+      public override Empty DefaultInstanceForType {
+        get { return global::grpc.testing.Empty.DefaultInstance; }
+      }
+      
+      public override Empty BuildPartial() {
+        if (resultIsReadOnly) {
+          return result;
+        }
+        resultIsReadOnly = true;
+        return result.MakeReadOnly();
+      }
+      
+      public override Builder MergeFrom(pb::IMessage other) {
+        if (other is Empty) {
+          return MergeFrom((Empty) other);
+        } else {
+          base.MergeFrom(other);
+          return this;
+        }
+      }
+      
+      public override Builder MergeFrom(Empty other) {
+        if (other == global::grpc.testing.Empty.DefaultInstance) return this;
+        PrepareBuilder();
+        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(_emptyFieldNames, field_name, global::System.StringComparer.Ordinal);
+            if(field_ordinal >= 0)
+              tag = _emptyFieldTags[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;
+            }
+          }
+        }
+        
+        if (unknownFields != null) {
+          this.UnknownFields = unknownFields.Build();
+        }
+        return this;
+      }
+      
+    }
+    static Empty() {
+      object.ReferenceEquals(global::grpc.testing.Proto.Empty.Descriptor, null);
+    }
+  }
+  
+  #endregion
+  
+}
+
+#endregion Designer generated code