Merge pull request #2872 from jtattermusch/fix_preconditions

C# code cleanup
pull/2895/head
Tim Emiola 10 years ago
commit 7493677632
  1. 6
      src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
  2. 2
      src/csharp/Grpc.Core.Tests/ChannelTest.cs
  3. 6
      src/csharp/Grpc.Core.Tests/ClientServerTest.cs
  4. 4
      src/csharp/Grpc.Core.Tests/CompressionTest.cs
  5. 31
      src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
  6. 12
      src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
  7. 4
      src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs
  8. 72
      src/csharp/Grpc.Core/CallInvocationDetails.cs
  9. 86
      src/csharp/Grpc.Core/CallOptions.cs
  10. 46
      src/csharp/Grpc.Core/Calls.cs
  11. 2
      src/csharp/Grpc.Core/Channel.cs
  12. 6
      src/csharp/Grpc.Core/ChannelOptions.cs
  13. 18
      src/csharp/Grpc.Core/ClientBase.cs
  14. 58
      src/csharp/Grpc.Core/ContextPropagationToken.cs
  15. 1
      src/csharp/Grpc.Core/Grpc.Core.csproj
  16. 20
      src/csharp/Grpc.Core/GrpcEnvironment.cs
  17. 17
      src/csharp/Grpc.Core/Internal/AsyncCall.cs
  18. 2
      src/csharp/Grpc.Core/Internal/Timespec.cs
  19. 4
      src/csharp/Grpc.Core/KeyCertificatePair.cs
  20. 11
      src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
  21. 6
      src/csharp/Grpc.Core/Logging/ILogger.cs
  22. 23
      src/csharp/Grpc.Core/Marshaller.cs
  23. 8
      src/csharp/Grpc.Core/Metadata.cs
  24. 58
      src/csharp/Grpc.Core/Method.cs
  25. 14
      src/csharp/Grpc.Core/RpcException.cs
  26. 2
      src/csharp/Grpc.Core/Server.cs
  27. 2
      src/csharp/Grpc.Core/ServerCredentials.cs
  28. 4
      src/csharp/Grpc.Core/ServerMethods.cs
  29. 4
      src/csharp/Grpc.Core/ServerPort.cs
  30. 8
      src/csharp/Grpc.Core/ServerServiceDefinition.cs
  31. 13
      src/csharp/Grpc.Core/Status.cs
  32. 156
      src/csharp/Grpc.Core/StatusCode.cs
  33. 9
      src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs
  34. 3
      src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
  35. 57
      src/csharp/Grpc.Core/Utils/ExceptionHelper.cs
  36. 25
      src/csharp/Grpc.Core/Utils/Preconditions.cs
  37. 34
      src/csharp/Grpc.Core/Version.cs
  38. 37
      src/csharp/Grpc.Core/VersionInfo.cs
  39. 10
      src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
  40. 10
      src/csharp/Grpc.Examples/MathExamples.cs
  41. 7
      src/csharp/Grpc.Examples/MathServiceImpl.cs
  42. 8
      src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
  43. 6
      src/csharp/Grpc.IntegrationTesting/InteropClient.cs
  44. 4
      src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs

@ -67,9 +67,9 @@ namespace Grpc.Core.Internal.Tests
[Test] [Test]
public void ConstructorPreconditions() public void ConstructorPreconditions()
{ {
Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption(null, "abc"); }); Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption(null, "abc"); });
Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption(null, 1); }); Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption(null, 1); });
Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption("abc", null); }); Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption("abc", null); });
} }
[Test] [Test]

@ -50,7 +50,7 @@ namespace Grpc.Core.Tests
[Test] [Test]
public void Constructor_RejectsInvalidParams() public void Constructor_RejectsInvalidParams()
{ {
Assert.Throws(typeof(NullReferenceException), () => new Channel(null, Credentials.Insecure)); Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, Credentials.Insecure));
} }
[Test] [Test]

@ -138,7 +138,7 @@ namespace Grpc.Core.Tests
helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) => helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
{ {
string result = ""; string result = "";
await requestStream.ForEach(async (request) => await requestStream.ForEachAsync(async (request) =>
{ {
result += request; result += request;
}); });
@ -147,7 +147,7 @@ namespace Grpc.Core.Tests
}); });
var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
await call.RequestStream.WriteAll(new string[] { "A", "B", "C" }); await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" });
Assert.AreEqual("ABC", await call.ResponseAsync); Assert.AreEqual("ABC", await call.ResponseAsync);
} }
@ -159,7 +159,7 @@ namespace Grpc.Core.Tests
helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) => helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
{ {
barrier.SetResult(null); barrier.SetResult(null);
await requestStream.ToList(); await requestStream.ToListAsync();
return ""; return "";
}); });

@ -90,7 +90,7 @@ namespace Grpc.Core.Tests
{ {
helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) => helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) =>
{ {
await requestStream.ToList(); await requestStream.ToListAsync();
context.WriteOptions = new WriteOptions(WriteFlags.NoCompress); context.WriteOptions = new WriteOptions(WriteFlags.NoCompress);
@ -122,7 +122,7 @@ namespace Grpc.Core.Tests
await call.RequestStream.CompleteAsync(); await call.RequestStream.CompleteAsync();
await call.ResponseStream.ToList(); await call.ResponseStream.ToListAsync();
} }
} }
} }

@ -110,6 +110,14 @@ namespace Grpc.Core.Tests
helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) => helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
{ {
Assert.Throws(typeof(ArgumentException), () =>
{
// Trying to override deadline while propagating deadline from parent call will throw.
Calls.BlockingUnaryCall(helper.CreateUnaryCall(
new CallOptions(deadline: DateTime.UtcNow.AddDays(8),
propagationToken: context.CreatePropagationToken())), "");
});
var callOptions = new CallOptions(propagationToken: context.CreatePropagationToken()); var callOptions = new CallOptions(propagationToken: context.CreatePropagationToken());
return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz"); return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz");
}); });
@ -118,5 +126,28 @@ namespace Grpc.Core.Tests
await call.RequestStream.CompleteAsync(); await call.RequestStream.CompleteAsync();
Assert.AreEqual("PASS", await call); Assert.AreEqual("PASS", await call);
} }
[Test]
public async Task SuppressDeadlinePropagation()
{
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
{
Assert.AreEqual(DateTime.MaxValue, context.Deadline);
return "PASS";
});
helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
{
Assert.IsTrue(context.CancellationToken.CanBeCanceled);
var callOptions = new CallOptions(propagationToken: context.CreatePropagationToken(new ContextPropagationOptions(propagateDeadline: false)));
return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz");
});
var cts = new CancellationTokenSource();
var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(deadline: DateTime.UtcNow.AddDays(7))));
await call.RequestStream.CompleteAsync();
Assert.AreEqual("PASS", await call);
}
} }
} }

@ -153,27 +153,23 @@ namespace Grpc.Core.Tests
return channel; return channel;
} }
public CallInvocationDetails<string, string> CreateUnaryCall(CallOptions options = null) public CallInvocationDetails<string, string> CreateUnaryCall(CallOptions options = default(CallOptions))
{ {
options = options ?? new CallOptions();
return new CallInvocationDetails<string, string>(channel, UnaryMethod, options); return new CallInvocationDetails<string, string>(channel, UnaryMethod, options);
} }
public CallInvocationDetails<string, string> CreateClientStreamingCall(CallOptions options = null) public CallInvocationDetails<string, string> CreateClientStreamingCall(CallOptions options = default(CallOptions))
{ {
options = options ?? new CallOptions();
return new CallInvocationDetails<string, string>(channel, ClientStreamingMethod, options); return new CallInvocationDetails<string, string>(channel, ClientStreamingMethod, options);
} }
public CallInvocationDetails<string, string> CreateServerStreamingCall(CallOptions options = null) public CallInvocationDetails<string, string> CreateServerStreamingCall(CallOptions options = default(CallOptions))
{ {
options = options ?? new CallOptions();
return new CallInvocationDetails<string, string>(channel, ServerStreamingMethod, options); return new CallInvocationDetails<string, string>(channel, ServerStreamingMethod, options);
} }
public CallInvocationDetails<string, string> CreateDuplexStreamingCall(CallOptions options = null) public CallInvocationDetails<string, string> CreateDuplexStreamingCall(CallOptions options = default(CallOptions))
{ {
options = options ?? new CallOptions();
return new CallInvocationDetails<string, string>(channel, DuplexStreamingMethod, options); return new CallInvocationDetails<string, string>(channel, DuplexStreamingMethod, options);
} }

