aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp/Grpc.Core
diff options
context:
space:
mode:
authorGravatar Tim Emiola <tbetbetbe@users.noreply.github.com>2015-03-17 09:35:19 -0700
committerGravatar Tim Emiola <tbetbetbe@users.noreply.github.com>2015-03-17 09:35:19 -0700
commit09eaec027ab4b3d97cb239820af98fe0c460f287 (patch)
tree150db9cb6b7d20f3022735ad7876f32080b66bf4 /src/csharp/Grpc.Core
parent4708fbb3fb55afb6481c3737b2808c87b917a790 (diff)
parentc0b3721d61fed71a3528cecfa6797cdc26722d3a (diff)
Merge pull request #1053 from jtattermusch/csharp_metadata
Added support for sending metadata from clients.
Diffstat (limited to 'src/csharp/Grpc.Core')
-rw-r--r--src/csharp/Grpc.Core/Call.cs55
-rw-r--r--src/csharp/Grpc.Core/Calls.cs30
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj7
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs37
-rw-r--r--src/csharp/Grpc.Core/Internal/CallSafeHandle.cs33
-rw-r--r--src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs72
-rw-r--r--src/csharp/Grpc.Core/Marshaller.cs5
-rw-r--r--src/csharp/Grpc.Core/Metadata.cs126
-rw-r--r--src/csharp/Grpc.Core/ServerServiceDefinition.cs15
-rw-r--r--src/csharp/Grpc.Core/Stub/AbstractStub.cs73
-rw-r--r--src/csharp/Grpc.Core/Stub/StubConfiguration.cs64
11 files changed, 442 insertions, 75 deletions
diff --git a/src/csharp/Grpc.Core/Call.cs b/src/csharp/Grpc.Core/Call.cs
index d84d5940c2..fe5f40f5e9 100644
--- a/src/csharp/Grpc.Core/Call.cs
+++ b/src/csharp/Grpc.Core/Call.cs
@@ -33,65 +33,70 @@
using System;
using Grpc.Core.Internal;
+using Grpc.Core.Utils;
namespace Grpc.Core
{
public class Call<TRequest, TResponse>
{
- readonly string methodName;
- readonly Func<TRequest, byte[]> requestSerializer;
- readonly Func<byte[], TResponse> responseDeserializer;
+ readonly string name;
+ readonly Marshaller<TRequest> requestMarshaller;
+ readonly Marshaller<TResponse> responseMarshaller;
readonly Channel channel;
+ readonly Metadata headers;
- public Call(string methodName,
- Func<TRequest, byte[]> requestSerializer,
- Func<byte[], TResponse> responseDeserializer,
- TimeSpan timeout,
- Channel channel)
+ public Call(string serviceName, Method<TRequest, TResponse> method, Channel channel, Metadata headers)
{
- this.methodName = methodName;
- this.requestSerializer = requestSerializer;
- this.responseDeserializer = responseDeserializer;
- this.channel = channel;
+ this.name = Preconditions.CheckNotNull(serviceName) + "/" + method.Name;
+ this.requestMarshaller = method.RequestMarshaller;
+ this.responseMarshaller = method.ResponseMarshaller;
+ this.channel = Preconditions.CheckNotNull(channel);
+ this.headers = Preconditions.CheckNotNull(headers);
}
- public Call(Method<TRequest, TResponse> method, Channel channel)
+ public Channel Channel
{
- this.methodName = method.Name;
- this.requestSerializer = method.RequestMarshaller.Serializer;
- this.responseDeserializer = method.ResponseMarshaller.Deserializer;
- this.channel = channel;
+ get
+ {
+ return this.channel;
+ }
}
- public Channel Channel
+ /// <summary>
+ /// Full methods name including the service name.
+ /// </summary>
+ public string Name
{
get
{
- return this.channel;
+ return name;
}
}
- public string MethodName
+ /// <summary>
+ /// Headers to send at the beginning of the call.
+ /// </summary>
+ public Metadata Headers
{
get
{
- return this.methodName;
+ return headers;
}
}
- public Func<TRequest, byte[]> RequestSerializer
+ public Marshaller<TRequest> RequestMarshaller
{
get
{
- return this.requestSerializer;
+ return requestMarshaller;
}
}
- public Func<byte[], TResponse> ResponseDeserializer
+ public Marshaller<TResponse> ResponseMarshaller
{
get
{
- return this.responseDeserializer;
+ return responseMarshaller;
}
}
}
diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs
index cc1d67afca..280387b323 100644
--- a/src/csharp/Grpc.Core/Calls.cs
+++ b/src/csharp/Grpc.Core/Calls.cs
@@ -45,30 +45,29 @@ namespace Grpc.Core
{
public static TResponse BlockingUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token)
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestSerializer, call.ResponseDeserializer);
- return asyncCall.UnaryCall(call.Channel, call.MethodName, req);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
+ return asyncCall.UnaryCall(call.Channel, call.Name, req, call.Headers);
}
public static async Task<TResponse> AsyncUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token)
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestSerializer, call.ResponseDeserializer);
- asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.MethodName);
- return await asyncCall.UnaryCallAsync(req);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
+ asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+ return await asyncCall.UnaryCallAsync(req, call.Headers);
}
public static void AsyncServerStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, IObserver<TResponse> outputs, CancellationToken token)
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestSerializer, call.ResponseDeserializer);
-
- asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.MethodName);
- asyncCall.StartServerStreamingCall(req, outputs);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
+ asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+ asyncCall.StartServerStreamingCall(req, outputs, call.Headers);
}
public static ClientStreamingAsyncResult<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, CancellationToken token)
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestSerializer, call.ResponseDeserializer);
- asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.MethodName);
- var task = asyncCall.ClientStreamingCallAsync();
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
+ asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+ var task = asyncCall.ClientStreamingCallAsync(call.Headers);
var inputs = new ClientStreamingInputObserver<TRequest, TResponse>(asyncCall);
return new ClientStreamingAsyncResult<TRequest, TResponse>(task, inputs);
}
@@ -80,10 +79,9 @@ namespace Grpc.Core
public static IObserver<TRequest> DuplexStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, IObserver<TResponse> outputs, CancellationToken token)
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestSerializer, call.ResponseDeserializer);
- asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.MethodName);
-
- asyncCall.StartDuplexStreamingCall(outputs);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
+ asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+ asyncCall.StartDuplexStreamingCall(outputs, call.Headers);
return new ClientStreamingInputObserver<TRequest, TResponse>(asyncCall);
}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 29f1a0604a..78ba32b277 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -79,6 +79,10 @@
<Compile Include="Utils\Preconditions.cs" />
<Compile Include="Internal\ServerCredentialsSafeHandle.cs" />
<Compile Include="ServerCredentials.cs" />
+ <Compile Include="Metadata.cs" />
+ <Compile Include="Internal\MetadataArraySafeHandle.cs" />
+ <Compile Include="Stub\AbstractStub.cs" />
+ <Compile Include="Stub\StubConfiguration.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
@@ -96,4 +100,7 @@
<Otherwise />
</Choose>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <Folder Include="Stub\" />
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 04fc28d988..bc72cb78de 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -77,7 +77,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Blocking unary request - unary response call.
/// </summary>
- public TResponse UnaryCall(Channel channel, string methodName, TRequest msg)
+ public TResponse UnaryCall(Channel channel, string methodName, TRequest msg, Metadata headers)
{
using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create())
{
@@ -92,7 +92,11 @@ namespace Grpc.Core.Internal
halfcloseRequested = true;
readingDone = true;
}
- call.BlockingUnary(cq, payload, unaryResponseHandler);
+
+ using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ {
+ call.BlockingUnary(cq, payload, unaryResponseHandler, metadataArray);
+ }
try
{
@@ -109,7 +113,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Starts a unary request - unary response call.
/// </summary>
- public Task<TResponse> UnaryCallAsync(TRequest msg)
+ public Task<TResponse> UnaryCallAsync(TRequest msg, Metadata headers)
{
lock (myLock)
{
@@ -122,8 +126,10 @@ namespace Grpc.Core.Internal
byte[] payload = UnsafeSerialize(msg);
unaryResponseTcs = new TaskCompletionSource<TResponse>();
- call.StartUnary(payload, unaryResponseHandler);
-
+ using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ {
+ call.StartUnary(payload, unaryResponseHandler, metadataArray);
+ }
return unaryResponseTcs.Task;
}
}
@@ -132,7 +138,7 @@ namespace Grpc.Core.Internal
/// Starts a streamed request - unary response call.
/// Use StartSendMessage and StartSendCloseFromClient to stream requests.
/// </summary>
- public Task<TResponse> ClientStreamingCallAsync()
+ public Task<TResponse> ClientStreamingCallAsync(Metadata headers)
{
lock (myLock)
{
@@ -142,7 +148,10 @@ namespace Grpc.Core.Internal
readingDone = true;
unaryResponseTcs = new TaskCompletionSource<TResponse>();
- call.StartClientStreaming(unaryResponseHandler);
+ using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ {
+ call.StartClientStreaming(unaryResponseHandler, metadataArray);
+ }
return unaryResponseTcs.Task;
}
@@ -151,7 +160,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Starts a unary request - streamed response call.
/// </summary>
- public void StartServerStreamingCall(TRequest msg, IObserver<TResponse> readObserver)
+ public void StartServerStreamingCall(TRequest msg, IObserver<TResponse> readObserver, Metadata headers)
{
lock (myLock)
{
@@ -165,7 +174,10 @@ namespace Grpc.Core.Internal
byte[] payload = UnsafeSerialize(msg);
- call.StartServerStreaming(payload, finishedHandler);
+ using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ {
+ call.StartServerStreaming(payload, finishedHandler, metadataArray);
+ }
StartReceiveMessage();
}
@@ -175,7 +187,7 @@ namespace Grpc.Core.Internal
/// Starts a streaming request - streaming response call.
/// Use StartSendMessage and StartSendCloseFromClient to stream requests.
/// </summary>
- public void StartDuplexStreamingCall(IObserver<TResponse> readObserver)
+ public void StartDuplexStreamingCall(IObserver<TResponse> readObserver, Metadata headers)
{
lock (myLock)
{
@@ -185,7 +197,10 @@ namespace Grpc.Core.Internal
this.readObserver = readObserver;
- call.StartDuplexStreaming(finishedHandler);
+ using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ {
+ call.StartDuplexStreaming(finishedHandler, metadataArray);
+ }
StartReceiveMessage();
}
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index a8cef4a68b..14add60c72 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -57,25 +57,28 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_unary(CallSafeHandle call,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
- byte[] send_buffer, UIntPtr send_buffer_len);
+ byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_call_blocking_unary(CallSafeHandle call, CompletionQueueSafeHandle dedicatedCq,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
- byte[] send_buffer, UIntPtr send_buffer_len);
+ byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_client_streaming(CallSafeHandle call,
- [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback);
+ [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
+ MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_server_streaming(CallSafeHandle call,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
- byte[] send_buffer, UIntPtr send_buffer_len);
+ byte[] send_buffer, UIntPtr send_buffer_len,
+ MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call,
- [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback);
+ [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
+ MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_send_message(CallSafeHandle call,
@@ -109,29 +112,29 @@ namespace Grpc.Core.Internal
return grpcsharp_channel_create_call(channel, cq, method, host, deadline);
}
- public void StartUnary(byte[] payload, CompletionCallbackDelegate callback)
+ public void StartUnary(byte[] payload, CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray)
{
- AssertCallOk(grpcsharp_call_start_unary(this, callback, payload, new UIntPtr((ulong)payload.Length)));
+ AssertCallOk(grpcsharp_call_start_unary(this, callback, payload, new UIntPtr((ulong)payload.Length), metadataArray));
}
- public void BlockingUnary(CompletionQueueSafeHandle dedicatedCq, byte[] payload, CompletionCallbackDelegate callback)
+ public void BlockingUnary(CompletionQueueSafeHandle dedicatedCq, byte[] payload, CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray)
{
- grpcsharp_call_blocking_unary(this, dedicatedCq, callback, payload, new UIntPtr((ulong)payload.Length));
+ grpcsharp_call_blocking_unary(this, dedicatedCq, callback, payload, new UIntPtr((ulong)payload.Length), metadataArray);
}
- public void StartClientStreaming(CompletionCallbackDelegate callback)
+ public void StartClientStreaming(CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray)
{
- AssertCallOk(grpcsharp_call_start_client_streaming(this, callback));
+ AssertCallOk(grpcsharp_call_start_client_streaming(this, callback, metadataArray));
}
- public void StartServerStreaming(byte[] payload, CompletionCallbackDelegate callback)
+ public void StartServerStreaming(byte[] payload, CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray)
{
- AssertCallOk(grpcsharp_call_start_server_streaming(this, callback, payload, new UIntPtr((ulong)payload.Length)));
+ AssertCallOk(grpcsharp_call_start_server_streaming(this, callback, payload, new UIntPtr((ulong)payload.Length), metadataArray));
}
- public void StartDuplexStreaming(CompletionCallbackDelegate callback)
+ public void StartDuplexStreaming(CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray)
{
- AssertCallOk(grpcsharp_call_start_duplex_streaming(this, callback));
+ AssertCallOk(grpcsharp_call_start_duplex_streaming(this, callback, metadataArray));
}
public void StartSendMessage(byte[] payload, CompletionCallbackDelegate callback)
diff --git a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
new file mode 100644
index 0000000000..c9c4d954c9
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
@@ -0,0 +1,72 @@
+#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.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+namespace Grpc.Core.Internal
+{
+ /// <summary>
+ /// grpc_metadata_array from <grpc/grpc.h>
+ /// </summary>
+ internal class MetadataArraySafeHandle : SafeHandleZeroIsInvalid
+ {
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern MetadataArraySafeHandle grpcsharp_metadata_array_create(UIntPtr capacity);
+
+ [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
+ static extern void grpcsharp_metadata_array_add(MetadataArraySafeHandle array, string key, byte[] value, UIntPtr valueLength);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_metadata_array_destroy_full(IntPtr array);
+
+ private MetadataArraySafeHandle()
+ {
+ }
+
+ 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++)
+ {
+ grpcsharp_metadata_array_add(metadataArray, entries[i].Key, entries[i].ValueBytes, new UIntPtr((ulong)entries[i].ValueBytes.Length));
+ }
+ return metadataArray;
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ grpcsharp_metadata_array_destroy_full(handle);
+ return true;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Marshaller.cs b/src/csharp/Grpc.Core/Marshaller.cs
index e73e7b762e..8b1a929074 100644
--- a/src/csharp/Grpc.Core/Marshaller.cs
+++ b/src/csharp/Grpc.Core/Marshaller.cs
@@ -32,6 +32,7 @@
#endregion
using System;
+using Grpc.Core.Utils;
namespace Grpc.Core
{
@@ -45,8 +46,8 @@ namespace Grpc.Core
public Marshaller(Func<T, byte[]> serializer, Func<byte[], T> deserializer)
{
- this.serializer = serializer;
- this.deserializer = deserializer;
+ this.serializer = Preconditions.CheckNotNull(serializer);
+ this.deserializer = Preconditions.CheckNotNull(deserializer);
}
public Func<T, byte[]> Serializer
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
new file mode 100644
index 0000000000..eccec26a61
--- /dev/null
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -0,0 +1,126 @@
+#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.Collections.Immutable;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// gRPC call metadata.
+ /// </summary>
+ public class Metadata
+ {
+ public static readonly Metadata Empty = new Metadata(ImmutableList<MetadataEntry>.Empty);
+
+ readonly ImmutableList<MetadataEntry> entries;
+
+ public Metadata(ImmutableList<MetadataEntry> entries)
+ {
+ this.entries = entries;
+ }
+
+ public ImmutableList<MetadataEntry> Entries
+ {
+ get
+ {
+ return this.entries;
+ }
+ }
+
+ public static Builder CreateBuilder()
+ {
+ return new Builder();
+ }
+
+ public struct MetadataEntry
+ {
+ readonly string key;
+ readonly byte[] valueBytes;
+
+ public MetadataEntry(string key, byte[] valueBytes)
+ {
+ this.key = key;
+ this.valueBytes = valueBytes;
+ }
+
+ public MetadataEntry(string key, string value)
+ {
+ this.key = key;
+ this.valueBytes = Encoding.ASCII.GetBytes(value);
+ }
+
+ public string Key
+ {
+ get
+ {
+ return this.key;
+ }
+ }
+
+ // TODO: using ByteString would guarantee immutability.
+ public byte[] ValueBytes
+ {
+ get
+ {
+ return this.valueBytes;
+ }
+ }
+ }
+
+ public class Builder
+ {
+ readonly List<Metadata.MetadataEntry> entries = new List<Metadata.MetadataEntry>();
+
+ public List<MetadataEntry> Entries
+ {
+ get
+ {
+ return entries;
+ }
+ }
+
+ 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/ServerServiceDefinition.cs b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
index 004415477c..f08c7d88f3 100644
--- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs
+++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
@@ -43,12 +43,10 @@ namespace Grpc.Core
/// </summary>
public class ServerServiceDefinition
{
- readonly string serviceName;
readonly ImmutableDictionary<string, IServerCallHandler> callHandlers;
- private ServerServiceDefinition(string serviceName, ImmutableDictionary<string, IServerCallHandler> callHandlers)
+ private ServerServiceDefinition(ImmutableDictionary<string, IServerCallHandler> callHandlers)
{
- this.serviceName = serviceName;
this.callHandlers = callHandlers;
}
@@ -79,7 +77,7 @@ namespace Grpc.Core
Method<TRequest, TResponse> method,
UnaryRequestServerMethod<TRequest, TResponse> handler)
{
- callHandlers.Add(method.Name, ServerCalls.UnaryRequestCall(method, handler));
+ callHandlers.Add(GetFullMethodName(serviceName, method.Name), ServerCalls.UnaryRequestCall(method, handler));
return this;
}
@@ -87,13 +85,18 @@ namespace Grpc.Core
Method<TRequest, TResponse> method,
StreamingRequestServerMethod<TRequest, TResponse> handler)
{
- callHandlers.Add(method.Name, ServerCalls.StreamingRequestCall(method, handler));
+ callHandlers.Add(GetFullMethodName(serviceName, method.Name), ServerCalls.StreamingRequestCall(method, handler));
return this;
}
public ServerServiceDefinition Build()
{
- return new ServerServiceDefinition(serviceName, callHandlers.ToImmutableDictionary());
+ return new ServerServiceDefinition(callHandlers.ToImmutableDictionary());
+ }
+
+ private string GetFullMethodName(string serviceName, string methodName)
+ {
+ return serviceName + "/" + methodName;
}
}
}
diff --git a/src/csharp/Grpc.Core/Stub/AbstractStub.cs b/src/csharp/Grpc.Core/Stub/AbstractStub.cs
new file mode 100644
index 0000000000..cf5ab958c5
--- /dev/null
+++ b/src/csharp/Grpc.Core/Stub/AbstractStub.cs
@@ -0,0 +1,73 @@
+#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.
+ /// <summary>
+ /// Base for client-side stubs.
+ /// </summary>
+ public abstract class AbstractStub<TStub, TConfig>
+ 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;
+ }
+ }
+
+ /// <summary>
+ /// Creates a new call to given method.
+ /// </summary>
+ protected Call<TRequest, TResponse> CreateCall<TRequest, TResponse>(string serviceName, Method<TRequest, TResponse> method)
+ {
+ var headerBuilder = Metadata.CreateBuilder();
+ config.HeaderInterceptor(headerBuilder);
+ return new Call<TRequest, TResponse>(serviceName, method, channel, headerBuilder.Build());
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Stub/StubConfiguration.cs b/src/csharp/Grpc.Core/Stub/StubConfiguration.cs
new file mode 100644
index 0000000000..5bcb5b40d2
--- /dev/null
+++ b/src/csharp/Grpc.Core/Stub/StubConfiguration.cs
@@ -0,0 +1,64 @@
+#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;
+ }
+ }
+ }
+}