Skip to content

Commit

Permalink
Merge pull request grpc#1053 from jtattermusch/csharp_metadata
Browse files Browse the repository at this point in the history
Added support for sending metadata from clients.
  • Loading branch information
tbetbetbe committed Mar 17, 2015
2 parents 4708fbb + c0b3721 commit 09eaec0
Show file tree
Hide file tree
Showing 19 changed files with 694 additions and 154 deletions.
14 changes: 8 additions & 6 deletions src/csharp/Grpc.Core.Tests/ClientServerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public class ClientServerTest
{
string host = "localhost";

string serviceName = "/tests.Test";

Method<string, string> unaryEchoStringMethod = new Method<string, string>(
MethodType.Unary,
"/tests.Test/UnaryEchoString",
Expand All @@ -69,15 +71,15 @@ public void UnaryCall()
{
Server server = new Server();
server.AddServiceDefinition(
ServerServiceDefinition.CreateBuilder("someService")
ServerServiceDefinition.CreateBuilder(serviceName)
.AddMethod(unaryEchoStringMethod, HandleUnaryEchoString).Build());

int port = server.AddPort(host + ":0");
server.Start();

using (Channel channel = new Channel(host + ":" + port))
{
var call = new Call<string, string>(unaryEchoStringMethod, channel);
var call = new Call<string, string>(serviceName, unaryEchoStringMethod, channel, Metadata.Empty);

Assert.AreEqual("ABC", Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken)));

Expand All @@ -92,15 +94,15 @@ public void UnaryCallPerformance()
{
Server server = new Server();
server.AddServiceDefinition(
ServerServiceDefinition.CreateBuilder("someService")
ServerServiceDefinition.CreateBuilder(serviceName)
.AddMethod(unaryEchoStringMethod, HandleUnaryEchoString).Build());

int port = server.AddPort(host + ":0");
server.Start();

using (Channel channel = new Channel(host + ":" + port))
{
var call = new Call<string, string>(unaryEchoStringMethod, channel);
var call = new Call<string, string>(serviceName, unaryEchoStringMethod, channel, Metadata.Empty);
BenchmarkUtil.RunBenchmark(100, 1000,
() => { Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken)); });
}
Expand All @@ -113,14 +115,14 @@ public void UnknownMethodHandler()
{
Server server = new Server();
server.AddServiceDefinition(
ServerServiceDefinition.CreateBuilder("someService").Build());
ServerServiceDefinition.CreateBuilder(serviceName).Build());

int port = server.AddPort(host + ":0");
server.Start();

using (Channel channel = new Channel(host + ":" + port))
{
var call = new Call<string, string>(unaryEchoStringMethod, channel);
var call = new Call<string, string>(serviceName, unaryEchoStringMethod, channel, Metadata.Empty);

try
{
Expand Down
4 changes: 4 additions & 0 deletions src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
<Compile Include="GrpcEnvironmentTest.cs" />
<Compile Include="TimespecTest.cs" />
<Compile Include="PInvokeTest.cs" />
<Compile Include="Internal\MetadataArraySafeHandleTest.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
Expand All @@ -56,4 +57,7 @@
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<Folder Include="Internal\" />
</ItemGroup>
</Project>
62 changes: 62 additions & 0 deletions src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#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;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;

namespace Grpc.Core.Internal.Tests
{
public class MetadataArraySafeHandleTest
{
[Test]
public void CreateEmptyAndDestroy()
{
var metadata = Metadata.CreateBuilder().Build();
var nativeMetadata = MetadataArraySafeHandle.Create(metadata);
nativeMetadata.Dispose();
}

[Test]
public void CreateAndDestroy()
{
var metadata = Metadata.CreateBuilder()
.Add(new Metadata.MetadataEntry("host", "somehost"))
.Add(new Metadata.MetadataEntry("header2", "header value")).Build();
var nativeMetadata = MetadataArraySafeHandle.Create(metadata);
nativeMetadata.Dispose();
}
}
}
55 changes: 30 additions & 25 deletions src/csharp/Grpc.Core/Call.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
Expand Down
30 changes: 14 additions & 16 deletions src/csharp/Grpc.Core/Calls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,30 +45,29 @@ public static class Calls
{
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);
}
Expand All @@ -80,10 +79,9 @@ public static TResponse BlockingClientStreamingCall<TRequest, TResponse>(Call<TR

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);
}

Expand Down
7 changes: 7 additions & 0 deletions src/csharp/Grpc.Core/Grpc.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand All @@ -96,4 +100,7 @@
<Otherwise />
</Choose>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<Folder Include="Stub\" />
</ItemGroup>
</Project>
Loading

0 comments on commit 09eaec0

Please sign in to comment.