@ -84,7 +84,7 @@ namespace Grpc.Core.Tests
{ {
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) => helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
{ {
Assert.Throws(typeof(NullReferenceException), async () => await context.WriteResponseHeadersAsync(null)); Assert.Throws(typeof(ArgumentNullException), async () => await context.WriteResponseHeadersAsync(null));
return "PASS"; return "PASS";
}); });
@ -129,7 +129,7 @@ namespace Grpc.Core.Tests
}); });
var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), ""); var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
var responses = await call.ResponseStream.ToList(); var responses = await call.ResponseStream.ToListAsync();
CollectionAssert.AreEqual(new[] { "A", "B" }, responses); CollectionAssert.AreEqual(new[] { "A", "B" }, responses);
} }
} }

@ -40,30 +40,60 @@ namespace Grpc.Core
/// <summary> /// <summary>
/// Details about a client-side call to be invoked. /// Details about a client-side call to be invoked.
/// </summary> /// </summary>
public class CallInvocationDetails<TRequest, TResponse> public struct CallInvocationDetails<TRequest, TResponse>
{ {
readonly Channel channel; readonly Channel channel;
readonly string method; readonly string method;
readonly string host; readonly string host;
readonly Marshaller<TRequest> requestMarshaller; readonly Marshaller<TRequest> requestMarshaller;
readonly Marshaller<TResponse> responseMarshaller; readonly Marshaller<TResponse> responseMarshaller;
readonly CallOptions options; CallOptions options;
/// <summary>
/// Initializes a new instance of the <see cref="Grpc.Core.CallInvocationDetails`2"/> struct.
/// </summary>
/// <param name="channel">Channel to use for this call.</param>
/// <param name="method">Method to call.</param>
/// <param name="options">Call options.</param>
public CallInvocationDetails(Channel channel, Method<TRequest, TResponse> method, CallOptions options) : public CallInvocationDetails(Channel channel, Method<TRequest, TResponse> method, CallOptions options) :
this(channel, method.FullName, null, method.RequestMarshaller, method.ResponseMarshaller, options) this(channel, method, null, options)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Grpc.Core.CallInvocationDetails`2"/> struct.
/// </summary>
/// <param name="channel">Channel to use for this call.</param>
/// <param name="method">Method to call.</param>
/// <param name="host">Host that contains the method. if <c>null</c>, default host will be used.</param>
/// <param name="options">Call options.</param>
public CallInvocationDetails(Channel channel, Method<TRequest, TResponse> method, string host, CallOptions options) :
this(channel, method.FullName, host, method.RequestMarshaller, method.ResponseMarshaller, options)
{ {
} }
/// <summary>
/// Initializes a new instance of the <see cref="Grpc.Core.CallInvocationDetails`2"/> struct.
/// </summary>
/// <param name="channel">Channel to use for this call.</param>
/// <param name="method">Qualified method name.</param>
/// <param name="host">Host that contains the method.</param>
/// <param name="requestMarshaller">Request marshaller.</param>
/// <param name="responseMarshaller">Response marshaller.</param>
/// <param name="options">Call options.</param>
public CallInvocationDetails(Channel channel, string method, string host, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller, CallOptions options) public CallInvocationDetails(Channel channel, string method, string host, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller, CallOptions options)
{ {
this.channel = Preconditions.CheckNotNull(channel); this.channel = Preconditions.CheckNotNull(channel, "channel");
this.method = Preconditions.CheckNotNull(method); this.method = Preconditions.CheckNotNull(method, "method");
this.host = host; this.host = host;
this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller); this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller, "requestMarshaller");
this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller); this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller, "responseMarshaller");
this.options = Preconditions.CheckNotNull(options); this.options = options;
} }
/// <summary>
/// Get channel associated with this call.
/// </summary>
public Channel Channel public Channel Channel
{ {
get get
@ -72,6 +102,9 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Gets name of method to be called.
/// </summary>
public string Method public string Method
{ {
get get
@ -80,6 +113,9 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Get name of host.
/// </summary>
public string Host public string Host
{ {
get get
@ -88,6 +124,9 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Gets marshaller used to serialize requests.
/// </summary>
public Marshaller<TRequest> RequestMarshaller public Marshaller<TRequest> RequestMarshaller
{ {
get get
@ -96,6 +135,9 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Gets marshaller used to deserialized responses.
/// </summary>
public Marshaller<TResponse> ResponseMarshaller public Marshaller<TResponse> ResponseMarshaller
{ {
get get
@ -104,6 +146,9 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Gets the call options.
/// </summary>
public CallOptions Options public CallOptions Options
{ {
get get
@ -111,5 +156,16 @@ namespace Grpc.Core
return options; return options;
} }
} }
/// <summary>
/// Returns new instance of <see cref="CallInvocationDetails"/> with
/// <c>Options</c> set to the value provided. Values of all other fields are preserved.
/// </summary>
public CallInvocationDetails<TRequest, TResponse> WithOptions(CallOptions options)
{
var newDetails = this;
newDetails.options = options;
return newDetails;
}
} }
} }

@ -42,29 +42,28 @@ namespace Grpc.Core
/// <summary> /// <summary>
/// Options for calls made by client. /// Options for calls made by client.
/// </summary> /// </summary>
public class CallOptions public struct CallOptions
{ {
readonly Metadata headers; Metadata headers;
readonly DateTime deadline; DateTime? deadline;
readonly CancellationToken cancellationToken; CancellationToken cancellationToken;
readonly WriteOptions writeOptions; WriteOptions writeOptions;
readonly ContextPropagationToken propagationToken; ContextPropagationToken propagationToken;
/// <summary> /// <summary>
/// Creates a new instance of <c>CallOptions</c>. /// Creates a new instance of <c>CallOptions</c> struct.
/// </summary> /// </summary>
/// <param name="headers">Headers to be sent with the call.</param> /// <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="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> /// <param name="cancellationToken">Can be used to request cancellation of the call.</param>
/// <param name="writeOptions">Write options that will be used for this call.</param> /// <param name="writeOptions">Write options that will be used for this call.</param>
/// <param name="propagationToken">Context propagation token obtained from <see cref="ServerCallContext"/>.</param> /// <param name="propagationToken">Context propagation token obtained from <see cref="ServerCallContext"/>.</param>
public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken? cancellationToken = null, public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken),
WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null) WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null)
{ {
// TODO(jtattermusch): consider only creating metadata object once it's really needed. this.headers = headers;
this.headers = headers ?? new Metadata(); this.deadline = deadline;
this.deadline = deadline ?? (propagationToken != null ? propagationToken.Deadline : DateTime.MaxValue); this.cancellationToken = cancellationToken;
this.cancellationToken = cancellationToken ?? (propagationToken != null ? propagationToken.CancellationToken : CancellationToken.None);
this.writeOptions = writeOptions; this.writeOptions = writeOptions;
this.propagationToken = propagationToken; this.propagationToken = propagationToken;
} }
@ -80,7 +79,7 @@ namespace Grpc.Core
/// <summary> /// <summary>
/// Call deadline. /// Call deadline.
/// </summary> /// </summary>
public DateTime Deadline public DateTime? Deadline
{ {
get { return deadline; } get { return deadline; }
} }
@ -114,5 +113,66 @@ namespace Grpc.Core
return this.propagationToken; return this.propagationToken;
} }
} }
/// <summary>
/// Returns new instance of <see cref="CallOptions"/> with
/// <c>Headers</c> set to the value provided. Values of all other fields are preserved.
/// </summary>
public CallOptions WithHeaders(Metadata headers)
{
var newOptions = this;
newOptions.headers = headers;
return newOptions;
}
/// <summary>
/// Returns new instance of <see cref="CallOptions"/> with
/// <c>Deadline</c> set to the value provided. Values of all other fields are preserved.
/// </summary>
public CallOptions WithDeadline(DateTime deadline)
{
var newOptions = this;
newOptions.deadline = deadline;
return newOptions;
}
/// <summary>
/// Returns new instance of <see cref="CallOptions"/> with
/// <c>CancellationToken</c> set to the value provided. Values of all other fields are preserved.
/// </summary>
public CallOptions WithCancellationToken(CancellationToken cancellationToken)
{
var newOptions = this;
newOptions.cancellationToken = cancellationToken;
return newOptions;
}
/// <summary>
/// Returns a new instance of <see cref="CallOptions"/> with
/// all previously unset values set to their defaults and deadline and cancellation
/// token propagated when appropriate.
/// </summary>
internal CallOptions Normalize()
{
var newOptions = this;
if (propagationToken != null)
{
if (propagationToken.Options.IsPropagateDeadline)
{
Preconditions.CheckArgument(!newOptions.deadline.HasValue,
"Cannot propagate deadline from parent call. The deadline has already been set explicitly.");
newOptions.deadline = propagationToken.ParentDeadline;
}
if (propagationToken.Options.IsPropagateCancellation)
{
Preconditions.CheckArgument(!newOptions.cancellationToken.CanBeCanceled,
"Cannot propagate cancellation token from parent call. The cancellation token has already been set to a non-default value.");
}
}
newOptions.headers = newOptions.headers ?? Metadata.Empty;
newOptions.deadline = newOptions.deadline ?? DateTime.MaxValue;
return newOptions;
}
} }
} }

