diff options
Diffstat (limited to 'src/csharp')
35 files changed, 797 insertions, 330 deletions
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index 35924868ca..64ea21800f 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -46,23 +46,26 @@ namespace Grpc.Core.Tests public class ClientServerTest { const string Host = "127.0.0.1"; - const string ServiceName = "/tests.Test"; + const string ServiceName = "tests.Test"; static readonly Method<string, string> EchoMethod = new Method<string, string>( MethodType.Unary, - "/tests.Test/Echo", + ServiceName, + "Echo", Marshallers.StringMarshaller, Marshallers.StringMarshaller); static readonly Method<string, string> ConcatAndEchoMethod = new Method<string, string>( MethodType.ClientStreaming, - "/tests.Test/ConcatAndEcho", + ServiceName, + "ConcatAndEcho", Marshallers.StringMarshaller, Marshallers.StringMarshaller); static readonly Method<string, string> NonexistentMethod = new Method<string, string>( MethodType.Unary, - "/tests.Test/NonexistentMethod", + ServiceName, + "NonexistentMethod", Marshallers.StringMarshaller, Marshallers.StringMarshaller); @@ -77,11 +80,13 @@ namespace Grpc.Core.Tests [SetUp] public void Init() { - server = new Server(); - server.AddServiceDefinition(ServiceDefinition); - int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure); + server = new Server + { + Services = { ServiceDefinition }, + Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } + }; server.Start(); - channel = new Channel(Host, port, Credentials.Insecure); + channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure); } [TearDown] @@ -100,17 +105,17 @@ namespace Grpc.Core.Tests [Test] public void UnaryCall() { - var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); - Assert.AreEqual("ABC", Calls.BlockingUnaryCall(internalCall, "ABC", CancellationToken.None)); + var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions()); + Assert.AreEqual("ABC", Calls.BlockingUnaryCall(callDetails, "ABC")); } [Test] public void UnaryCall_ServerHandlerThrows() { - var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); + var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions()); try { - Calls.BlockingUnaryCall(internalCall, "THROW", CancellationToken.None); + Calls.BlockingUnaryCall(callDetails, "THROW"); Assert.Fail(); } catch (RpcException e) @@ -122,10 +127,10 @@ namespace Grpc.Core.Tests [Test] public void UnaryCall_ServerHandlerThrowsRpcException() { - var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); + var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions()); try { - Calls.BlockingUnaryCall(internalCall, "THROW_UNAUTHENTICATED", CancellationToken.None); + Calls.BlockingUnaryCall(callDetails, "THROW_UNAUTHENTICATED"); Assert.Fail(); } catch (RpcException e) @@ -137,10 +142,10 @@ namespace Grpc.Core.Tests [Test] public void UnaryCall_ServerHandlerSetsStatus() { - var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); + var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions()); try { - Calls.BlockingUnaryCall(internalCall, "SET_UNAUTHENTICATED", CancellationToken.None); + Calls.BlockingUnaryCall(callDetails, "SET_UNAUTHENTICATED"); Assert.Fail(); } catch (RpcException e) @@ -150,20 +155,20 @@ namespace Grpc.Core.Tests } [Test] - public void AsyncUnaryCall() + public async Task AsyncUnaryCall() { - var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); - var result = Calls.AsyncUnaryCall(internalCall, "ABC", CancellationToken.None).ResponseAsync.Result; + var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions()); + var result = await Calls.AsyncUnaryCall(callDetails, "ABC"); Assert.AreEqual("ABC", result); } [Test] public async Task AsyncUnaryCall_ServerHandlerThrows() { - var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); + var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions()); try { - await Calls.AsyncUnaryCall(internalCall, "THROW", CancellationToken.None); + await Calls.AsyncUnaryCall(callDetails, "THROW"); Assert.Fail(); } catch (RpcException e) @@ -175,8 +180,8 @@ namespace Grpc.Core.Tests [Test] public async Task ClientStreamingCall() { - var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty); - var call = Calls.AsyncClientStreamingCall(internalCall, CancellationToken.None); + var callDetails = new CallInvocationDetails<string, string>(channel, ConcatAndEchoMethod, new CallOptions()); + var call = Calls.AsyncClientStreamingCall(callDetails); await call.RequestStream.WriteAll(new string[] { "A", "B", "C" }); Assert.AreEqual("ABC", await call.ResponseAsync); @@ -185,10 +190,9 @@ namespace Grpc.Core.Tests [Test] public async Task ClientStreamingCall_CancelAfterBegin() { - var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty); - var cts = new CancellationTokenSource(); - var call = Calls.AsyncClientStreamingCall(internalCall, cts.Token); + var callDetails = new CallInvocationDetails<string, string>(channel, ConcatAndEchoMethod, new CallOptions(cancellationToken: cts.Token)); + var call = Calls.AsyncClientStreamingCall(callDetails); // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it. await Task.Delay(1000); @@ -212,8 +216,8 @@ namespace Grpc.Core.Tests new Metadata.Entry("ascii-header", "abcdefg"), new Metadata.Entry("binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff }), }; - var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, headers); - var call = Calls.AsyncUnaryCall(internalCall, "ABC", CancellationToken.None); + var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions(headers: headers)); + var call = Calls.AsyncUnaryCall(callDetails, "ABC"); Assert.AreEqual("ABC", call.ResponseAsync.Result); @@ -233,25 +237,25 @@ namespace Grpc.Core.Tests { channel.Dispose(); - var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); - Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(internalCall, "ABC", CancellationToken.None)); + var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions()); + Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(callDetails, "ABC")); } [Test] public void UnaryCallPerformance() { - var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); + var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions()); BenchmarkUtil.RunBenchmark(100, 100, - () => { Calls.BlockingUnaryCall(internalCall, "ABC", default(CancellationToken)); }); + () => { Calls.BlockingUnaryCall(callDetails, "ABC"); }); } [Test] public void UnknownMethodHandler() { - var internalCall = new Call<string, string>(ServiceName, NonexistentMethod, channel, Metadata.Empty); + var callDetails = new CallInvocationDetails<string, string>(channel, NonexistentMethod, new CallOptions()); try { - Calls.BlockingUnaryCall(internalCall, "ABC", default(CancellationToken)); + Calls.BlockingUnaryCall(callDetails, "ABC"); Assert.Fail(); } catch (RpcException e) @@ -263,16 +267,16 @@ namespace Grpc.Core.Tests [Test] public void UserAgentStringPresent() { - var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); - string userAgent = Calls.BlockingUnaryCall(internalCall, "RETURN-USER-AGENT", CancellationToken.None); + var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions()); + string userAgent = Calls.BlockingUnaryCall(callDetails, "RETURN-USER-AGENT"); Assert.IsTrue(userAgent.StartsWith("grpc-csharp/")); } [Test] public void PeerInfoPresent() { - var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); - string peer = Calls.BlockingUnaryCall(internalCall, "RETURN-PEER", CancellationToken.None); + var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions()); + string peer = Calls.BlockingUnaryCall(callDetails, "RETURN-PEER"); Assert.IsTrue(peer.Contains(Host)); } @@ -284,8 +288,8 @@ namespace Grpc.Core.Tests var stateChangedTask = channel.WaitForStateChangedAsync(channel.State); - var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); - await Calls.AsyncUnaryCall(internalCall, "abc", CancellationToken.None); + var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions()); + await Calls.AsyncUnaryCall(callDetails, "abc"); await stateChangedTask; Assert.AreEqual(ChannelState.Ready, channel.State); diff --git a/src/csharp/Grpc.Core.Tests/ServerTest.cs b/src/csharp/Grpc.Core.Tests/ServerTest.cs index ba9efae871..485006ebac 100644 --- a/src/csharp/Grpc.Core.Tests/ServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ServerTest.cs @@ -32,6 +32,7 @@ #endregion using System; +using System.Linq; using Grpc.Core; using Grpc.Core.Internal; using Grpc.Core.Utils; @@ -44,11 +45,45 @@ namespace Grpc.Core.Tests [Test] public void StartAndShutdownServer() { - Server server = new Server(); - server.AddPort("localhost", Server.PickUnusedPort, ServerCredentials.Insecure); + Server server = new Server + { + Ports = { new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure) } + }; server.Start(); server.ShutdownAsync().Wait(); GrpcEnvironment.Shutdown(); } + + [Test] + public void PickUnusedPort() + { + Server server = new Server + { + Ports = { new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure) } + }; + + var boundPort = server.Ports.Single(); + Assert.AreEqual(0, boundPort.Port); + Assert.Greater(boundPort.BoundPort, 0); + + server.Start(); + server.ShutdownAsync(); + GrpcEnvironment.Shutdown(); + } + + [Test] + public void CannotModifyAfterStarted() + { + Server server = new Server + { + Ports = { new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure) } + }; + server.Start(); + Assert.Throws(typeof(InvalidOperationException), () => server.Ports.Add("localhost", 9999, ServerCredentials.Insecure)); + Assert.Throws(typeof(InvalidOperationException), () => server.Services.Add(ServerServiceDefinition.CreateBuilder("serviceName").Build())); + + server.ShutdownAsync().Wait(); + GrpcEnvironment.Shutdown(); + } } } diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs index a09273b846..fc395b0acd 100644 --- a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs +++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs @@ -49,11 +49,12 @@ namespace Grpc.Core.Tests public class TimeoutsTest { const string Host = "localhost"; - const string ServiceName = "/tests.Test"; + const string ServiceName = "tests.Test"; static readonly Method<string, string> TestMethod = new Method<string, string>( MethodType.Unary, - "/tests.Test/Test", + ServiceName, + "Test", Marshallers.StringMarshaller, Marshallers.StringMarshaller); @@ -70,11 +71,13 @@ namespace Grpc.Core.Tests [SetUp] public void Init() { - server = new Server(); - server.AddServiceDefinition(ServiceDefinition); - int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure); + server = new Server + { + Services = { ServiceDefinition }, + Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } + }; server.Start(); - channel = new Channel(Host, port, Credentials.Insecure); + channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure); stringFromServerHandlerTcs = new TaskCompletionSource<string>(); } @@ -96,12 +99,12 @@ namespace Grpc.Core.Tests public void InfiniteDeadline() { // no deadline specified, check server sees infinite deadline - var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty); - Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(internalCall, "RETURN_DEADLINE", CancellationToken.None)); + var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions()); + Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(callDetails, "RETURN_DEADLINE")); // DateTime.MaxValue deadline specified, check server sees infinite deadline - var internalCall2 = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, DateTime.MaxValue); - Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(internalCall2, "RETURN_DEADLINE", CancellationToken.None)); + var callDetails2 = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions()); + Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(callDetails2, "RETURN_DEADLINE")); } [Test] @@ -110,9 +113,9 @@ namespace Grpc.Core.Tests var remainingTimeClient = TimeSpan.FromDays(7); var deadline = DateTime.UtcNow + remainingTimeClient; Thread.Sleep(1000); - var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, deadline); + var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions(deadline: deadline)); - var serverDeadlineTicksString = Calls.BlockingUnaryCall(internalCall, "RETURN_DEADLINE", CancellationToken.None); + var serverDeadlineTicksString = Calls.BlockingUnaryCall(callDetails, "RETURN_DEADLINE"); var serverDeadline = new DateTime(long.Parse(serverDeadlineTicksString), DateTimeKind.Utc); // A fairly relaxed check that the deadline set by client and deadline seen by server @@ -124,12 +127,11 @@ namespace Grpc.Core.Tests [Test] public void DeadlineInThePast() { - var deadline = DateTime.MinValue; - var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, deadline); + var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions(deadline: DateTime.MinValue)); try { - Calls.BlockingUnaryCall(internalCall, "TIMEOUT", CancellationToken.None); + Calls.BlockingUnaryCall(callDetails, "TIMEOUT"); Assert.Fail(); } catch (RpcException e) @@ -143,11 +145,11 @@ namespace Grpc.Core.Tests public void DeadlineExceededStatusOnTimeout() { var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)); - var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, deadline); + var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions(deadline: deadline)); try { - Calls.BlockingUnaryCall(internalCall, "TIMEOUT", CancellationToken.None); + Calls.BlockingUnaryCall(callDetails, "TIMEOUT"); Assert.Fail(); } catch (RpcException e) @@ -161,11 +163,11 @@ namespace Grpc.Core.Tests public void ServerReceivesCancellationOnTimeout() { var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)); - var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, deadline); + var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions(deadline: deadline)); try { - Calls.BlockingUnaryCall(internalCall, "CHECK_CANCELLATION_RECEIVED", CancellationToken.None); + Calls.BlockingUnaryCall(callDetails, "CHECK_CANCELLATION_RECEIVED"); Assert.Fail(); } catch (RpcException e) diff --git a/src/csharp/Grpc.Core/Call.cs b/src/csharp/Grpc.Core/CallInvocationDetails.cs index 94c5e26082..eb23a3a209 100644 --- a/src/csharp/Grpc.Core/Call.cs +++ b/src/csharp/Grpc.Core/CallInvocationDetails.cs @@ -38,30 +38,30 @@ using Grpc.Core.Utils; namespace Grpc.Core { /// <summary> - /// Abstraction of a call to be invoked on a client. + /// Details about a client-side call to be invoked. /// </summary> - public class Call<TRequest, TResponse> + public class CallInvocationDetails<TRequest, TResponse> { - readonly string name; + readonly Channel channel; + readonly string method; + readonly string host; readonly Marshaller<TRequest> requestMarshaller; readonly Marshaller<TResponse> responseMarshaller; - readonly Channel channel; - readonly Metadata headers; - readonly DateTime deadline; + readonly CallOptions options; - public Call(string serviceName, Method<TRequest, TResponse> method, Channel channel, Metadata headers) - : this(serviceName, method, channel, headers, DateTime.MaxValue) + public CallInvocationDetails(Channel channel, Method<TRequest, TResponse> method, CallOptions options) : + this(channel, method.FullName, null, method.RequestMarshaller, method.ResponseMarshaller, options) { } - public Call(string serviceName, Method<TRequest, TResponse> method, Channel channel, Metadata headers, DateTime deadline) + public CallInvocationDetails(Channel channel, string method, string host, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller, CallOptions options) { - this.name = method.GetFullName(serviceName); - this.requestMarshaller = method.RequestMarshaller; - this.responseMarshaller = method.ResponseMarshaller; this.channel = Preconditions.CheckNotNull(channel); - this.headers = Preconditions.CheckNotNull(headers); - this.deadline = deadline; + this.method = Preconditions.CheckNotNull(method); + this.host = host; + this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller); + this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller); + this.options = Preconditions.CheckNotNull(options); } public Channel Channel @@ -72,49 +72,43 @@ namespace Grpc.Core } } - /// <summary> - /// Full methods name including the service name. - /// </summary> - public string Name + public string Method { get { - return name; + return this.method; } } - /// <summary> - /// Headers to send at the beginning of the call. - /// </summary> - public Metadata Headers + public string Host { get { - return headers; + return this.host; } } - public DateTime Deadline + public Marshaller<TRequest> RequestMarshaller { get { - return this.deadline; + return this.requestMarshaller; } } - public Marshaller<TRequest> RequestMarshaller + public Marshaller<TResponse> ResponseMarshaller { get { - return requestMarshaller; + return this.responseMarshaller; } } - - public Marshaller<TResponse> ResponseMarshaller + + public CallOptions Options { get { - return responseMarshaller; + return options; } } } diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs new file mode 100644 index 0000000000..8e9739335f --- /dev/null +++ b/src/csharp/Grpc.Core/CallOptions.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.Threading; + +using Grpc.Core.Internal; +using Grpc.Core.Utils; + +namespace Grpc.Core +{ + /// <summary> + /// Options for calls made by client. + /// </summary> + public class CallOptions + { + readonly Metadata headers; + readonly DateTime deadline; + readonly CancellationToken cancellationToken; + + /// <summary> + /// Creates a new instance of <c>CallOptions</c>. + /// </summary> + /// <param name="headers">Headers to be sent with the call.</param> + /// <param name="deadline">Deadline for the call to finish. null means no deadline.</param> + /// <param name="cancellationToken">Can be used to request cancellation of the call.</param> + public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // TODO(jtattermusch): consider only creating metadata object once it's really needed. + this.headers = headers != null ? headers : new Metadata(); + this.deadline = deadline.HasValue ? deadline.Value : DateTime.MaxValue; + this.cancellationToken = cancellationToken; + } + + /// <summary> + /// Headers to send at the beginning of the call. + /// </summary> + public Metadata Headers + { + get { return headers; } + } + + /// <summary> + /// Call deadline. + /// </summary> + public DateTime Deadline + { + get { return deadline; } + } + + /// <summary> + /// Token that can be used for cancelling the call. + /// </summary> + public CancellationToken CancellationToken + { + get { return cancellationToken; } + } + } +} diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs index 054fc27491..00a8cabf82 100644 --- a/src/csharp/Grpc.Core/Calls.cs +++ b/src/csharp/Grpc.Core/Calls.cs @@ -43,70 +43,52 @@ namespace Grpc.Core /// </summary> public static class Calls { - public static TResponse BlockingUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token) + public static TResponse BlockingUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req) where TRequest : class where TResponse : class { - var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); - // TODO(jtattermusch): this gives a race that cancellation can be requested before the call even starts. - RegisterCancellationCallback(asyncCall, token); - return asyncCall.UnaryCall(call.Channel, call.Name, req, call.Headers, call.Deadline); + var asyncCall = new AsyncCall<TRequest, TResponse>(call); + return asyncCall.UnaryCall(req); } - public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token) + public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req) where TRequest : class where TResponse : class { - var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); - asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline)); - var asyncResult = asyncCall.UnaryCallAsync(req, call.Headers, call.Deadline); - RegisterCancellationCallback(asyncCall, token); + var asyncCall = new AsyncCall<TRequest, TResponse>(call); + var asyncResult = asyncCall.UnaryCallAsync(req); return new AsyncUnaryCall<TResponse>(asyncResult, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } - public static AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token) + public static AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req) where TRequest : class where TResponse : class { - var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); - asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline)); - asyncCall.StartServerStreamingCall(req, call.Headers, call.Deadline); - RegisterCancellationCallback(asyncCall, token); + var asyncCall = new AsyncCall<TRequest, TResponse>(call); + asyncCall.StartServerStreamingCall(req); var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall); return new AsyncServerStreamingCall<TResponse>(responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } - public static AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, CancellationToken token) + public static AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call) where TRequest : class where TResponse : class { - var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); - asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline)); - var resultTask = asyncCall.ClientStreamingCallAsync(call.Headers, call.Deadline); - RegisterCancellationCallback(asyncCall, token); + var asyncCall = new AsyncCall<TRequest, TResponse>(call); + var resultTask = asyncCall.ClientStreamingCallAsync(); var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall); return new AsyncClientStreamingCall<TRequest, TResponse>(requestStream, resultTask, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } - public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, CancellationToken token) + public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call) where TRequest : class where TResponse : class { - var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); - asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline)); - asyncCall.StartDuplexStreamingCall(call.Headers, call.Deadline); - RegisterCancellationCallback(asyncCall, token); + var asyncCall = new AsyncCall<TRequest, TResponse>(call); + asyncCall.StartDuplexStreamingCall(); var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall); var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall); return new AsyncDuplexStreamingCall<TRequest, TResponse>(requestStream, responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } - - private static void RegisterCancellationCallback<TRequest, TResponse>(AsyncCall<TRequest, TResponse> asyncCall, CancellationToken token) - { - if (token.CanBeCanceled) - { - token.Register(() => asyncCall.Cancel()); - } - } } } diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs index 0b69610443..9273ea4582 100644 --- a/src/csharp/Grpc.Core/Channel.cs +++ b/src/csharp/Grpc.Core/Channel.cs @@ -178,22 +178,6 @@ namespace Grpc.Core } } - internal CompletionQueueSafeHandle CompletionQueue - { - get - { - return this.environment.CompletionQueue; - } - } - - internal CompletionRegistry CompletionRegistry - { - get - { - return this.environment.CompletionRegistry; - } - } - internal GrpcEnvironment Environment { get diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs index f70408dae7..1e0f90287a 100644 --- a/src/csharp/Grpc.Core/ChannelOptions.cs +++ b/src/csharp/Grpc.Core/ChannelOptions.cs @@ -30,7 +30,6 @@ #endregion using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs index fd3473128a..88494bb4ac 100644 --- a/src/csharp/Grpc.Core/ClientBase.cs +++ b/src/csharp/Grpc.Core/ClientBase.cs @@ -76,19 +76,17 @@ namespace Grpc.Core /// <summary> /// Creates a new call to given method. /// </summary> - protected Call<TRequest, TResponse> CreateCall<TRequest, TResponse>(string serviceName, Method<TRequest, TResponse> method, Metadata metadata, DateTime? deadline) + protected CallInvocationDetails<TRequest, TResponse> CreateCall<TRequest, TResponse>(Method<TRequest, TResponse> method, CallOptions options) where TRequest : class where TResponse : class { var interceptor = HeaderInterceptor; if (interceptor != null) { - metadata = metadata ?? new Metadata(); - interceptor(metadata); - metadata.Freeze(); + interceptor(options.Headers); + options.Headers.Freeze(); } - return new Call<TRequest, TResponse>(serviceName, method, channel, - metadata ?? Metadata.Empty, deadline ?? DateTime.MaxValue); + return new CallInvocationDetails<TRequest, TResponse>(channel, method, options); } } } diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 641b54baba..52defd1965 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -44,9 +44,6 @@ <Reference Include="System.Interactive.Async"> <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath> </Reference> - <Reference Include="System.Collections.Immutable"> - <HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath> - </Reference> </ItemGroup> <ItemGroup> <Compile Include="AsyncDuplexStreamingCall.cs" /> @@ -55,11 +52,11 @@ <Compile Include="IServerStreamWriter.cs" /> <Compile Include="IAsyncStreamWriter.cs" /> <Compile Include="IAsyncStreamReader.cs" /> + <Compile Include="ServerPort.cs" /> <Compile Include="Version.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="RpcException.cs" /> <Compile Include="Calls.cs" /> - <Compile Include="Call.cs" /> <Compile Include="AsyncClientStreamingCall.cs" /> <Compile Include="GrpcEnvironment.cs" /> <Compile Include="Status.cs" /> @@ -116,6 +113,8 @@ <Compile Include="Logging\ConsoleLogger.cs" /> <Compile Include="Internal\NativeLogRedirector.cs" /> <Compile Include="ChannelState.cs" /> + <Compile Include="CallInvocationDetails.cs" /> + <Compile Include="CallOptions.cs" /> </ItemGroup> <ItemGroup> <None Include="Grpc.Core.nuspec" /> @@ -146,7 +145,5 @@ </Target> <Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" /> <Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" /> - <ItemGroup> - <Folder Include="Logging\" /> - </ItemGroup> + <ItemGroup /> </Project>
\ No newline at end of file diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec index 086776f69d..fe49efc7ec 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.nuspec +++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec @@ -15,7 +15,6 @@ <copyright>Copyright 2015, Google Inc.</copyright> <tags>gRPC RPC Protocol HTTP/2</tags> <dependencies> - <dependency id="System.Collections.Immutable" version="1.1.36" /> <dependency id="Ix-Async" version="1.2.3" /> <dependency id="grpc.native.csharp_ext" version="$GrpcNativeCsharpExtVersion$" /> </dependencies> diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index 48f466460f..414b5c4282 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -50,7 +50,7 @@ namespace Grpc.Core.Internal { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCall<TRequest, TResponse>>(); - Channel channel; + readonly CallInvocationDetails<TRequest, TResponse> callDetails; // Completion of a pending unary response if not null. TaskCompletionSource<TResponse> unaryResponseTcs; @@ -60,26 +60,18 @@ namespace Grpc.Core.Internal bool readObserverCompleted; // True if readObserver has already been completed. - public AsyncCall(Func<TRequest, byte[]> serializer, Func<byte[], TResponse> deserializer) : base(serializer, deserializer) + public AsyncCall(CallInvocationDetails<TRequest, TResponse> callDetails) + : base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer) { - } - - public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName, Timespec deadline) - { - this.channel = channel; - var call = channel.Handle.CreateCall(channel.CompletionRegistry, cq, methodName, null, deadline); - channel.Environment.DebugStats.ActiveClientCalls.Increment(); - InitializeInternal(call); + this.callDetails = callDetails; } // TODO: this method is not Async, so it shouldn't be in AsyncCall class, but // it is reusing fair amount of code in this class, so we are leaving it here. - // TODO: for other calls, you need to call Initialize, this methods calls initialize - // on its own, so there's a usage inconsistency. /// <summary> /// Blocking unary request - unary response call. /// </summary> - public TResponse UnaryCall(Channel channel, string methodName, TRequest msg, Metadata headers, DateTime deadline) + public TResponse UnaryCall(TRequest msg) { using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create()) { @@ -89,13 +81,15 @@ namespace Grpc.Core.Internal lock (myLock) { - Initialize(channel, cq, methodName, Timespec.FromDateTime(deadline)); + Preconditions.CheckState(!started); started = true; + Initialize(cq); + halfcloseRequested = true; readingDone = true; } - using (var metadataArray = MetadataArraySafeHandle.Create(headers)) + using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers)) { using (var ctx = BatchContextSafeHandle.Create()) { @@ -129,20 +123,22 @@ namespace Grpc.Core.Internal /// <summary> /// Starts a unary request - unary response call. /// </summary> - public Task<TResponse> UnaryCallAsync(TRequest msg, Metadata headers, DateTime deadline) + public Task<TResponse> UnaryCallAsync(TRequest msg) { lock (myLock) { - Preconditions.CheckNotNull(call); - + Preconditions.CheckState(!started); started = true; + + Initialize(callDetails.Channel.Environment.CompletionQueue); + halfcloseRequested = true; readingDone = true; byte[] payload = UnsafeSerialize(msg); unaryResponseTcs = new TaskCompletionSource<TResponse>(); - using (var metadataArray = MetadataArraySafeHandle.Create(headers)) + using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers)) { call.StartUnary(payload, HandleUnaryResponse, metadataArray); } @@ -154,17 +150,19 @@ namespace Grpc.Core.Internal /// Starts a streamed request - unary response call. /// Use StartSendMessage and StartSendCloseFromClient to stream requests. /// </summary> - public Task<TResponse> ClientStreamingCallAsync(Metadata headers, DateTime deadline) + public Task<TResponse> ClientStreamingCallAsync() { lock (myLock) { - Preconditions.CheckNotNull(call); - + Preconditions.CheckState(!started); started = true; + + Initialize(callDetails.Channel.Environment.CompletionQueue); + readingDone = true; unaryResponseTcs = new TaskCompletionSource<TResponse>(); - using (var metadataArray = MetadataArraySafeHandle.Create(headers)) + using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers)) { call.StartClientStreaming(HandleUnaryResponse, metadataArray); } @@ -176,19 +174,21 @@ namespace Grpc.Core.Internal /// <summary> /// Starts a unary request - streamed response call. /// </summary> - public void StartServerStreamingCall(TRequest msg, Metadata headers, DateTime deadline) + public void StartServerStreamingCall(TRequest msg) { lock (myLock) { - Preconditions.CheckNotNull(call); - + Preconditions.CheckState(!started); started = true; + + Initialize(callDetails.Channel.Environment.CompletionQueue); + halfcloseRequested = true; halfclosed = true; // halfclose not confirmed yet, but it will be once finishedHandler is called. byte[] payload = UnsafeSerialize(msg); - using (var metadataArray = MetadataArraySafeHandle.Create(headers)) + using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers)) { call.StartServerStreaming(payload, HandleFinished, metadataArray); } @@ -199,15 +199,16 @@ namespace Grpc.Core.Internal /// Starts a streaming request - streaming response call. /// Use StartSendMessage and StartSendCloseFromClient to stream requests. /// </summary> - public void StartDuplexStreamingCall(Metadata headers, DateTime deadline) + public void StartDuplexStreamingCall() { lock (myLock) { - Preconditions.CheckNotNull(call); - + Preconditions.CheckState(!started); started = true; - using (var metadataArray = MetadataArraySafeHandle.Create(headers)) + Initialize(callDetails.Channel.Environment.CompletionQueue); + + using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers)) { call.StartDuplexStreaming(HandleFinished, metadataArray); } @@ -309,7 +310,26 @@ namespace Grpc.Core.Internal protected override void OnReleaseResources() { - channel.Environment.DebugStats.ActiveClientCalls.Decrement(); + callDetails.Channel.Environment.DebugStats.ActiveClientCalls.Decrement(); + } + + private void Initialize(CompletionQueueSafeHandle cq) + { + var call = callDetails.Channel.Handle.CreateCall(callDetails.Channel.Environment.CompletionRegistry, cq, + callDetails.Method, callDetails.Host, Timespec.FromDateTime(callDetails.Options.Deadline)); + callDetails.Channel.Environment.DebugStats.ActiveClientCalls.Increment(); + InitializeInternal(call); + RegisterCancellationCallback(); + } + + // Make sure that once cancellationToken for this call is cancelled, Cancel() will be called. + private void RegisterCancellationCallback() + { + var token = callDetails.Options.CancellationToken; + if (token.CanBeCanceled) + { + token.Register(() => this.Cancel()); + } } /// <summary> diff --git a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs index 59238a452c..37a4f5256b 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs @@ -42,7 +42,7 @@ namespace Grpc.Core.Internal internal class ServerCredentialsSafeHandle : SafeHandleZeroIsInvalid { [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)] - static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs); + static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, bool forceClientAuth); [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_server_credentials_release(IntPtr credentials); @@ -51,12 +51,13 @@ namespace Grpc.Core.Internal { } - public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray) + public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, bool forceClientAuth) { Preconditions.CheckArgument(keyCertPairCertChainArray.Length == keyCertPairPrivateKeyArray.Length); return grpcsharp_ssl_server_credentials_create(pemRootCerts, keyCertPairCertChainArray, keyCertPairPrivateKeyArray, - new UIntPtr((ulong)keyCertPairCertChainArray.Length)); + new UIntPtr((ulong)keyCertPairCertChainArray.Length), + forceClientAuth); } protected override bool ReleaseHandle() diff --git a/src/csharp/Grpc.Core/KeyCertificatePair.cs b/src/csharp/Grpc.Core/KeyCertificatePair.cs index 7cea18618e..5def15a656 100644 --- a/src/csharp/Grpc.Core/KeyCertificatePair.cs +++ b/src/csharp/Grpc.Core/KeyCertificatePair.cs @@ -33,7 +33,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using Grpc.Core.Internal; using Grpc.Core.Utils; diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs index 2f308cbb11..6fd0a7109d 100644 --- a/src/csharp/Grpc.Core/Metadata.cs +++ b/src/csharp/Grpc.Core/Metadata.cs @@ -32,7 +32,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Collections.Immutable; using System.Collections.Specialized; using System.Runtime.InteropServices; using System.Text; diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs index 77d36191c3..cc047ac9f8 100644 --- a/src/csharp/Grpc.Core/Method.cs +++ b/src/csharp/Grpc.Core/Method.cs @@ -53,16 +53,20 @@ namespace Grpc.Core public class Method<TRequest, TResponse> { readonly MethodType type; + readonly string serviceName; readonly string name; readonly Marshaller<TRequest> requestMarshaller; readonly Marshaller<TResponse> responseMarshaller; + readonly string fullName; - public Method(MethodType type, string name, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller) + public Method(MethodType type, string serviceName, string name, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller) { this.type = type; - this.name = name; - this.requestMarshaller = requestMarshaller; - this.responseMarshaller = responseMarshaller; + this.serviceName = Preconditions.CheckNotNull(serviceName); + this.name = Preconditions.CheckNotNull(name); + this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller); + this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller); + this.fullName = GetFullName(serviceName); } public MethodType Type @@ -72,6 +76,14 @@ namespace Grpc.Core return this.type; } } + + public string ServiceName + { + get + { + return this.serviceName; + } + } public string Name { @@ -97,6 +109,14 @@ namespace Grpc.Core } } + public string FullName + { + get + { + return this.fullName; + } + } + /// <summary> /// Gets full name of the method including the service name. /// </summary> diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs index 3217547cc4..eb5b043d1c 100644 --- a/src/csharp/Grpc.Core/Server.cs +++ b/src/csharp/Grpc.Core/Server.cs @@ -32,7 +32,7 @@ #endregion using System; -using System.Collections.Concurrent; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; @@ -48,18 +48,17 @@ namespace Grpc.Core /// </summary> public class Server { - /// <summary> - /// Pass this value as port to have the server choose an unused listening port for you. - /// </summary> - public const int PickUnusedPort = 0; - static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<Server>(); + readonly ServiceDefinitionCollection serviceDefinitions; + readonly ServerPortCollection ports; readonly GrpcEnvironment environment; readonly List<ChannelOption> options; readonly ServerSafeHandle handle; readonly object myLock = new object(); + readonly List<ServerServiceDefinition> serviceDefinitionsList = new List<ServerServiceDefinition>(); + readonly List<ServerPort> serverPortList = new List<ServerPort>(); readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>(); readonly TaskCompletionSource<object> shutdownTcs = new TaskCompletionSource<object>(); @@ -72,6 +71,8 @@ namespace Grpc.Core /// <param name="options">Channel options.</param> public Server(IEnumerable<ChannelOption> options = null) { + this.serviceDefinitions = new ServiceDefinitionCollection(this); + this.ports = new ServerPortCollection(this); this.environment = GrpcEnvironment.GetInstance(); this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>(); using (var channelArgs = ChannelOptions.CreateChannelArgs(this.options)) @@ -81,47 +82,26 @@ namespace Grpc.Core } /// <summary> - /// Adds a service definition to the server. This is how you register - /// handlers for a service with the server. - /// Only call this before Start(). + /// Services that will be exported by the server once started. Register a service with this + /// server by adding its definition to this collection. /// </summary> - public void AddServiceDefinition(ServerServiceDefinition serviceDefinition) + public ServiceDefinitionCollection Services { - lock (myLock) + get { - Preconditions.CheckState(!startRequested); - foreach (var entry in serviceDefinition.CallHandlers) - { - callHandlers.Add(entry.Key, entry.Value); - } + return serviceDefinitions; } } /// <summary> - /// Add a port on which server should listen. - /// Only call this before Start(). + /// Ports on which the server will listen once started. Register a port with this + /// server by adding its definition to this collection. /// </summary> - /// <returns>The port on which server will be listening.</returns> - /// <param name="host">the host</param> - /// <param name="port">the port. If zero, an unused port is chosen automatically.</param> - public int AddPort(string host, int port, ServerCredentials credentials) + public ServerPortCollection Ports { - lock (myLock) + get { - Preconditions.CheckNotNull(credentials); - Preconditions.CheckState(!startRequested); - var address = string.Format("{0}:{1}", host, port); - using (var nativeCredentials = credentials.ToNativeCredentials()) - { - if (nativeCredentials != null) - { - return handle.AddSecurePort(address, nativeCredentials); - } - else - { - return handle.AddInsecurePort(address); - } - } + return ports; } } @@ -190,6 +170,50 @@ namespace Grpc.Core } /// <summary> + /// Adds a service definition. + /// </summary> + private void AddServiceDefinitionInternal(ServerServiceDefinition serviceDefinition) + { + lock (myLock) + { + Preconditions.CheckState(!startRequested); + foreach (var entry in serviceDefinition.CallHandlers) + { + callHandlers.Add(entry.Key, entry.Value); + } + serviceDefinitionsList.Add(serviceDefinition); + } + } + + /// <summary> + /// Adds a listening port. + /// </summary> + private int AddPortInternal(ServerPort serverPort) + { + lock (myLock) + { + Preconditions.CheckNotNull(serverPort.Credentials); + Preconditions.CheckState(!startRequested); + var address = string.Format("{0}:{1}", serverPort.Host, serverPort.Port); + int boundPort; + using (var nativeCredentials = serverPort.Credentials.ToNativeCredentials()) + { + if (nativeCredentials != null) + { + boundPort = handle.AddSecurePort(address, nativeCredentials); + } + else + { + boundPort = handle.AddInsecurePort(address); + } + } + var newServerPort = new ServerPort(serverPort, boundPort); + this.serverPortList.Add(newServerPort); + return boundPort; + } + } + + /// <summary> /// Allows one new RPC call to be received by server. /// </summary> private void AllowOneRpc() @@ -249,5 +273,82 @@ namespace Grpc.Core { shutdownTcs.SetResult(null); } + + /// <summary> + /// Collection of service definitions. + /// </summary> + public class ServiceDefinitionCollection : IEnumerable<ServerServiceDefinition> + { + readonly Server server; + + internal ServiceDefinitionCollection(Server server) + { + this.server = server; + } + + /// <summary> + /// Adds a service definition to the server. This is how you register + /// handlers for a service with the server. Only call this before Start(). + /// </summary> + public void Add(ServerServiceDefinition serviceDefinition) + { + server.AddServiceDefinitionInternal(serviceDefinition); + } + + public IEnumerator<ServerServiceDefinition> GetEnumerator() + { + return server.serviceDefinitionsList.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return server.serviceDefinitionsList.GetEnumerator(); + } + } + + /// <summary> + /// Collection of server ports. + /// </summary> + public class ServerPortCollection : IEnumerable<ServerPort> + { + readonly Server server; + + internal ServerPortCollection(Server server) + { + this.server = server; + } + + /// <summary> + /// Adds a new port on which server should listen. + /// Only call this before Start(). + /// <returns>The port on which server will be listening.</returns> + /// </summary> + public int Add(ServerPort serverPort) + { + return server.AddPortInternal(serverPort); + } + + /// <summary> + /// Adds a new port on which server should listen. + /// <returns>The port on which server will be listening.</returns> + /// </summary> + /// <param name="host">the host</param> + /// <param name="port">the port. If zero, an unused port is chosen automatically.</param> + /// <param name="credentials">credentials to use to secure this port.</param> + public int Add(string host, int port, ServerCredentials credentials) + { + return Add(new ServerPort(host, port, credentials)); + } + + public IEnumerator<ServerPort> GetEnumerator() + { + return server.serverPortList.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return server.serverPortList.GetEnumerator(); + } + } } } diff --git a/src/csharp/Grpc.Core/ServerCallContext.cs b/src/csharp/Grpc.Core/ServerCallContext.cs index 0c48adaea5..032b1390db 100644 --- a/src/csharp/Grpc.Core/ServerCallContext.cs +++ b/src/csharp/Grpc.Core/ServerCallContext.cs @@ -65,7 +65,7 @@ namespace Grpc.Core this.cancellationToken = cancellationToken; } - /// <summary> Name of method called in this RPC. </summary> + /// <summary>Name of method called in this RPC.</summary> public string Method { get @@ -74,7 +74,7 @@ namespace Grpc.Core } } - /// <summary> Name of host called in this RPC. </summary> + /// <summary>Name of host called in this RPC.</summary> public string Host { get @@ -83,7 +83,7 @@ namespace Grpc.Core } } - /// <summary> Address of the remote endpoint in URI format. </summary> + /// <summary>Address of the remote endpoint in URI format.</summary> public string Peer { get @@ -92,7 +92,7 @@ namespace Grpc.Core } } - /// <summary> Deadline for this RPC. </summary> + /// <summary>Deadline for this RPC.</summary> public DateTime Deadline { get @@ -101,7 +101,7 @@ namespace Grpc.Core } } - /// <summary> Initial metadata sent by client. </summary> + /// <summary>Initial metadata sent by client.</summary> public Metadata RequestHeaders { get @@ -110,8 +110,7 @@ namespace Grpc.Core } } - // TODO(jtattermusch): support signalling cancellation. - /// <summary> Cancellation token signals when call is cancelled. </summary> + ///<summary>Cancellation token signals when call is cancelled.</summary> public CancellationToken CancellationToken { get @@ -120,7 +119,7 @@ namespace Grpc.Core } } - /// <summary> Trailers to send back to client after RPC finishes.</summary> + /// <summary>Trailers to send back to client after RPC finishes.</summary> public Metadata ResponseTrailers { get diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs index 32ed4b78a1..c11a1ede08 100644 --- a/src/csharp/Grpc.Core/ServerCredentials.cs +++ b/src/csharp/Grpc.Core/ServerCredentials.cs @@ -33,7 +33,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using Grpc.Core.Internal; using Grpc.Core.Utils; @@ -80,18 +79,26 @@ namespace Grpc.Core { readonly IList<KeyCertificatePair> keyCertificatePairs; readonly string rootCertificates; + readonly bool forceClientAuth; /// <summary> /// Creates server-side SSL credentials. /// </summary> - /// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param> /// <param name="keyCertificatePairs">Key-certificates to use.</param> - public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates) + /// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param> + /// <param name="forceClientAuth">If true, client will be rejected unless it proves its unthenticity using against rootCertificates.</param> + public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates, bool forceClientAuth) { this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly(); Preconditions.CheckArgument(this.keyCertificatePairs.Count > 0, "At least one KeyCertificatePair needs to be provided"); + if (forceClientAuth) + { + Preconditions.CheckNotNull(rootCertificates, + "Cannot force client authentication unless you provide rootCertificates."); + } this.rootCertificates = rootCertificates; + this.forceClientAuth = forceClientAuth; } /// <summary> @@ -100,7 +107,7 @@ namespace Grpc.Core /// using client root certificates. /// </summary> /// <param name="keyCertificatePairs">Key-certificates to use.</param> - public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs) : this(keyCertificatePairs, null) + public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs) : this(keyCertificatePairs, null, false) { } @@ -126,6 +133,17 @@ namespace Grpc.Core } } + /// <summary> + /// If true, the authenticity of client check will be enforced. + /// </summary> + public bool ForceClientAuthentication + { + get + { + return this.forceClientAuth; + } + } + internal override ServerCredentialsSafeHandle ToNativeCredentials() { int count = keyCertificatePairs.Count; @@ -136,7 +154,7 @@ namespace Grpc.Core certChains[i] = keyCertificatePairs[i].CertificateChain; keys[i] = keyCertificatePairs[i].PrivateKey; } - return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys); + return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys, forceClientAuth); } } } diff --git a/src/csharp/Grpc.Core/ServerPort.cs b/src/csharp/Grpc.Core/ServerPort.cs new file mode 100644 index 0000000000..55e4bd0062 --- /dev/null +++ b/src/csharp/Grpc.Core/ServerPort.cs @@ -0,0 +1,120 @@ +#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.Utils; + +namespace Grpc.Core +{ + /// <summary> + /// A port exposed by a server. + /// </summary> + public class ServerPort + { + /// <summary> + /// Pass this value as port to have the server choose an unused listening port for you. + /// Ports added to a server will contain the bound port in their <see cref="BoundPort"/> property. + /// </summary> + public const int PickUnused = 0; + + readonly string host; + readonly int port; + readonly ServerCredentials credentials; + readonly int boundPort; + + /// <summary> + /// Creates a new port on which server should listen. + /// </summary> + /// <returns>The port on which server will be listening.</returns> + /// <param name="host">the host</param> + /// <param name="port">the port. If zero, an unused port is chosen automatically.</param> + /// <param name="credentials">credentials to use to secure this port.</param> + public ServerPort(string host, int port, ServerCredentials credentials) + { + this.host = Preconditions.CheckNotNull(host); + this.port = port; + this.credentials = Preconditions.CheckNotNull(credentials); + } + + /// <summary> + /// Creates a port from an existing <c>ServerPort</c> instance and boundPort value. + /// </summary> + internal ServerPort(ServerPort serverPort, int boundPort) + { + this.host = serverPort.host; + this.port = serverPort.port; + this.credentials = serverPort.credentials; + this.boundPort = boundPort; + } + + /// <value>The host.</value> + public string Host + { + get + { + return host; + } + } + + /// <value>The port.</value> + public int Port + { + get + { + return port; + } + } + + /// <value>The server credentials.</value> + public ServerCredentials Credentials + { + get + { + return credentials; + } + } + + /// <value> + /// The port actually bound by the server. This is useful if you let server + /// pick port automatically. <see cref="PickUnused"/> + /// </value> + public int BoundPort + { + get + { + return boundPort; + } + } + } +} diff --git a/src/csharp/Grpc.Core/ServerServiceDefinition.cs b/src/csharp/Grpc.Core/ServerServiceDefinition.cs index b180186c12..a00d156e52 100644 --- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs +++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs @@ -33,7 +33,7 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; +using System.Collections.ObjectModel; using Grpc.Core.Internal; namespace Grpc.Core @@ -43,14 +43,14 @@ namespace Grpc.Core /// </summary> public class ServerServiceDefinition { - readonly ImmutableDictionary<string, IServerCallHandler> callHandlers; + readonly ReadOnlyDictionary<string, IServerCallHandler> callHandlers; - private ServerServiceDefinition(ImmutableDictionary<string, IServerCallHandler> callHandlers) + private ServerServiceDefinition(Dictionary<string, IServerCallHandler> callHandlers) { - this.callHandlers = callHandlers; + this.callHandlers = new ReadOnlyDictionary<string, IServerCallHandler>(callHandlers); } - internal ImmutableDictionary<string, IServerCallHandler> CallHandlers + internal IDictionary<string, IServerCallHandler> CallHandlers { get { @@ -115,7 +115,7 @@ namespace Grpc.Core public ServerServiceDefinition Build() { - return new ServerServiceDefinition(callHandlers.ToImmutableDictionary()); + return new ServerServiceDefinition(callHandlers); } } } diff --git a/src/csharp/Grpc.Core/packages.config b/src/csharp/Grpc.Core/packages.config index 6cdcdf2656..9b12b9b096 100644 --- a/src/csharp/Grpc.Core/packages.config +++ b/src/csharp/Grpc.Core/packages.config @@ -3,5 +3,4 @@ <package id="grpc.dependencies.openssl.redist" version="1.0.2.2" targetFramework="net45" /> <package id="grpc.dependencies.zlib.redist" version="1.2.8.9" targetFramework="net45" /> <package id="Ix-Async" version="1.2.3" targetFramework="net45" /> - <package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" /> </packages>
\ No newline at end of file diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs index 468eefbe3e..5f7e717b0c 100644 --- a/src/csharp/Grpc.Examples.MathServer/MathServer.cs +++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs @@ -38,16 +38,19 @@ namespace math { class MainClass { + const string Host = "0.0.0.0"; + const int Port = 23456; + public static void Main(string[] args) { - string host = "0.0.0.0"; - - Server server = new Server(); - server.AddServiceDefinition(Math.BindService(new MathServiceImpl())); - int port = server.AddPort(host, 23456, ServerCredentials.Insecure); + Server server = new Server + { + Services = { Math.BindService(new MathServiceImpl()) }, + Ports = { { Host, Port, ServerCredentials.Insecure } } + }; server.Start(); - Console.WriteLine("MathServer listening on port " + port); + Console.WriteLine("MathServer listening on port " + Port); Console.WriteLine("Press any key to stop the server..."); Console.ReadKey(); diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index 242d29a9a5..08aece7ef2 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -33,6 +33,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core; @@ -46,7 +47,7 @@ namespace math.Tests /// </summary> public class MathClientServerTest { - string host = "localhost"; + const string Host = "localhost"; Server server; Channel channel; Math.MathClient client; @@ -54,19 +55,14 @@ namespace math.Tests [TestFixtureSetUp] public void Init() { - server = new Server(); - server.AddServiceDefinition(Math.BindService(new MathServiceImpl())); - int port = server.AddPort(host, Server.PickUnusedPort, ServerCredentials.Insecure); - server.Start(); - channel = new Channel(host, port, Credentials.Insecure); - client = Math.NewClient(channel); - - // TODO(jtattermusch): get rid of the custom header here once we have dedicated tests - // for header support. - client.HeaderInterceptor = (metadata) => + server = new Server { - metadata.Add(new Metadata.Entry("custom-header", "abcdef")); + Services = { Math.BindService(new MathServiceImpl()) }, + Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } }; + server.Start(); + channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure); + client = Math.NewClient(channel); } [TestFixtureTearDown] diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs index 67827e7b4f..4941ff35f7 100644 --- a/src/csharp/Grpc.Examples/MathGrpc.cs +++ b/src/csharp/Grpc.Examples/MathGrpc.cs @@ -19,24 +19,28 @@ namespace math { static readonly Method<global::math.DivArgs, global::math.DivReply> __Method_Div = new Method<global::math.DivArgs, global::math.DivReply>( MethodType.Unary, + __ServiceName, "Div", __Marshaller_DivArgs, __Marshaller_DivReply); static readonly Method<global::math.DivArgs, global::math.DivReply> __Method_DivMany = new Method<global::math.DivArgs, global::math.DivReply>( MethodType.DuplexStreaming, + __ServiceName, "DivMany", __Marshaller_DivArgs, __Marshaller_DivReply); static readonly Method<global::math.FibArgs, global::math.Num> __Method_Fib = new Method<global::math.FibArgs, global::math.Num>( MethodType.ServerStreaming, + __ServiceName, "Fib", __Marshaller_FibArgs, __Marshaller_Num); static readonly Method<global::math.Num, global::math.Num> __Method_Sum = new Method<global::math.Num, global::math.Num>( MethodType.ClientStreaming, + __ServiceName, "Sum", __Marshaller_Num, __Marshaller_Num); @@ -45,10 +49,15 @@ namespace math { public interface IMathClient { global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + global::math.DivReply Div(global::math.DivArgs request, CallOptions options); AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, CallOptions options); AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(CallOptions options); AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, CallOptions options); AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(CallOptions options); } // server-side interface @@ -68,28 +77,53 @@ namespace math { } public global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Div, headers, deadline); - return Calls.BlockingUnaryCall(call, request, cancellationToken); + var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken)); + return Calls.BlockingUnaryCall(call, request); + } + public global::math.DivReply Div(global::math.DivArgs request, CallOptions options) + { + var call = CreateCall(__Method_Div, options); + return Calls.BlockingUnaryCall(call, request); } public AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Div, headers, deadline); - return Calls.AsyncUnaryCall(call, request, cancellationToken); + var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncUnaryCall(call, request); + } + public AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, CallOptions options) + { + var call = CreateCall(__Method_Div, options); + return Calls.AsyncUnaryCall(call, request); } public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_DivMany, headers, deadline); - return Calls.AsyncDuplexStreamingCall(call, cancellationToken); + var call = CreateCall(__Method_DivMany, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncDuplexStreamingCall(call); + } + public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(CallOptions options) + { + var call = CreateCall(__Method_DivMany, options); + return Calls.AsyncDuplexStreamingCall(call); } public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Fib, headers, deadline); - return Calls.AsyncServerStreamingCall(call, request, cancellationToken); + var call = CreateCall(__Method_Fib, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncServerStreamingCall(call, request); + } + public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, CallOptions options) + { + var call = CreateCall(__Method_Fib, options); + return Calls.AsyncServerStreamingCall(call, request); } public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Sum, headers, deadline); - return Calls.AsyncClientStreamingCall(call, cancellationToken); + var call = CreateCall(__Method_Sum, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncClientStreamingCall(call); + } + public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(CallOptions options) + { + var call = CreateCall(__Method_Sum, options); + return Calls.AsyncClientStreamingCall(call); } } diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs index 9d89698a8f..024377e216 100644 --- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs +++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs @@ -57,11 +57,13 @@ namespace Grpc.HealthCheck.Tests { serviceImpl = new HealthServiceImpl(); - server = new Server(); - server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl)); - int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure); + server = new Server + { + Services = { Grpc.Health.V1Alpha.Health.BindService(serviceImpl) }, + Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } + }; server.Start(); - channel = new Channel(Host, port, Credentials.Insecure); + channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure); client = Grpc.Health.V1Alpha.Health.NewClient(channel); } diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs index 892cdb3f04..0dabc91f7c 100644 --- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs +++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs @@ -17,6 +17,7 @@ namespace Grpc.Health.V1Alpha { static readonly Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse> __Method_Check = new Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse>( MethodType.Unary, + __ServiceName, "Check", __Marshaller_HealthCheckRequest, __Marshaller_HealthCheckResponse); @@ -25,7 +26,9 @@ namespace Grpc.Health.V1Alpha { public interface IHealthClient { global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options); AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options); } // server-side interface @@ -42,13 +45,23 @@ namespace Grpc.Health.V1Alpha { } public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Check, headers, deadline); - return Calls.BlockingUnaryCall(call, request, cancellationToken); + var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken)); + return Calls.BlockingUnaryCall(call, request); + } + public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options) + { + var call = CreateCall(__Method_Check, options); + return Calls.BlockingUnaryCall(call, request); } public AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Check, headers, deadline); - return Calls.AsyncUnaryCall(call, request, cancellationToken); + var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncUnaryCall(call, request); + } + public AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options) + { + var call = CreateCall(__Method_Check, options); + return Calls.AsyncUnaryCall(call, request); } } diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index abc27f811e..06a75a3351 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -87,9 +87,6 @@ <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop"> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath> </Reference> - <Reference Include="System.Collections.Immutable"> - <HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath> - </Reference> </ItemGroup> <ItemGroup> <Compile Include="..\Grpc.Core\Version.cs"> diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs index 2756ce97aa..6fa721bc1c 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs @@ -33,6 +33,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using grpc.testing; @@ -47,7 +48,7 @@ namespace Grpc.IntegrationTesting /// </summary> public class InteropClientServerTest { - string host = "localhost"; + const string Host = "localhost"; Server server; Channel channel; TestService.ITestServiceClient client; @@ -55,16 +56,19 @@ namespace Grpc.IntegrationTesting [TestFixtureSetUp] public void Init() { - server = new Server(); - server.AddServiceDefinition(TestService.BindService(new TestServiceImpl())); - int port = server.AddPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials()); + server = new Server + { + Services = { TestService.BindService(new TestServiceImpl()) }, + Ports = { { Host, ServerPort.PickUnused, TestCredentials.CreateTestServerCredentials() } } + }; server.Start(); var options = new List<ChannelOption> { new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride) }; - channel = new Channel(host, port, TestCredentials.CreateTestClientCredentials(true), options); + int port = server.Ports.Single().BoundPort; + channel = new Channel(Host, port, TestCredentials.CreateTestClientCredentials(true), options); client = TestService.NewClient(channel); } diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs index bf6947e09d..504fd11857 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs @@ -88,18 +88,20 @@ namespace Grpc.IntegrationTesting private void Run() { - var server = new Server(); - server.AddServiceDefinition(TestService.BindService(new TestServiceImpl())); + var server = new Server + { + Services = { TestService.BindService(new TestServiceImpl()) } + }; string host = "0.0.0.0"; int port = options.port.Value; if (options.useTls) { - server.AddPort(host, port, TestCredentials.CreateTestServerCredentials()); + server.Ports.Add(host, port, TestCredentials.CreateTestServerCredentials()); } else { - server.AddPort(host, options.port.Value, ServerCredentials.Insecure); + server.Ports.Add(host, options.port.Value, ServerCredentials.Insecure); } Console.WriteLine("Running server on " + string.Format("{0}:{1}", host, port)); server.Start(); diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs index 1baf40eea2..1c398eb84e 100644 --- a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs @@ -34,6 +34,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; using grpc.testing; @@ -49,7 +50,7 @@ namespace Grpc.IntegrationTesting /// </summary> public class SslCredentialsTest { - string host = "localhost"; + const string Host = "localhost"; Server server; Channel channel; TestService.ITestServiceClient client; @@ -62,12 +63,14 @@ namespace Grpc.IntegrationTesting File.ReadAllText(TestCredentials.ServerCertChainPath), File.ReadAllText(TestCredentials.ServerPrivateKeyPath)); - var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert); + var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert, true); var clientCredentials = new SslCredentials(rootCert, keyCertPair); - server = new Server(); - server.AddServiceDefinition(TestService.BindService(new TestServiceImpl())); - int port = server.AddPort(host, Server.PickUnusedPort, serverCredentials); + server = new Server + { + Services = { TestService.BindService(new TestServiceImpl()) }, + Ports = { { Host, ServerPort.PickUnused, serverCredentials } } + }; server.Start(); var options = new List<ChannelOption> @@ -75,7 +78,7 @@ namespace Grpc.IntegrationTesting new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride) }; - channel = new Channel(host, port, clientCredentials, options); + channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options); client = TestService.NewClient(channel); } diff --git a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs index 54d8587713..da0b7fb910 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs @@ -33,7 +33,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Text.RegularExpressions; diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs index ddcd0c2958..697acb53d8 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs @@ -22,36 +22,42 @@ namespace grpc.testing { static readonly Method<global::grpc.testing.Empty, global::grpc.testing.Empty> __Method_EmptyCall = new Method<global::grpc.testing.Empty, global::grpc.testing.Empty>( MethodType.Unary, + __ServiceName, "EmptyCall", __Marshaller_Empty, __Marshaller_Empty); static readonly Method<global::grpc.testing.SimpleRequest, global::grpc.testing.SimpleResponse> __Method_UnaryCall = new Method<global::grpc.testing.SimpleRequest, global::grpc.testing.SimpleResponse>( MethodType.Unary, + __ServiceName, "UnaryCall", __Marshaller_SimpleRequest, __Marshaller_SimpleResponse); static readonly Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> __Method_StreamingOutputCall = new Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse>( MethodType.ServerStreaming, + __ServiceName, "StreamingOutputCall", __Marshaller_StreamingOutputCallRequest, __Marshaller_StreamingOutputCallResponse); static readonly Method<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> __Method_StreamingInputCall = new Method<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse>( MethodType.ClientStreaming, + __ServiceName, "StreamingInputCall", __Marshaller_StreamingInputCallRequest, __Marshaller_StreamingInputCallResponse); static readonly Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> __Method_FullDuplexCall = new Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse>( MethodType.DuplexStreaming, + __ServiceName, "FullDuplexCall", __Marshaller_StreamingOutputCallRequest, __Marshaller_StreamingOutputCallResponse); static readonly Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> __Method_HalfDuplexCall = new Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse>( MethodType.DuplexStreaming, + __ServiceName, "HalfDuplexCall", __Marshaller_StreamingOutputCallRequest, __Marshaller_StreamingOutputCallResponse); @@ -60,13 +66,21 @@ namespace grpc.testing { public interface ITestServiceClient { global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, CallOptions options); AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, CallOptions options); global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, CallOptions options); AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, CallOptions options); AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, CallOptions options); AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options); AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options); AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options); } // server-side interface @@ -88,43 +102,83 @@ namespace grpc.testing { } public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_EmptyCall, headers, deadline); - return Calls.BlockingUnaryCall(call, request, cancellationToken); + var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.BlockingUnaryCall(call, request); + } + public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, CallOptions options) + { + var call = CreateCall(__Method_EmptyCall, options); + return Calls.BlockingUnaryCall(call, request); } public AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_EmptyCall, headers, deadline); - return Calls.AsyncUnaryCall(call, request, cancellationToken); + var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncUnaryCall(call, request); + } + public AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, CallOptions options) + { + var call = CreateCall(__Method_EmptyCall, options); + return Calls.AsyncUnaryCall(call, request); } public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_UnaryCall, headers, deadline); - return Calls.BlockingUnaryCall(call, request, cancellationToken); + var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.BlockingUnaryCall(call, request); + } + public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, CallOptions options) + { + var call = CreateCall(__Method_UnaryCall, options); + return Calls.BlockingUnaryCall(call, request); } public AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_UnaryCall, headers, deadline); - return Calls.AsyncUnaryCall(call, request, cancellationToken); + var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncUnaryCall(call, request); + } + public AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, CallOptions options) + { + var call = CreateCall(__Method_UnaryCall, options); + return Calls.AsyncUnaryCall(call, request); } public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_StreamingOutputCall, headers, deadline); - return Calls.AsyncServerStreamingCall(call, request, cancellationToken); + var call = CreateCall(__Method_StreamingOutputCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncServerStreamingCall(call, request); + } + public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, CallOptions options) + { + var call = CreateCall(__Method_StreamingOutputCall, options); + return Calls.AsyncServerStreamingCall(call, request); } public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_StreamingInputCall, headers, deadline); - return Calls.AsyncClientStreamingCall(call, cancellationToken); + var call = CreateCall(__Method_StreamingInputCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncClientStreamingCall(call); + } + public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options) + { + var call = CreateCall(__Method_StreamingInputCall, options); + return Calls.AsyncClientStreamingCall(call); } public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_FullDuplexCall, headers, deadline); - return Calls.AsyncDuplexStreamingCall(call, cancellationToken); + var call = CreateCall(__Method_FullDuplexCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncDuplexStreamingCall(call); + } + public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options) + { + var call = CreateCall(__Method_FullDuplexCall, options); + return Calls.AsyncDuplexStreamingCall(call); } public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_HalfDuplexCall, headers, deadline); - return Calls.AsyncDuplexStreamingCall(call, cancellationToken); + var call = CreateCall(__Method_HalfDuplexCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncDuplexStreamingCall(call); + } + public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options) + { + var call = CreateCall(__Method_HalfDuplexCall, options); + return Calls.AsyncDuplexStreamingCall(call); } } diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config index 746133a7a5..7d1f84f303 100644 --- a/src/csharp/Grpc.IntegrationTesting/packages.config +++ b/src/csharp/Grpc.IntegrationTesting/packages.config @@ -11,5 +11,4 @@ <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" /> <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" /> <package id="NUnit" version="2.6.4" targetFramework="net45" /> - <package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" /> </packages>
\ No newline at end of file diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index a7be4077b8..048887bc12 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -379,7 +379,8 @@ GPR_EXPORT grpc_call *GPR_CALLTYPE grpcsharp_channel_create_call(grpc_channel *channel, grpc_completion_queue *cq, const char *method, const char *host, gpr_timespec deadline) { - return grpc_channel_create_call(channel, cq, method, host, deadline); + return grpc_channel_create_call(channel, NULL, GRPC_PROPAGATE_DEFAULTS, cq, + method, host, deadline); } GPR_EXPORT grpc_connectivity_state GPR_CALLTYPE @@ -792,7 +793,8 @@ grpcsharp_secure_channel_create(grpc_credentials *creds, const char *target, GPR_EXPORT grpc_server_credentials *GPR_CALLTYPE grpcsharp_ssl_server_credentials_create( const char *pem_root_certs, const char **key_cert_pair_cert_chain_array, - const char **key_cert_pair_private_key_array, size_t num_key_cert_pairs) { + const char **key_cert_pair_private_key_array, size_t num_key_cert_pairs, + int force_client_auth) { size_t i; grpc_server_credentials *creds; grpc_ssl_pem_key_cert_pair *key_cert_pairs = @@ -807,9 +809,9 @@ grpcsharp_ssl_server_credentials_create( key_cert_pairs[i].private_key = key_cert_pair_private_key_array[i]; } } - /* TODO: Add a force_client_auth parameter and pass it here. */ creds = grpc_ssl_server_credentials_create(pem_root_certs, key_cert_pairs, - num_key_cert_pairs, 0); + num_key_cert_pairs, + force_client_auth); gpr_free(key_cert_pairs); return creds; } |