From e5c9b80566c3260035187b19e37c91f5cd3d4e2a Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 14 Jul 2015 17:46:58 -0700 Subject: renaming stub to client and refactoring metadata class --- src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs | 8 +- src/csharp/Grpc.Core/Calls.cs | 2 +- src/csharp/Grpc.Core/ClientBase.cs | 89 ++++++++++ src/csharp/Grpc.Core/Grpc.Core.csproj | 3 +- .../Grpc.Core/Internal/MetadataArraySafeHandle.cs | 8 +- src/csharp/Grpc.Core/Metadata.cs | 179 ++++++++++++++++----- src/csharp/Grpc.Core/Stub/AbstractStub.cs | 75 --------- src/csharp/Grpc.Core/Stub/StubConfiguration.cs | 64 -------- src/csharp/Grpc.Core/Version.cs | 1 - src/csharp/Grpc.Examples.MathClient/MathClient.cs | 14 +- src/csharp/Grpc.Examples/MathExamples.cs | 26 +-- src/csharp/Grpc.Examples/MathGrpc.cs | 2 +- src/csharp/Grpc.HealthCheck/HealthGrpc.cs | 2 +- src/csharp/Grpc.IntegrationTesting/TestGrpc.cs | 2 +- 14 files changed, 261 insertions(+), 214 deletions(-) create mode 100644 src/csharp/Grpc.Core/ClientBase.cs delete mode 100644 src/csharp/Grpc.Core/Stub/AbstractStub.cs delete mode 100644 src/csharp/Grpc.Core/Stub/StubConfiguration.cs (limited to 'src') diff --git a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs b/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs index ca384d1a6e..420c4cb537 100644 --- a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs +++ b/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs @@ -52,10 +52,10 @@ namespace Grpc.Auth /// /// Creates OAuth2 interceptor. /// - public static HeaderInterceptorDelegate Create(GoogleCredential googleCredential) + public static MetadataInterceptorDelegate Create(GoogleCredential googleCredential) { var interceptor = new OAuth2Interceptor(googleCredential.InternalCredential, SystemClock.Default); - return new HeaderInterceptorDelegate(interceptor.InterceptHeaders); + return new MetadataInterceptorDelegate(interceptor.InterceptHeaders); } /// @@ -94,10 +94,10 @@ namespace Grpc.Auth return credential.Token.AccessToken; } - public void InterceptHeaders(Metadata.Builder headerBuilder) + public void InterceptHeaders(Metadata metadata) { var accessToken = GetAccessToken(CancellationToken.None); - headerBuilder.Add(new Metadata.MetadataEntry(AuthorizationHeader, Schema + " " + accessToken)); + metadata.Add(new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken)); } } } diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs index 750282258f..9e95182c72 100644 --- a/src/csharp/Grpc.Core/Calls.cs +++ b/src/csharp/Grpc.Core/Calls.cs @@ -39,7 +39,7 @@ using Grpc.Core.Internal; namespace Grpc.Core { /// - /// Helper methods for generated client stubs to make RPC calls. + /// Helper methods for generated clients to make RPC calls. /// public static class Calls { diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs new file mode 100644 index 0000000000..59dc40ba4e --- /dev/null +++ b/src/csharp/Grpc.Core/ClientBase.cs @@ -0,0 +1,89 @@ +#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 Grpc.Core.Internal; + +namespace Grpc.Core +{ + public delegate void MetadataInterceptorDelegate(Metadata metadata); + + /// + /// Base class for client-side stubs. + /// + public abstract class ClientBase + { + readonly Channel channel; + + public ClientBase(Channel channel) + { + this.channel = channel; + } + + /// + /// Can be used to register a custom header (initial metadata) interceptor. + /// The delegate each time before a new call on this client is started. + /// + public MetadataInterceptorDelegate HeaderInterceptor + { + get; + set; + } + + /// + /// Channel associated with this client. + /// + public Channel Channel + { + get + { + return this.channel; + } + } + + /// + /// Creates a new call to given method. + /// + protected Call CreateCall(string serviceName, Method method) + where TRequest : class + where TResponse : class + { + var metadata = new Metadata(); + HeaderInterceptor(metadata); + metadata.Freeze(); + return new Call(serviceName, method, channel, metadata); + } + } +} diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index cde42c3b7e..a227fe5477 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -88,8 +88,7 @@ - - + diff --git a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs index c9c4d954c9..80aa7f5603 100644 --- a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs @@ -54,11 +54,11 @@ namespace Grpc.Core.Internal public static MetadataArraySafeHandle Create(Metadata metadata) { - var entries = metadata.Entries; - var metadataArray = grpcsharp_metadata_array_create(new UIntPtr((ulong)entries.Count)); - for (int i = 0; i < entries.Count; i++) + // TODO(jtattermusch): we might wanna check that the metadata is readonly + var metadataArray = grpcsharp_metadata_array_create(new UIntPtr((ulong)metadata.Count)); + for (int i = 0; i < metadata.Count; i++) { - grpcsharp_metadata_array_add(metadataArray, entries[i].Key, entries[i].ValueBytes, new UIntPtr((ulong)entries[i].ValueBytes.Length)); + grpcsharp_metadata_array_add(metadataArray, metadata[i].Key, metadata[i].ValueBytes, new UIntPtr((ulong)metadata[i].ValueBytes.Length)); } return metadataArray; } diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs index eccec26a61..ddfe8488b7 100644 --- a/src/csharp/Grpc.Core/Metadata.cs +++ b/src/csharp/Grpc.Core/Metadata.cs @@ -30,55 +30,163 @@ #endregion using System; +using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; +using System.Collections.Specialized; using System.Runtime.InteropServices; using System.Text; +using Grpc.Core.Utils; + namespace Grpc.Core { /// - /// gRPC call metadata. + /// Provides access to read and write metadata values to be exchanged during a call. /// - public class Metadata + public sealed class Metadata : IList { - public static readonly Metadata Empty = new Metadata(ImmutableList.Empty); + /// + /// An read-only instance of metadata containing no entries. + /// + public static readonly Metadata Empty = new Metadata().Freeze(); + + readonly List entries; + bool readOnly; + + public Metadata() + { + this.entries = new List(); + } + + public Metadata(ICollection entries) + { + this.entries = new List(entries); + } + + /// + /// Makes this object read-only. + /// + /// this object + public Metadata Freeze() + { + this.readOnly = true; + return this; + } + + // TODO: add support for access by key + + #region IList members + + public int IndexOf(Metadata.Entry item) + { + return entries.IndexOf(item); + } - readonly ImmutableList entries; + public void Insert(int index, Metadata.Entry item) + { + CheckWriteable(); + entries.Insert(index, item); + } - public Metadata(ImmutableList entries) + public void RemoveAt(int index) { - this.entries = entries; + CheckWriteable(); + entries.RemoveAt(index); } - public ImmutableList Entries + public Metadata.Entry this[int index] { get { - return this.entries; + return entries[index]; + } + + set + { + CheckWriteable(); + entries[index] = value; } } - public static Builder CreateBuilder() + public void Add(Metadata.Entry item) + { + CheckWriteable(); + entries.Add(item); + } + + public void Clear() + { + CheckWriteable(); + entries.Clear(); + } + + public bool Contains(Metadata.Entry item) + { + return entries.Contains(item); + } + + public void CopyTo(Metadata.Entry[] array, int arrayIndex) { - return new Builder(); + entries.CopyTo(array, arrayIndex); } - - public struct MetadataEntry + + public int Count + { + get { return entries.Count; } + } + + public bool IsReadOnly + { + get { return readOnly; } + } + + public bool Remove(Metadata.Entry item) + { + CheckWriteable(); + return entries.Remove(item); + } + + public IEnumerator GetEnumerator() + { + return entries.GetEnumerator(); + } + + IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return entries.GetEnumerator(); + } + + private void CheckWriteable() + { + Preconditions.CheckState(!readOnly, "Object is read only"); + } + + #endregion + + /// + /// Metadata entry + /// + public struct Entry { + private static readonly Encoding Encoding = Encoding.ASCII; + readonly string key; - readonly byte[] valueBytes; + string value; + byte[] valueBytes; - public MetadataEntry(string key, byte[] valueBytes) + public Entry(string key, byte[] valueBytes) { - this.key = key; - this.valueBytes = valueBytes; + this.key = Preconditions.CheckNotNull(key); + this.value = null; + this.valueBytes = Preconditions.CheckNotNull(valueBytes); } - public MetadataEntry(string key, string value) + public Entry(string key, string value) { - this.key = key; - this.valueBytes = Encoding.ASCII.GetBytes(value); + this.key = Preconditions.CheckNotNull(key); + this.value = Preconditions.CheckNotNull(value); + this.valueBytes = null; } public string Key @@ -89,38 +197,29 @@ namespace Grpc.Core } } - // TODO: using ByteString would guarantee immutability. public byte[] ValueBytes { get { - return this.valueBytes; + if (valueBytes == null) + { + valueBytes = Encoding.GetBytes(value); + } + return valueBytes; } } - } - public class Builder - { - readonly List entries = new List(); - - public List Entries + public string Value { get { - return entries; + if (value == null) + { + value = Encoding.GetString(valueBytes); + } + return value; } } - - public Builder Add(MetadataEntry entry) - { - entries.Add(entry); - return this; - } - - public Metadata Build() - { - return new Metadata(entries.ToImmutableList()); - } } - } + } } diff --git a/src/csharp/Grpc.Core/Stub/AbstractStub.cs b/src/csharp/Grpc.Core/Stub/AbstractStub.cs deleted file mode 100644 index 4a8b254357..0000000000 --- a/src/csharp/Grpc.Core/Stub/AbstractStub.cs +++ /dev/null @@ -1,75 +0,0 @@ -#region Copyright notice and license - -// Copyright 2015, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#endregion - -using System; -using Grpc.Core.Internal; - -namespace Grpc.Core -{ - // TODO: support adding timeout to methods. - /// - /// Base for client-side stubs. - /// - public abstract class AbstractStub - where TConfig : StubConfiguration - { - readonly Channel channel; - readonly TConfig config; - - public AbstractStub(Channel channel, TConfig config) - { - this.channel = channel; - this.config = config; - } - - public Channel Channel - { - get - { - return this.channel; - } - } - - /// - /// Creates a new call to given method. - /// - protected Call CreateCall(string serviceName, Method method) - where TRequest : class - where TResponse : class - { - var headerBuilder = Metadata.CreateBuilder(); - config.HeaderInterceptor(headerBuilder); - return new Call(serviceName, method, channel, headerBuilder.Build()); - } - } -} diff --git a/src/csharp/Grpc.Core/Stub/StubConfiguration.cs b/src/csharp/Grpc.Core/Stub/StubConfiguration.cs deleted file mode 100644 index 5bcb5b40d2..0000000000 --- a/src/csharp/Grpc.Core/Stub/StubConfiguration.cs +++ /dev/null @@ -1,64 +0,0 @@ -#region Copyright notice and license - -// Copyright 2015, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#endregion - -using System; -using Grpc.Core.Internal; -using Grpc.Core.Utils; - -namespace Grpc.Core -{ - public delegate void HeaderInterceptorDelegate(Metadata.Builder headerBuilder); - - public class StubConfiguration - { - /// - /// The default stub configuration. - /// - public static readonly StubConfiguration Default = new StubConfiguration((headerBuilder) => { }); - - readonly HeaderInterceptorDelegate headerInterceptor; - - public StubConfiguration(HeaderInterceptorDelegate headerInterceptor) - { - this.headerInterceptor = Preconditions.CheckNotNull(headerInterceptor); - } - - public HeaderInterceptorDelegate HeaderInterceptor - { - get - { - return headerInterceptor; - } - } - } -} diff --git a/src/csharp/Grpc.Core/Version.cs b/src/csharp/Grpc.Core/Version.cs index 972f495bd7..f1db1f6157 100644 --- a/src/csharp/Grpc.Core/Version.cs +++ b/src/csharp/Grpc.Core/Version.cs @@ -3,4 +3,3 @@ using System.Runtime.CompilerServices; // The current version of gRPC C#. [assembly: AssemblyVersion("0.6.0.*")] - diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs index b763721460..cfe2a06916 100644 --- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs +++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs @@ -41,18 +41,18 @@ namespace math { using (Channel channel = new Channel("127.0.0.1", 23456)) { - Math.IMathClient stub = new Math.MathClient(channel); - MathExamples.DivExample(stub); + Math.IMathClient client = new Math.MathClient(channel); + MathExamples.DivExample(client); - MathExamples.DivAsyncExample(stub).Wait(); + MathExamples.DivAsyncExample(client).Wait(); - MathExamples.FibExample(stub).Wait(); + MathExamples.FibExample(client).Wait(); - MathExamples.SumExample(stub).Wait(); + MathExamples.SumExample(client).Wait(); - MathExamples.DivManyExample(stub).Wait(); + MathExamples.DivManyExample(client).Wait(); - MathExamples.DependendRequestsExample(stub).Wait(); + MathExamples.DependendRequestsExample(client).Wait(); } GrpcEnvironment.Shutdown(); diff --git a/src/csharp/Grpc.Examples/MathExamples.cs b/src/csharp/Grpc.Examples/MathExamples.cs index d2cfbee18f..7deb651689 100644 --- a/src/csharp/Grpc.Examples/MathExamples.cs +++ b/src/csharp/Grpc.Examples/MathExamples.cs @@ -38,29 +38,29 @@ namespace math { public static class MathExamples { - public static void DivExample(Math.IMathClient stub) + public static void DivExample(Math.IMathClient client) { - DivReply result = stub.Div(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build()); + DivReply result = client.Div(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build()); Console.WriteLine("Div Result: " + result); } - public static async Task DivAsyncExample(Math.IMathClient stub) + public static async Task DivAsyncExample(Math.IMathClient client) { - Task resultTask = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build()); + Task resultTask = client.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build()); DivReply result = await resultTask; Console.WriteLine("DivAsync Result: " + result); } - public static async Task FibExample(Math.IMathClient stub) + public static async Task FibExample(Math.IMathClient client) { - using (var call = stub.Fib(new FibArgs.Builder { Limit = 5 }.Build())) + using (var call = client.Fib(new FibArgs.Builder { Limit = 5 }.Build())) { List result = await call.ResponseStream.ToList(); Console.WriteLine("Fib Result: " + string.Join("|", result)); } } - public static async Task SumExample(Math.IMathClient stub) + public static async Task SumExample(Math.IMathClient client) { var numbers = new List { @@ -69,14 +69,14 @@ namespace math new Num.Builder { Num_ = 3 }.Build() }; - using (var call = stub.Sum()) + using (var call = client.Sum()) { await call.RequestStream.WriteAll(numbers); Console.WriteLine("Sum Result: " + await call.Result); } } - public static async Task DivManyExample(Math.IMathClient stub) + public static async Task DivManyExample(Math.IMathClient client) { var divArgsList = new List { @@ -84,14 +84,14 @@ namespace math new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(), new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build() }; - using (var call = stub.DivMany()) + using (var call = client.DivMany()) { await call.RequestStream.WriteAll(divArgsList); Console.WriteLine("DivMany Result: " + string.Join("|", await call.ResponseStream.ToList())); } } - public static async Task DependendRequestsExample(Math.IMathClient stub) + public static async Task DependendRequestsExample(Math.IMathClient client) { var numbers = new List { @@ -101,13 +101,13 @@ namespace math }; Num sum; - using (var sumCall = stub.Sum()) + using (var sumCall = client.Sum()) { await sumCall.RequestStream.WriteAll(numbers); sum = await sumCall.Result; } - DivReply result = await stub.DivAsync(new DivArgs.Builder { Dividend = sum.Num_, Divisor = numbers.Count }.Build()); + DivReply result = await client.DivAsync(new DivArgs.Builder { Dividend = sum.Num_, Divisor = numbers.Count }.Build()); Console.WriteLine("Avg Result: " + result); } } diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs index b9efc44e8c..bf820e2e3a 100644 --- a/src/csharp/Grpc.Examples/MathGrpc.cs +++ b/src/csharp/Grpc.Examples/MathGrpc.cs @@ -61,7 +61,7 @@ namespace math { } // client stub - public class MathClient : AbstractStub, IMathClient + public class MathClient : ClientBase, IMathClient { public MathClient(Channel channel) : this(channel, StubConfiguration.Default) { diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs index ed9fc4ed77..d135ebd8c3 100644 --- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs +++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs @@ -35,7 +35,7 @@ namespace Grpc.Health.V1Alpha { } // client stub - public class HealthClient : AbstractStub, IHealthClient + public class HealthClient : ClientBase, IHealthClient { public HealthClient(Channel channel) : this(channel, StubConfiguration.Default) { diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs index ee077f9f56..35b9b3de40 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs @@ -81,7 +81,7 @@ namespace grpc.testing { } // client stub - public class TestServiceClient : AbstractStub, ITestServiceClient + public class TestServiceClient : ClientBase, ITestServiceClient { public TestServiceClient(Channel channel) : this(channel, StubConfiguration.Default) { -- cgit v1.2.3