@ -31,8 +31,6 @@
#endregion #endregion
using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Grpc.Core.Internal; using Grpc.Core.Internal;
@ -40,9 +38,20 @@ namespace Grpc.Core
{ {
/// <summary> /// <summary>
/// Helper methods for generated clients to make RPC calls. /// Helper methods for generated clients to make RPC calls.
/// Most users will use this class only indirectly and will be
/// making calls using client object generated from protocol
/// buffer definition files.
/// </summary> /// </summary>
public static class Calls public static class Calls
{ {
/// <summary>
/// Invokes a simple remote call in a blocking fashion.
/// </summary>
/// <returns>The response.</returns>
/// <param name="call">The call defintion.</param>
/// <param name="req">Request message.</param>
/// <typeparam name="TRequest">Type of request message.</typeparam>
/// <typeparam name="TResponse">The of response message.</typeparam>
public static TResponse BlockingUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req) public static TResponse BlockingUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req)
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class
@ -51,6 +60,14 @@ namespace Grpc.Core
return asyncCall.UnaryCall(req); return asyncCall.UnaryCall(req);
} }
/// <summary>
/// Invokes a simple remote call asynchronously.
/// </summary>
/// <returns>An awaitable call object providing access to the response.</returns>
/// <param name="call">The call defintion.</param>
/// <param name="req">Request message.</param>
/// <typeparam name="TRequest">Type of request message.</typeparam>
/// <typeparam name="TResponse">The of response message.</typeparam>
public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req) public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req)
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class
@ -60,6 +77,15 @@ namespace Grpc.Core
return new AsyncUnaryCall<TResponse>(asyncResult, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); return new AsyncUnaryCall<TResponse>(asyncResult, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
} }
/// <summary>
/// Invokes a server streaming call asynchronously.
/// In server streaming scenario, client sends on request and server responds with a stream of responses.
/// </summary>
/// <returns>A call object providing access to the asynchronous response stream.</returns>
/// <param name="call">The call defintion.</param>
/// <param name="req">Request message.</param>
/// <typeparam name="TRequest">Type of request message.</typeparam>
/// <typeparam name="TResponse">The of response messages.</typeparam>
public static AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req) public static AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req)
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class
@ -70,6 +96,13 @@ namespace Grpc.Core
return new AsyncServerStreamingCall<TResponse>(responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); return new AsyncServerStreamingCall<TResponse>(responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
} }
/// <summary>
/// Invokes a client streaming call asynchronously.
/// In client streaming scenario, client sends a stream of requests and server responds with a single response.
/// </summary>
/// <returns>An awaitable call object providing access to the response.</returns>
/// <typeparam name="TRequest">Type of request messages.</typeparam>
/// <typeparam name="TResponse">The of response message.</typeparam>
public static AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call) public static AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call)
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class
@ -80,6 +113,15 @@ namespace Grpc.Core
return new AsyncClientStreamingCall<TRequest, TResponse>(requestStream, resultTask, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); return new AsyncClientStreamingCall<TRequest, TResponse>(requestStream, resultTask, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
} }
/// <summary>
/// Invokes a duplex streaming call asynchronously.
/// In duplex streaming scenario, client sends a stream of requests and server responds with a stream of responses.
/// The response stream is completely independent and both side can be sending messages at the same time.
/// </summary>
/// <returns>A call object providing access to the asynchronous request and response streams.</returns>
/// <param name="call">The call definition.</param>
/// <typeparam name="TRequest">Type of request messages.</typeparam>
/// <typeparam name="TResponse">Type of reponse messages.</typeparam>
public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call) public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call)
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class

@ -63,7 +63,7 @@ namespace Grpc.Core
/// <param name="options">Channel options.</param> /// <param name="options">Channel options.</param>
public Channel(string host, Credentials credentials, IEnumerable<ChannelOption> options = null) public Channel(string host, Credentials credentials, IEnumerable<ChannelOption> options = null)
{ {
Preconditions.CheckNotNull(host); Preconditions.CheckNotNull(host, "host");
this.environment = GrpcEnvironment.GetInstance(); this.environment = GrpcEnvironment.GetInstance();
this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>(); this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();

@ -63,8 +63,8 @@ namespace Grpc.Core
public ChannelOption(string name, string stringValue) public ChannelOption(string name, string stringValue)
{ {
this.type = OptionType.String; this.type = OptionType.String;
this.name = Preconditions.CheckNotNull(name); this.name = Preconditions.CheckNotNull(name, "name");
this.stringValue = Preconditions.CheckNotNull(stringValue); this.stringValue = Preconditions.CheckNotNull(stringValue, "stringValue");
} }
/// <summary> /// <summary>
@ -75,7 +75,7 @@ namespace Grpc.Core
public ChannelOption(string name, int intValue) public ChannelOption(string name, int intValue)
{ {
this.type = OptionType.Integer; this.type = OptionType.Integer;
this.name = Preconditions.CheckNotNull(name); this.name = Preconditions.CheckNotNull(name, "name");
this.intValue = intValue; this.intValue = intValue;
} }

@ -62,6 +62,18 @@ namespace Grpc.Core
set; set;
} }
/// <summary>
/// gRPC supports multiple "hosts" being served by a single server.
/// This property can be used to set the target host explicitly.
/// By default, this will be set to <c>null</c> with the meaning
/// "use default host".
/// </summary>
public string Host
{
get;
set;
}
/// <summary> /// <summary>
/// Channel associated with this client. /// Channel associated with this client.
/// </summary> /// </summary>
@ -83,10 +95,14 @@ namespace Grpc.Core
var interceptor = HeaderInterceptor; var interceptor = HeaderInterceptor;
if (interceptor != null) if (interceptor != null)
{ {
if (options.Headers == null)
{
options = options.WithHeaders(new Metadata());
}
interceptor(options.Headers); interceptor(options.Headers);
options.Headers.Freeze(); options.Headers.Freeze();
} }
return new CallInvocationDetails<TRequest, TResponse>(channel, method, options); return new CallInvocationDetails<TRequest, TResponse>(channel, method, Host, options);
} }
} }
} }

@ -52,7 +52,7 @@ namespace Grpc.Core
/// <summary> /// <summary>
/// Default propagation mask used by C core. /// Default propagation mask used by C core.
/// </summary> /// </summary>
const ContextPropagationFlags DefaultCoreMask = (ContextPropagationFlags)0xffff; private const ContextPropagationFlags DefaultCoreMask = (ContextPropagationFlags)0xffff;
/// <summary> /// <summary>
/// Default propagation mask used by C# - we want to propagate deadline /// Default propagation mask used by C# - we want to propagate deadline
@ -74,6 +74,9 @@ namespace Grpc.Core
this.options = options ?? ContextPropagationOptions.Default; this.options = options ?? ContextPropagationOptions.Default;
} }
/// <summary>
/// Gets the native handle of the parent call.
/// </summary>
internal CallSafeHandle ParentCall internal CallSafeHandle ParentCall
{ {
get get
@ -82,7 +85,10 @@ namespace Grpc.Core
} }
} }
internal DateTime Deadline /// <summary>
/// Gets the parent call's deadline.
/// </summary>
internal DateTime ParentDeadline
{ {
get get
{ {
@ -90,7 +96,10 @@ namespace Grpc.Core
} }
} }
internal CancellationToken CancellationToken /// <summary>
/// Gets the parent call's cancellation token.
/// </summary>
internal CancellationToken ParentCancellationToken
{ {
get get
{ {
@ -98,6 +107,9 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Get the context propagation options.
/// </summary>
internal ContextPropagationOptions Options internal ContextPropagationOptions Options
{ {
get get
@ -105,16 +117,6 @@ namespace Grpc.Core
return this.options; return this.options;
} }
} }
internal bool IsPropagateDeadline
{
get { return false; }
}
internal bool IsPropagateCancellation
{
get { return false; }
}
} }
/// <summary> /// <summary>
@ -122,7 +124,37 @@ namespace Grpc.Core
/// </summary> /// </summary>
public class ContextPropagationOptions public class ContextPropagationOptions
{ {
/// <summary>
/// The context propagation options that will be used by default.
/// </summary>
public static readonly ContextPropagationOptions Default = new ContextPropagationOptions(); public static readonly ContextPropagationOptions Default = new ContextPropagationOptions();
bool propagateDeadline;
bool propagateCancellation;
/// <summary>
/// Creates new context propagation options.
/// </summary>
/// <param name="propagateDeadline">If set to <c>true</c> parent call's deadline will be propagated to the child call.</param>
/// <param name="propagateCancellation">If set to <c>true</c> parent call's cancellation token will be propagated to the child call.</param>
public ContextPropagationOptions(bool propagateDeadline = true, bool propagateCancellation = true)
{
this.propagateDeadline = propagateDeadline;
this.propagateCancellation = propagateCancellation;
}
/// <value><c>true</c> if parent call's deadline should be propagated to the child call.</value>
public bool IsPropagateDeadline
{
get { return this.propagateDeadline; }
}
/// <value><c>true</c> if parent call's cancellation token should be propagated to the child call.</value>
public bool IsPropagateCancellation
{
get { return this.propagateCancellation; }
}
} }
/// <summary> /// <summary>

