aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs8
-rw-r--r--src/csharp/Grpc.Core/Calls.cs2
-rw-r--r--src/csharp/Grpc.Core/ClientBase.cs (renamed from src/csharp/Grpc.Core/Stub/AbstractStub.cs)34
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj3
-rw-r--r--src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs8
-rw-r--r--src/csharp/Grpc.Core/Metadata.cs179
-rw-r--r--src/csharp/Grpc.Core/Stub/StubConfiguration.cs64
-rw-r--r--src/csharp/Grpc.Core/Version.cs1
-rw-r--r--src/csharp/Grpc.Examples.MathClient/MathClient.cs14
-rw-r--r--src/csharp/Grpc.Examples/MathExamples.cs26
-rw-r--r--src/csharp/Grpc.Examples/MathGrpc.cs2
-rw-r--r--src/csharp/Grpc.HealthCheck/HealthGrpc.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestGrpc.cs2
13 files changed, 196 insertions, 149 deletions
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
/// <summary>
/// Creates OAuth2 interceptor.
/// </summary>
- 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);
}
/// <summary>
@@ -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
{
/// <summary>
- /// Helper methods for generated client stubs to make RPC calls.
+ /// Helper methods for generated clients to make RPC calls.
/// </summary>
public static class Calls
{
diff --git a/src/csharp/Grpc.Core/Stub/AbstractStub.cs b/src/csharp/Grpc.Core/ClientBase.cs
index 4a8b254357..59dc40ba4e 100644
--- a/src/csharp/Grpc.Core/Stub/AbstractStub.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -32,26 +32,39 @@
#endregion
using System;
+using System.Collections.Generic;
+
using Grpc.Core.Internal;
namespace Grpc.Core
{
- // TODO: support adding timeout to methods.
+ public delegate void MetadataInterceptorDelegate(Metadata metadata);
+
/// <summary>
- /// Base for client-side stubs.
+ /// Base class for client-side stubs.
/// </summary>
- public abstract class AbstractStub<TStub, TConfig>
- where TConfig : StubConfiguration
+ public abstract class ClientBase
{
readonly Channel channel;
- readonly TConfig config;
- public AbstractStub(Channel channel, TConfig config)
+ public ClientBase(Channel channel)
{
this.channel = channel;
- this.config = config;
}
+ /// <summary>
+ /// Can be used to register a custom header (initial metadata) interceptor.
+ /// The delegate each time before a new call on this client is started.
+ /// </summary>
+ public MetadataInterceptorDelegate HeaderInterceptor
+ {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// Channel associated with this client.
+ /// </summary>
public Channel Channel
{
get
@@ -67,9 +80,10 @@ namespace Grpc.Core
where TRequest : class
where TResponse : class
{
- var headerBuilder = Metadata.CreateBuilder();
- config.HeaderInterceptor(headerBuilder);
- return new Call<TRequest, TResponse>(serviceName, method, channel, headerBuilder.Build());
+ var metadata = new Metadata();
+ HeaderInterceptor(metadata);
+ metadata.Freeze();
+ return new Call<TRequest, TResponse>(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 @@
<Compile Include="ServerCredentials.cs" />
<Compile Include="Metadata.cs" />
<Compile Include="Internal\MetadataArraySafeHandle.cs" />
- <Compile Include="Stub\AbstractStub.cs" />
- <Compile Include="Stub\StubConfiguration.cs" />
+ <Compile Include="ClientBase.cs" />
<Compile Include="Internal\ServerCalls.cs" />
<Compile Include="ServerMethods.cs" />
<Compile Include="Internal\ClientRequestStream.cs" />
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
{
/// <summary>
- /// gRPC call metadata.
+ /// Provides access to read and write metadata values to be exchanged during a call.
/// </summary>
- public class Metadata
+ public sealed class Metadata : IList<Metadata.Entry>
{
- public static readonly Metadata Empty = new Metadata(ImmutableList<MetadataEntry>.Empty);
+ /// <summary>
+ /// An read-only instance of metadata containing no entries.
+ /// </summary>
+ public static readonly Metadata Empty = new Metadata().Freeze();
+
+ readonly List<Entry> entries;
+ bool readOnly;
+
+ public Metadata()
+ {
+ this.entries = new List<Entry>();
+ }
+
+ public Metadata(ICollection<Entry> entries)
+ {
+ this.entries = new List<Entry>(entries);
+ }
+
+ /// <summary>
+ /// Makes this object read-only.
+ /// </summary>
+ /// <returns>this object</returns>
+ 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<MetadataEntry> entries;
+ public void Insert(int index, Metadata.Entry item)
+ {
+ CheckWriteable();
+ entries.Insert(index, item);
+ }
- public Metadata(ImmutableList<MetadataEntry> entries)
+ public void RemoveAt(int index)
{
- this.entries = entries;
+ CheckWriteable();
+ entries.RemoveAt(index);
}
- public ImmutableList<MetadataEntry> 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<Metadata.Entry> GetEnumerator()
+ {
+ return entries.GetEnumerator();
+ }
+
+ IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return entries.GetEnumerator();
+ }
+
+ private void CheckWriteable()
+ {
+ Preconditions.CheckState(!readOnly, "Object is read only");
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Metadata entry
+ /// </summary>
+ 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<Metadata.MetadataEntry> entries = new List<Metadata.MetadataEntry>();
-
- public List<MetadataEntry> 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/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
- {
- /// <summary>
- /// The default stub configuration.
- /// </summary>
- 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<DivReply> resultTask = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
+ Task<DivReply> 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<Num> 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<Num>
{
@@ -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<DivArgs>
{
@@ -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<Num>
{
@@ -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<MathClient, StubConfiguration>, IMathClient
+ public class MathClient : ClientBase<MathClient, StubConfiguration>, 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<HealthClient, StubConfiguration>, IHealthClient
+ public class HealthClient : ClientBase<HealthClient, StubConfiguration>, 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<TestServiceClient, StubConfiguration>, ITestServiceClient
+ public class TestServiceClient : ClientBase<TestServiceClient, StubConfiguration>, ITestServiceClient
{
public TestServiceClient(Channel channel) : this(channel, StubConfiguration.Default)
{