@ -77,7 +77,6 @@
<Compile Include="ServerServiceDefinition.cs" /> <Compile Include="ServerServiceDefinition.cs" />
<Compile Include="Utils\AsyncStreamExtensions.cs" /> <Compile Include="Utils\AsyncStreamExtensions.cs" />
<Compile Include="Utils\BenchmarkUtil.cs" /> <Compile Include="Utils\BenchmarkUtil.cs" />
<Compile Include="Utils\ExceptionHelper.cs" />
<Compile Include="Internal\CredentialsSafeHandle.cs" /> <Compile Include="Internal\CredentialsSafeHandle.cs" />
<Compile Include="Credentials.cs" /> <Compile Include="Credentials.cs" />
<Compile Include="Internal\ChannelArgsSafeHandle.cs" /> <Compile Include="Internal\ChannelArgsSafeHandle.cs" />

@ -115,7 +115,7 @@ namespace Grpc.Core
/// </summary> /// </summary>
public static void SetLogger(ILogger customLogger) public static void SetLogger(ILogger customLogger)
{ {
Preconditions.CheckNotNull(customLogger); Preconditions.CheckNotNull(customLogger, "customLogger");
logger = customLogger; logger = customLogger;
} }
@ -192,23 +192,5 @@ namespace Grpc.Core
Logger.Info("gRPC shutdown."); Logger.Info("gRPC shutdown.");
} }
/// <summary>
/// Shuts down this environment asynchronously.
/// </summary>
private Task CloseAsync()
{
return Task.Run(() =>
{
try
{
Close();
}
catch (Exception e)
{
Logger.Error(e, "Error occured while shutting down GrpcEnvironment.");
}
});
}
} }
} }

@ -63,7 +63,7 @@ namespace Grpc.Core.Internal
public AsyncCall(CallInvocationDetails<TRequest, TResponse> callDetails) public AsyncCall(CallInvocationDetails<TRequest, TResponse> callDetails)
: base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer) : base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer)
{ {
this.details = callDetails; this.details = callDetails.WithOptions(callDetails.Options.Normalize());
this.initialMetadataSent = true; // we always send metadata at the very beginning of the call. this.initialMetadataSent = true; // we always send metadata at the very beginning of the call.
} }
@ -109,15 +109,9 @@ namespace Grpc.Core.Internal
} }
} }
try
{
// Once the blocking call returns, the result should be available synchronously. // Once the blocking call returns, the result should be available synchronously.
return unaryResponseTcs.Task.Result; // Note that GetAwaiter().GetResult() doesn't wrap exceptions in AggregateException.
} return unaryResponseTcs.Task.GetAwaiter().GetResult();
catch (AggregateException ae)
{
throw ExceptionHelper.UnwrapRpcException(ae);
}
} }
} }
@ -324,12 +318,11 @@ namespace Grpc.Core.Internal
private void Initialize(CompletionQueueSafeHandle cq) private void Initialize(CompletionQueueSafeHandle cq)
{ {
var propagationToken = details.Options.PropagationToken; var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance;
var parentCall = propagationToken != null ? propagationToken.ParentCall : CallSafeHandle.NullInstance;
var call = details.Channel.Handle.CreateCall(details.Channel.Environment.CompletionRegistry, var call = details.Channel.Handle.CreateCall(details.Channel.Environment.CompletionRegistry,
parentCall, ContextPropagationToken.DefaultMask, cq, parentCall, ContextPropagationToken.DefaultMask, cq,
details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline)); details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value));
details.Channel.Environment.DebugStats.ActiveClientCalls.Increment(); details.Channel.Environment.DebugStats.ActiveClientCalls.Increment();
InitializeInternal(call); InitializeInternal(call);
RegisterCancellationCallback(); RegisterCancellationCallback();

@ -211,7 +211,7 @@ namespace Grpc.Core.Internal
return Timespec.InfPast; return Timespec.InfPast;
} }
Preconditions.CheckArgument(dateTime.Kind == DateTimeKind.Utc, "dateTime"); Preconditions.CheckArgument(dateTime.Kind == DateTimeKind.Utc, "dateTime needs of kind DateTimeKind.Utc or be equal to DateTime.MaxValue or DateTime.MinValue.");
try try
{ {

@ -54,8 +54,8 @@ namespace Grpc.Core
/// <param name="privateKey">PEM encoded private key.</param> /// <param name="privateKey">PEM encoded private key.</param>
public KeyCertificatePair(string certificateChain, string privateKey) public KeyCertificatePair(string certificateChain, string privateKey)
{ {
this.certificateChain = Preconditions.CheckNotNull(certificateChain); this.certificateChain = Preconditions.CheckNotNull(certificateChain, "certificateChain");
this.privateKey = Preconditions.CheckNotNull(privateKey); this.privateKey = Preconditions.CheckNotNull(privateKey, "privateKey");
} }
/// <summary> /// <summary>

@ -42,16 +42,21 @@ namespace Grpc.Core.Logging
readonly Type forType; readonly Type forType;
readonly string forTypeString; readonly string forTypeString;
/// <summary>Creates a console logger not associated to any specific type.</summary>
public ConsoleLogger() : this(null) public ConsoleLogger() : this(null)
{ {
} }
/// <summary>Creates a console logger that logs messsage specific for given type.</summary>
private ConsoleLogger(Type forType) private ConsoleLogger(Type forType)
{ {
this.forType = forType; this.forType = forType;
this.forTypeString = forType != null ? forType.FullName + " " : ""; this.forTypeString = forType != null ? forType.FullName + " " : "";
} }
/// <summary>
/// Returns a logger associated with the specified type.
/// </summary>
public ILogger ForType<T>() public ILogger ForType<T>()
{ {
if (typeof(T) == forType) if (typeof(T) == forType)
@ -61,31 +66,37 @@ namespace Grpc.Core.Logging
return new ConsoleLogger(typeof(T)); return new ConsoleLogger(typeof(T));
} }
/// <summary>Logs a message with severity Debug.</summary>
public void Debug(string message, params object[] formatArgs) public void Debug(string message, params object[] formatArgs)
{ {
Log("D", message, formatArgs); Log("D", message, formatArgs);
} }
/// <summary>Logs a message with severity Info.</summary>
public void Info(string message, params object[] formatArgs) public void Info(string message, params object[] formatArgs)
{ {
Log("I", message, formatArgs); Log("I", message, formatArgs);
} }
/// <summary>Logs a message with severity Warning.</summary>
public void Warning(string message, params object[] formatArgs) public void Warning(string message, params object[] formatArgs)
{ {
Log("W", message, formatArgs); Log("W", message, formatArgs);
} }
/// <summary>Logs a message and an associated exception with severity Warning.</summary>
public void Warning(Exception exception, string message, params object[] formatArgs) public void Warning(Exception exception, string message, params object[] formatArgs)
{ {
Log("W", message + " " + exception, formatArgs); Log("W", message + " " + exception, formatArgs);
} }
/// <summary>Logs a message with severity Error.</summary>
public void Error(string message, params object[] formatArgs) public void Error(string message, params object[] formatArgs)
{ {
Log("E", message, formatArgs); Log("E", message, formatArgs);
} }
/// <summary>Logs a message and an associated exception with severity Error.</summary>
public void Error(Exception exception, string message, params object[] formatArgs) public void Error(Exception exception, string message, params object[] formatArgs)
{ {
Log("E", message + " " + exception, formatArgs); Log("E", message + " " + exception, formatArgs);

@ -42,16 +42,22 @@ namespace Grpc.Core.Logging
/// <summary>Returns a logger associated with the specified type.</summary> /// <summary>Returns a logger associated with the specified type.</summary>
ILogger ForType<T>(); ILogger ForType<T>();
/// <summary>Logs a message with severity Debug.</summary>
void Debug(string message, params object[] formatArgs); void Debug(string message, params object[] formatArgs);
/// <summary>Logs a message with severity Info.</summary>
void Info(string message, params object[] formatArgs); void Info(string message, params object[] formatArgs);
/// <summary>Logs a message with severity Warning.</summary>
void Warning(string message, params object[] formatArgs); void Warning(string message, params object[] formatArgs);
/// <summary>Logs a message and an associated exception with severity Warning.</summary>
void Warning(Exception exception, string message, params object[] formatArgs); void Warning(Exception exception, string message, params object[] formatArgs);
/// <summary>Logs a message with severity Error.</summary>
void Error(string message, params object[] formatArgs); void Error(string message, params object[] formatArgs);
/// <summary>Logs a message and an associated exception with severity Error.</summary>
void Error(Exception exception, string message, params object[] formatArgs); void Error(Exception exception, string message, params object[] formatArgs);
} }
} }

@ -37,19 +37,27 @@ using Grpc.Core.Utils;
namespace Grpc.Core namespace Grpc.Core
{ {
/// <summary> /// <summary>
/// For serializing and deserializing messages. /// Encapsulates the logic for serializing and deserializing messages.
/// </summary> /// </summary>
public struct Marshaller<T> public struct Marshaller<T>
{ {
readonly Func<T, byte[]> serializer; readonly Func<T, byte[]> serializer;
readonly Func<byte[], T> deserializer; readonly Func<byte[], T> deserializer;
/// <summary>
/// Initializes a new marshaller.
/// </summary>
/// <param name="serializer">Function that will be used to serialize messages.</param>
/// <param name="deserializer">Function that will be used to deserialize messages.</param>
public Marshaller(Func<T, byte[]> serializer, Func<byte[], T> deserializer) public Marshaller(Func<T, byte[]> serializer, Func<byte[], T> deserializer)
{ {
this.serializer = Preconditions.CheckNotNull(serializer); this.serializer = Preconditions.CheckNotNull(serializer, "serializer");
this.deserializer = Preconditions.CheckNotNull(deserializer); this.deserializer = Preconditions.CheckNotNull(deserializer, "deserializer");
} }
/// <summary>
/// Gets the serializer function.
/// </summary>
public Func<T, byte[]> Serializer public Func<T, byte[]> Serializer
{ {
get get
@ -58,6 +66,9 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Gets the deserializer function.
/// </summary>
public Func<byte[], T> Deserializer public Func<byte[], T> Deserializer
{ {
get get
@ -72,11 +83,17 @@ namespace Grpc.Core
/// </summary> /// </summary>
public static class Marshallers public static class Marshallers
{ {
/// <summary>
/// Creates a marshaller from specified serializer and deserializer.
/// </summary>
public static Marshaller<T> Create<T>(Func<T, byte[]> serializer, Func<byte[], T> deserializer) public static Marshaller<T> Create<T>(Func<T, byte[]> serializer, Func<byte[], T> deserializer)
{ {
return new Marshaller<T>(serializer, deserializer); return new Marshaller<T>(serializer, deserializer);
} }
/// <summary>
/// Returns a marshaller for <c>string</c> type. This is useful for testing.
/// </summary>
public static Marshaller<string> StringMarshaller public static Marshaller<string> StringMarshaller
{ {
get get

@ -186,15 +186,15 @@ namespace Grpc.Core
public Entry(string key, byte[] valueBytes) public Entry(string key, byte[] valueBytes)
{ {
this.key = Preconditions.CheckNotNull(key); this.key = Preconditions.CheckNotNull(key, "key");
this.value = null; this.value = null;
this.valueBytes = Preconditions.CheckNotNull(valueBytes); this.valueBytes = Preconditions.CheckNotNull(valueBytes, "valueBytes");
} }
public Entry(string key, string value) public Entry(string key, string value)
{ {
this.key = Preconditions.CheckNotNull(key); this.key = Preconditions.CheckNotNull(key, "key");
this.value = Preconditions.CheckNotNull(value); this.value = Preconditions.CheckNotNull(value, "value");
this.valueBytes = null; this.valueBytes = null;
} }

@ -41,14 +41,21 @@ namespace Grpc.Core
/// </summary> /// </summary>
public enum MethodType public enum MethodType
{ {
Unary, // Unary request, unary response. /// <summary>Single request sent from client, single response received from server.</summary>
ClientStreaming, // Streaming request, unary response. Unary,
ServerStreaming, // Unary request, streaming response.
DuplexStreaming // Streaming request, streaming response. /// <summary>Stream of request sent from client, single response received from server.</summary>
ClientStreaming,
/// <summary>Single request sent from client, stream of responses received from server.</summary>
ServerStreaming,
/// <summary>Both server and client can stream arbitrary number of requests and responses simultaneously.</summary>
DuplexStreaming
} }
/// <summary> /// <summary>
/// A description of a service method. /// A description of a remote method.
/// </summary> /// </summary>
public class Method<TRequest, TResponse> public class Method<TRequest, TResponse>
{ {
@ -59,16 +66,27 @@ namespace Grpc.Core
readonly Marshaller<TResponse> responseMarshaller; readonly Marshaller<TResponse> responseMarshaller;
readonly string fullName; readonly string fullName;
/// <summary>
/// Initializes a new instance of the <c>Method</c> class.
/// </summary>
/// <param name="type">Type of method.</param>
/// <param name="serviceName">Name of service this method belongs to.</param>
/// <param name="name">Unqualified name of the method.</param>
/// <param name="requestMarshaller">Marshaller used for request messages.</param>
/// <param name="responseMarshaller">Marshaller used for response messages.</param>
public Method(MethodType type, string serviceName, 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.type = type;
this.serviceName = Preconditions.CheckNotNull(serviceName); this.serviceName = Preconditions.CheckNotNull(serviceName, "serviceName");
this.name = Preconditions.CheckNotNull(name); this.name = Preconditions.CheckNotNull(name, "name");
this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller); this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller, "requestMarshaller");
this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller); this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller, "responseMarshaller");
this.fullName = GetFullName(serviceName); this.fullName = GetFullName(serviceName, name);
} }
/// <summary>
/// Gets the type of the method.
/// </summary>
public MethodType Type public MethodType Type
{ {
get get
@ -77,6 +95,9 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Gets the name of the service to which this method belongs.
/// </summary>
public string ServiceName public string ServiceName
{ {
get get
@ -85,6 +106,9 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Gets the unqualified name of the method.
/// </summary>
public string Name public string Name
{ {
get get
@ -93,6 +117,9 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Gets the marshaller used for request messages.
/// </summary>
public Marshaller<TRequest> RequestMarshaller public Marshaller<TRequest> RequestMarshaller
{ {
get get
@ -101,6 +128,9 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Gets the marshaller used for response messages.
/// </summary>
public Marshaller<TResponse> ResponseMarshaller public Marshaller<TResponse> ResponseMarshaller
{ {
get get
@ -109,6 +139,10 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Gets the fully qualified name of the method. On the server side, methods are dispatched
/// based on this name.
/// </summary>
public string FullName public string FullName
{ {
get get
@ -120,9 +154,9 @@ namespace Grpc.Core
/// <summary> /// <summary>
/// Gets full name of the method including the service name. /// Gets full name of the method including the service name.
/// </summary> /// </summary>
internal string GetFullName(string serviceName) internal static string GetFullName(string serviceName, string methodName)
{ {
return "/" + Preconditions.CheckNotNull(serviceName) + "/" + this.Name; return "/" + serviceName + "/" + methodName;
} }
} }
} }

@ -36,22 +36,34 @@ using System;
namespace Grpc.Core namespace Grpc.Core
{ {
/// <summary> /// <summary>
/// Thrown when remote procedure call fails. /// Thrown when remote procedure call fails. Every <c>RpcException</c> is associated with a resulting <see cref="Status"/> of the call.
/// </summary> /// </summary>
public class RpcException : Exception public class RpcException : Exception
{ {
private readonly Status status; private readonly Status status;
/// <summary>
/// Creates a new <c>RpcException</c> associated with given status.
/// </summary>
/// <param name="status">Resulting status of a call.</param>
public RpcException(Status status) : base(status.ToString()) public RpcException(Status status) : base(status.ToString())
{ {
this.status = status; this.status = status;
} }
/// <summary>
/// Creates a new <c>RpcException</c> associated with given status and message.
/// </summary>
/// <param name="status">Resulting status of a call.</param>
/// <param name="message">The exception message.</param>
public RpcException(Status status, string message) : base(message) public RpcException(Status status, string message) : base(message)
{ {
this.status = status; this.status = status;
} }
/// <summary>
/// Resulting status of the call.
/// </summary>
public Status Status public Status Status
{ {
get get

@ -192,7 +192,7 @@ namespace Grpc.Core
{ {
lock (myLock) lock (myLock)
{ {
Preconditions.CheckNotNull(serverPort.Credentials); Preconditions.CheckNotNull(serverPort.Credentials, "serverPort");
Preconditions.CheckState(!startRequested); Preconditions.CheckState(!startRequested);
var address = string.Format("{0}:{1}", serverPort.Host, serverPort.Port); var address = string.Format("{0}:{1}", serverPort.Host, serverPort.Port);
int boundPort; int boundPort;

@ -91,7 +91,7 @@ namespace Grpc.Core
{ {
this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly(); this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly();
Preconditions.CheckArgument(this.keyCertificatePairs.Count > 0, Preconditions.CheckArgument(this.keyCertificatePairs.Count > 0,
"At least one KeyCertificatePair needs to be provided"); "At least one KeyCertificatePair needs to be provided.");
if (forceClientAuth) if (forceClientAuth)
{ {
Preconditions.CheckNotNull(rootCertificates, Preconditions.CheckNotNull(rootCertificates,

@ -31,12 +31,8 @@
#endregion #endregion
using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Grpc.Core.Internal;
namespace Grpc.Core namespace Grpc.Core
{ {
/// <summary> /// <summary>

@ -62,9 +62,9 @@ namespace Grpc.Core
/// <param name="credentials">credentials to use to secure this port.</param> /// <param name="credentials">credentials to use to secure this port.</param>
public ServerPort(string host, int port, ServerCredentials credentials) public ServerPort(string host, int port, ServerCredentials credentials)
{ {
this.host = Preconditions.CheckNotNull(host); this.host = Preconditions.CheckNotNull(host, "host");
this.port = port; this.port = port;
this.credentials = Preconditions.CheckNotNull(credentials); this.credentials = Preconditions.CheckNotNull(credentials, "credentials");
} }
/// <summary> /// <summary>

@ -79,7 +79,7 @@ namespace Grpc.Core
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class
{ {
callHandlers.Add(method.GetFullName(serviceName), ServerCalls.UnaryCall(method, handler)); callHandlers.Add(method.FullName, ServerCalls.UnaryCall(method, handler));
return this; return this;
} }
@ -89,7 +89,7 @@ namespace Grpc.Core
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class
{ {
callHandlers.Add(method.GetFullName(serviceName), ServerCalls.ClientStreamingCall(method, handler)); callHandlers.Add(method.FullName, ServerCalls.ClientStreamingCall(method, handler));
return this; return this;
} }
@ -99,7 +99,7 @@ namespace Grpc.Core
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class
{ {
callHandlers.Add(method.GetFullName(serviceName), ServerCalls.ServerStreamingCall(method, handler)); callHandlers.Add(method.FullName, ServerCalls.ServerStreamingCall(method, handler));
return this; return this;
} }
@ -109,7 +109,7 @@ namespace Grpc.Core
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class
{ {
callHandlers.Add(method.GetFullName(serviceName), ServerCalls.DuplexStreamingCall(method, handler)); callHandlers.Add(method.FullName, ServerCalls.DuplexStreamingCall(method, handler));
return this; return this;
} }

@ -29,13 +29,12 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion #endregion
using System; using Grpc.Core.Utils;
using System.Runtime.InteropServices;
namespace Grpc.Core namespace Grpc.Core
{ {
/// <summary> /// <summary>
/// Represents RPC result. /// Represents RPC result, which consists of <see cref="StatusCode"/> and an optional detail string.
/// </summary> /// </summary>
public struct Status public struct Status
{ {
@ -52,6 +51,11 @@ namespace Grpc.Core
readonly StatusCode statusCode; readonly StatusCode statusCode;
readonly string detail; readonly string detail;
/// <summary>
/// Creates a new instance of <c>Status</c>.
/// </summary>
/// <param name="statusCode">Status code.</param>
/// <param name="detail">Detail.</param>
public Status(StatusCode statusCode, string detail) public Status(StatusCode statusCode, string detail)
{ {
this.statusCode = statusCode; this.statusCode = statusCode;
@ -80,6 +84,9 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="Grpc.Core.Status"/>.
/// </summary>
public override string ToString() public override string ToString()
{ {
return string.Format("Status(StatusCode={0}, Detail=\"{1}\")", statusCode, detail); return string.Format("Status(StatusCode={0}, Detail=\"{1}\")", statusCode, detail);

@ -31,8 +31,6 @@
#endregion #endregion
using System;
namespace Grpc.Core namespace Grpc.Core
{ {
/// <summary> /// <summary>
@ -41,101 +39,101 @@ namespace Grpc.Core
/// </summary> /// </summary>
public enum StatusCode public enum StatusCode
{ {
/* Not an error; returned on success */ /// <summary>Not an error; returned on success.</summary>
OK = 0, OK = 0,
/* The operation was cancelled (typically by the caller). */
/// <summary>The operation was cancelled (typically by the caller).</summary>
Cancelled = 1, Cancelled = 1,
/* Unknown error. An example of where this error may be returned is
if a Status value received from another address space belongs to /// <summary>
an error-space that is not known in this address space. Also /// Unknown error. An example of where this error may be returned is
errors raised by APIs that do not return enough error information /// if a Status value received from another address space belongs to
may be converted to this error. */ /// an error-space that is not known in this address space. Also
/// errors raised by APIs that do not return enough error information
/// may be converted to this error.
/// </summary>
Unknown = 2, Unknown = 2,
/* Client specified an invalid argument. Note that this differs
from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments /// <summary>
that are problematic regardless of the state of the system /// Client specified an invalid argument. Note that this differs
(e.g., a malformed file name). */ /// from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments
/// that are problematic regardless of the state of the system
/// (e.g., a malformed file name).
/// </summary>
InvalidArgument = 3, InvalidArgument = 3,
/* Deadline expired before operation could complete. For operations
that change the state of the system, this error may be returned /// <summary>
even if the operation has completed successfully. For example, a /// Deadline expired before operation could complete. For operations
successful response from a server could have been delayed long /// that change the state of the system, this error may be returned
enough for the deadline to expire. */ /// even if the operation has completed successfully. For example, a
/// successful response from a server could have been delayed long
/// enough for the deadline to expire.
/// </summary>
DeadlineExceeded = 4, DeadlineExceeded = 4,
/* Some requested entity (e.g., file or directory) was not found. */
/// <summary>Some requested entity (e.g., file or directory) was not found.</summary>
NotFound = 5, NotFound = 5,
/* Some entity that we attempted to create (e.g., file or directory)
already exists. */ /// <summary>Some entity that we attempted to create (e.g., file or directory) already exists.</summary>
AlreadyExists = 6, AlreadyExists = 6,
/* The caller does not have permission to execute the specified
operation. PERMISSION_DENIED must not be used for rejections /// <summary>
caused by exhausting some resource (use RESOURCE_EXHAUSTED /// The caller does not have permission to execute the specified
instead for those errors). PERMISSION_DENIED must not be /// operation. PERMISSION_DENIED must not be used for rejections
used if the caller can not be identified (use UNAUTHENTICATED /// caused by exhausting some resource (use RESOURCE_EXHAUSTED
instead for those errors). */ /// instead for those errors). PERMISSION_DENIED must not be
/// used if the caller can not be identified (use UNAUTHENTICATED
/// instead for those errors).
/// </summary>
PermissionDenied = 7, PermissionDenied = 7,
/* The request does not have valid authentication credentials for the
operation. */ /// <summary>The request does not have valid authentication credentials for the operation.</summary>
Unauthenticated = 16, Unauthenticated = 16,
/* Some resource has been exhausted, perhaps a per-user quota, or
perhaps the entire file system is out of space. */ /// <summary>
/// Some resource has been exhausted, perhaps a per-user quota, or
/// perhaps the entire file system is out of space.
/// </summary>
ResourceExhausted = 8, ResourceExhausted = 8,
/* Operation was rejected because the system is not in a state
required for the operation's execution. For example, directory /// <summary>
to be deleted may be non-empty, an rmdir operation is applied to /// Operation was rejected because the system is not in a state
a non-directory, etc. /// required for the operation's execution. For example, directory
/// to be deleted may be non-empty, an rmdir operation is applied to
A litmus test that may help a service implementor in deciding /// a non-directory, etc.
between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE: /// </summary>
(a) Use UNAVAILABLE if the client can retry just the failing call.
(b) Use ABORTED if the client should retry at a higher-level
(e.g., restarting a read-modify-write sequence).
(c) Use FAILED_PRECONDITION if the client should not retry until
the system state has been explicitly fixed. E.g., if an "rmdir"
fails because the directory is non-empty, FAILED_PRECONDITION
should be returned since the client should not retry unless
they have first fixed up the directory by deleting files from it.
(d) Use FAILED_PRECONDITION if the client performs conditional
REST Get/Update/Delete on a resource and the resource on the
server does not match the condition. E.g., conflicting
read-modify-write on the same resource. */
FailedPrecondition = 9, FailedPrecondition = 9,
/* The operation was aborted, typically due to a concurrency issue
like sequencer check failures, transaction aborts, etc.
See litmus test above for deciding between FAILED_PRECONDITION, /// <summary>
ABORTED, and UNAVAILABLE. */ /// The operation was aborted, typically due to a concurrency issue
/// like sequencer check failures, transaction aborts, etc.
/// </summary>
Aborted = 10, Aborted = 10,
/* Operation was attempted past the valid range. E.g., seeking or
reading past end of file. /// <summary>
/// Operation was attempted past the valid range. E.g., seeking or
Unlike INVALID_ARGUMENT, this error indicates a problem that may /// reading past end of file.
be fixed if the system state changes. For example, a 32-bit file /// </summary>
system will generate INVALID_ARGUMENT if asked to read at an
offset that is not in the range [0,2^32-1], but it will generate
OUT_OF_RANGE if asked to read from an offset past the current
file size.
There is a fair bit of overlap between FAILED_PRECONDITION and
OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific
error) when it applies so that callers who are iterating through
a space can easily look for an OUT_OF_RANGE error to detect when
they are done. */
OutOfRange = 11, OutOfRange = 11,
/* Operation is not implemented or not supported/enabled in this service. */
/// <summary>Operation is not implemented or not supported/enabled in this service.</summary>
Unimplemented = 12, Unimplemented = 12,
/* Internal errors. Means some invariants expected by underlying
system has been broken. If you see one of these errors, /// <summary>
something is very broken. */ /// Internal errors. Means some invariants expected by underlying
/// system has been broken. If you see one of these errors,
/// something is very broken.
/// </summary>
Internal = 13, Internal = 13,
/* The service is currently unavailable. This is a most likely a
transient condition and may be corrected by retrying with
a backoff.
See litmus test above for deciding between FAILED_PRECONDITION, /// <summary>
ABORTED, and UNAVAILABLE. */ /// The service is currently unavailable. This is a most likely a
/// transient condition and may be corrected by retrying with
/// a backoff.
/// </summary>
Unavailable = 14, Unavailable = 14,
/* Unrecoverable data loss or corruption. */
/// <summary>Unrecoverable data loss or corruption.</summary>
DataLoss = 15 DataLoss = 15
} }
} }

@ -33,7 +33,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Grpc.Core.Utils namespace Grpc.Core.Utils
@ -46,7 +45,7 @@ namespace Grpc.Core.Utils
/// <summary> /// <summary>
/// Reads the entire stream and executes an async action for each element. /// Reads the entire stream and executes an async action for each element.
/// </summary> /// </summary>
public static async Task ForEach<T>(this IAsyncStreamReader<T> streamReader, Func<T, Task> asyncAction) public static async Task ForEachAsync<T>(this IAsyncStreamReader<T> streamReader, Func<T, Task> asyncAction)
where T : class where T : class
{ {
while (await streamReader.MoveNext()) while (await streamReader.MoveNext())
@ -58,7 +57,7 @@ namespace Grpc.Core.Utils
/// <summary> /// <summary>
/// Reads the entire stream and creates a list containing all the elements read. /// Reads the entire stream and creates a list containing all the elements read.
/// </summary> /// </summary>
public static async Task<List<T>> ToList<T>(this IAsyncStreamReader<T> streamReader) public static async Task<List<T>> ToListAsync<T>(this IAsyncStreamReader<T> streamReader)
where T : class where T : class
{ {
var result = new List<T>(); var result = new List<T>();
@ -73,7 +72,7 @@ namespace Grpc.Core.Utils
/// Writes all elements from given enumerable to the stream. /// Writes all elements from given enumerable to the stream.
/// Completes the stream afterwards unless close = false. /// Completes the stream afterwards unless close = false.
/// </summary> /// </summary>
public static async Task WriteAll<T>(this IClientStreamWriter<T> streamWriter, IEnumerable<T> elements, bool complete = true) public static async Task WriteAllAsync<T>(this IClientStreamWriter<T> streamWriter, IEnumerable<T> elements, bool complete = true)
where T : class where T : class
{ {
foreach (var element in elements) foreach (var element in elements)
@ -89,7 +88,7 @@ namespace Grpc.Core.Utils
/// <summary> /// <summary>
/// Writes all elements from given enumerable to the stream. /// Writes all elements from given enumerable to the stream.
/// </summary> /// </summary>
public static async Task WriteAll<T>(this IServerStreamWriter<T> streamWriter, IEnumerable<T> elements) public static async Task WriteAllAsync<T>(this IServerStreamWriter<T> streamWriter, IEnumerable<T> elements)
where T : class where T : class
{ {
foreach (var element in elements) foreach (var element in elements)

@ -39,6 +39,9 @@ using System.Threading.Tasks;
namespace Grpc.Core.Utils namespace Grpc.Core.Utils
{ {
/// <summary>
/// Utility methods to run microbenchmarks.
/// </summary>
public static class BenchmarkUtil public static class BenchmarkUtil
{ {
/// <summary> /// <summary>

@ -1,57 +0,0 @@
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
namespace Grpc.Core.Utils
{
public static class ExceptionHelper
{
/// <summary>
/// If inner exceptions contain RpcException, rethrows it.
/// Otherwise, rethrows the original aggregate exception.
/// Always throws, the exception return type is here only to make the.
/// </summary>
public static Exception UnwrapRpcException(AggregateException ae)
{
foreach (var e in ae.InnerExceptions)
{
if (e is RpcException)
{
throw e;
}
}
throw ae;
}
}
}

@ -32,17 +32,16 @@
#endregion #endregion
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace Grpc.Core.Utils namespace Grpc.Core.Utils
{ {
/// <summary>
/// Utility methods to simplify checking preconditions in the code.
/// </summary>
public static class Preconditions public static class Preconditions
{ {
/// <summary> /// <summary>
/// Throws ArgumentException if condition is false. /// Throws <see cref="ArgumentException"/> if condition is false.
/// </summary> /// </summary>
public static void CheckArgument(bool condition) public static void CheckArgument(bool condition)
{ {
@ -53,7 +52,7 @@ namespace Grpc.Core.Utils
} }
/// <summary> /// <summary>
/// Throws ArgumentException with given message if condition is false. /// Throws <see cref="ArgumentException"/> with given message if condition is false.
/// </summary> /// </summary>
public static void CheckArgument(bool condition, string errorMessage) public static void CheckArgument(bool condition, string errorMessage)
{ {
@ -64,31 +63,31 @@ namespace Grpc.Core.Utils
} }
/// <summary> /// <summary>
/// Throws NullReferenceException if reference is null. /// Throws <see cref="ArgumentNullException"/> if reference is null.
/// </summary> /// </summary>
public static T CheckNotNull<T>(T reference) public static T CheckNotNull<T>(T reference)
{ {
if (reference == null) if (reference == null)
{ {
throw new NullReferenceException(); throw new ArgumentNullException();
} }
return reference; return reference;
} }
/// <summary> /// <summary>
/// Throws NullReferenceException with given message if reference is null. /// Throws <see cref="ArgumentNullException"/> if reference is null.
/// </summary> /// </summary>
public static T CheckNotNull<T>(T reference, string errorMessage) public static T CheckNotNull<T>(T reference, string paramName)
{ {
if (reference == null) if (reference == null)
{ {
throw new NullReferenceException(errorMessage); throw new ArgumentNullException(paramName);
} }
return reference; return reference;
} }
/// <summary> /// <summary>
/// Throws InvalidOperationException if condition is false. /// Throws <see cref="InvalidOperationException"/> if condition is false.
/// </summary> /// </summary>
public static void CheckState(bool condition) public static void CheckState(bool condition)
{ {
@ -99,7 +98,7 @@ namespace Grpc.Core.Utils
} }
/// <summary> /// <summary>
/// Throws InvalidOperationException with given message if condition is false. /// Throws <see cref="InvalidOperationException"/> with given message if condition is false.
/// </summary> /// </summary>
public static void CheckState(bool condition, string errorMessage) public static void CheckState(bool condition, string errorMessage)
{ {

@ -1,5 +1,37 @@
#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.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
// The current version of gRPC C#. // The current version of gRPC C#.
[assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentVersion + ".0")] [assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentVersion + ".0")]

@ -1,8 +1,41 @@
using System.Reflection; #region Copyright notice and license
using System.Runtime.CompilerServices;
// 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
namespace Grpc.Core namespace Grpc.Core
{ {
/// <summary>
/// Provides info about current version of gRPC.
/// </summary>
public static class VersionInfo public static class VersionInfo
{ {
/// <summary> /// <summary>

@ -109,7 +109,7 @@ namespace math.Tests
{ {
using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build())) using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build()))
{ {
var responses = await call.ResponseStream.ToList(); var responses = await call.ResponseStream.ToListAsync();
CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 }, CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 },
responses.ConvertAll((n) => n.Num_)); responses.ConvertAll((n) => n.Num_));
} }
@ -151,7 +151,7 @@ namespace math.Tests
using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(),
deadline: DateTime.UtcNow.AddMilliseconds(500))) deadline: DateTime.UtcNow.AddMilliseconds(500)))
{ {
var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.ToList()); var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.ToListAsync());
// We can't guarantee the status code always DeadlineExceeded. See issue #2685. // We can't guarantee the status code always DeadlineExceeded. See issue #2685.
Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal });
@ -167,7 +167,7 @@ namespace math.Tests
var numbers = new List<long> { 10, 20, 30 }.ConvertAll( var numbers = new List<long> { 10, 20, 30 }.ConvertAll(
n => Num.CreateBuilder().SetNum_(n).Build()); n => Num.CreateBuilder().SetNum_(n).Build());
await call.RequestStream.WriteAll(numbers); await call.RequestStream.WriteAllAsync(numbers);
var result = await call.ResponseAsync; var result = await call.ResponseAsync;
Assert.AreEqual(60, result.Num_); Assert.AreEqual(60, result.Num_);
} }
@ -185,8 +185,8 @@ namespace math.Tests
using (var call = client.DivMany()) using (var call = client.DivMany())
{ {
await call.RequestStream.WriteAll(divArgsList); await call.RequestStream.WriteAllAsync(divArgsList);
var result = await call.ResponseStream.ToList(); var result = await call.ResponseStream.ToListAsync();
CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient)); CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient));
CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder)); CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder));

@ -54,7 +54,7 @@ namespace math
{ {
using (var call = client.Fib(new FibArgs.Builder { Limit = 5 }.Build())) using (var call = client.Fib(new FibArgs.Builder { Limit = 5 }.Build()))
{ {
List<Num> result = await call.ResponseStream.ToList(); List<Num> result = await call.ResponseStream.ToListAsync();
Console.WriteLine("Fib Result: " + string.Join("|", result)); Console.WriteLine("Fib Result: " + string.Join("|", result));
} }
} }
@ -70,7 +70,7 @@ namespace math
using (var call = client.Sum()) using (var call = client.Sum())
{ {
await call.RequestStream.WriteAll(numbers); await call.RequestStream.WriteAllAsync(numbers);
Console.WriteLine("Sum Result: " + await call.ResponseAsync); Console.WriteLine("Sum Result: " + await call.ResponseAsync);
} }
} }
@ -85,8 +85,8 @@ namespace math
}; };
using (var call = client.DivMany()) using (var call = client.DivMany())
{ {
await call.RequestStream.WriteAll(divArgsList); await call.RequestStream.WriteAllAsync(divArgsList);
Console.WriteLine("DivMany Result: " + string.Join("|", await call.ResponseStream.ToList())); Console.WriteLine("DivMany Result: " + string.Join("|", await call.ResponseStream.ToListAsync()));
} }
} }
@ -102,7 +102,7 @@ namespace math
Num sum; Num sum;
using (var sumCall = client.Sum()) using (var sumCall = client.Sum())
{ {
await sumCall.RequestStream.WriteAll(numbers); await sumCall.RequestStream.WriteAllAsync(numbers);
sum = await sumCall.ResponseAsync; sum = await sumCall.ResponseAsync;
} }

@ -75,7 +75,7 @@ namespace math
public async Task<Num> Sum(IAsyncStreamReader<Num> requestStream, ServerCallContext context) public async Task<Num> Sum(IAsyncStreamReader<Num> requestStream, ServerCallContext context)
{ {
long sum = 0; long sum = 0;
await requestStream.ForEach(async num => await requestStream.ForEachAsync(async num =>
{ {
sum += num.Num_; sum += num.Num_;
}); });
@ -84,10 +84,7 @@ namespace math
public async Task DivMany(IAsyncStreamReader<DivArgs> requestStream, IServerStreamWriter<DivReply> responseStream, ServerCallContext context) public async Task DivMany(IAsyncStreamReader<DivArgs> requestStream, IServerStreamWriter<DivReply> responseStream, ServerCallContext context)
{ {
await requestStream.ForEach(async divArgs => await requestStream.ForEachAsync(async divArgs => await responseStream.WriteAsync(DivInternal(divArgs)));
{
await responseStream.WriteAsync(DivInternal(divArgs));
});
} }
static DivReply DivInternal(DivArgs args) static DivReply DivInternal(DivArgs args)

@ -92,11 +92,11 @@ namespace Grpc.HealthCheck.Tests
public void NullsRejected() public void NullsRejected()
{ {
var impl = new HealthServiceImpl(); var impl = new HealthServiceImpl();
Assert.Throws(typeof(NullReferenceException), () => impl.SetStatus(null, "", HealthCheckResponse.Types.ServingStatus.SERVING)); Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus(null, "", HealthCheckResponse.Types.ServingStatus.SERVING));
Assert.Throws(typeof(NullReferenceException), () => impl.SetStatus("", null, HealthCheckResponse.Types.ServingStatus.SERVING)); Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus("", null, HealthCheckResponse.Types.ServingStatus.SERVING));
Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus(null, "")); Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus(null, ""));
Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus("", null)); Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus("", null));
} }
private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string host, string service) private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string host, string service)

@ -215,7 +215,7 @@ namespace Grpc.IntegrationTesting
using (var call = client.StreamingInputCall()) using (var call = client.StreamingInputCall())
{ {
await call.RequestStream.WriteAll(bodySizes); await call.RequestStream.WriteAllAsync(bodySizes);
var response = await call.ResponseAsync; var response = await call.ResponseAsync;
Assert.AreEqual(74922, response.AggregatedPayloadSize); Assert.AreEqual(74922, response.AggregatedPayloadSize);
@ -237,7 +237,7 @@ namespace Grpc.IntegrationTesting
using (var call = client.StreamingOutputCall(request)) using (var call = client.StreamingOutputCall(request))
{ {
var responseList = await call.ResponseStream.ToList(); var responseList = await call.ResponseStream.ToListAsync();
foreach (var res in responseList) foreach (var res in responseList)
{ {
Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type); Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type);
@ -303,7 +303,7 @@ namespace Grpc.IntegrationTesting
{ {
await call.RequestStream.CompleteAsync(); await call.RequestStream.CompleteAsync();
var responseList = await call.ResponseStream.ToList(); var responseList = await call.ResponseStream.ToListAsync();
Assert.AreEqual(0, responseList.Count); Assert.AreEqual(0, responseList.Count);
} }
Console.WriteLine("Passed!"); Console.WriteLine("Passed!");

@ -71,7 +71,7 @@ namespace grpc.testing
public async Task<StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<StreamingInputCallRequest> requestStream, ServerCallContext context) public async Task<StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<StreamingInputCallRequest> requestStream, ServerCallContext context)
{ {
int sum = 0; int sum = 0;
await requestStream.ForEach(async request => await requestStream.ForEachAsync(async request =>
{ {
sum += request.Payload.Body.Length; sum += request.Payload.Body.Length;
}); });
@ -80,7 +80,7 @@ namespace grpc.testing
public async Task FullDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context) public async Task FullDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
{ {
await requestStream.ForEach(async request => await requestStream.ForEachAsync(async request =>
{ {
foreach (var responseParam in request.ResponseParametersList) foreach (var responseParam in request.ResponseParametersList)
{ {

Loading…
Cancel
Save