aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp
diff options
context:
space:
mode:
authorGravatar Nicolas "Pixel" Noble <pixel@nobis-crew.org>2015-08-12 19:53:03 +0200
committerGravatar Nicolas "Pixel" Noble <pixel@nobis-crew.org>2015-08-12 19:53:03 +0200
commit9b6248fc6d3be0e3970e19138bedd0655e4565e8 (patch)
treeee2852ba33f5638d9d3973c944ccc604b5e6fb99 /src/csharp
parentb457cd831ad519d5ec023005ba6ccfb52ff4c9cb (diff)
parent3b226512d4aa84d58e1e61ce3f9adb9315f2d619 (diff)
Merge branch 'master' of github.com:grpc/grpc into the-ultimate-showdown
Conflicts: src/node/ext/call.cc src/node/ext/channel.cc
Diffstat (limited to 'src/csharp')
-rw-r--r--src/csharp/Grpc.Auth/GoogleCredential.cs125
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.csproj27
-rw-r--r--src/csharp/Grpc.Auth/OAuth2Interceptors.cs26
-rw-r--r--src/csharp/Grpc.Auth/app.config4
-rw-r--r--src/csharp/Grpc.Auth/packages.config4
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs6
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelTest.cs6
-rw-r--r--src/csharp/Grpc.Core.Tests/ClientServerTest.cs6
-rw-r--r--src/csharp/Grpc.Core.Tests/CompressionTest.cs4
-rw-r--r--src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs31
-rw-r--r--src/csharp/Grpc.Core.Tests/MockServiceHelper.cs12
-rw-r--r--src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs4
-rw-r--r--src/csharp/Grpc.Core/CallInvocationDetails.cs72
-rw-r--r--src/csharp/Grpc.Core/CallOptions.cs86
-rw-r--r--src/csharp/Grpc.Core/Calls.cs46
-rw-r--r--src/csharp/Grpc.Core/Channel.cs24
-rw-r--r--src/csharp/Grpc.Core/ChannelOptions.cs6
-rw-r--r--src/csharp/Grpc.Core/ClientBase.cs29
-rw-r--r--src/csharp/Grpc.Core/ContextPropagationToken.cs58
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj1
-rw-r--r--src/csharp/Grpc.Core/GrpcEnvironment.cs20
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs19
-rw-r--r--src/csharp/Grpc.Core/Internal/Timespec.cs2
-rw-r--r--src/csharp/Grpc.Core/KeyCertificatePair.cs4
-rw-r--r--src/csharp/Grpc.Core/Logging/ConsoleLogger.cs13
-rw-r--r--src/csharp/Grpc.Core/Logging/ILogger.cs6
-rw-r--r--src/csharp/Grpc.Core/Marshaller.cs23
-rw-r--r--src/csharp/Grpc.Core/Metadata.cs8
-rw-r--r--src/csharp/Grpc.Core/Method.cs60
-rw-r--r--src/csharp/Grpc.Core/RpcException.cs14
-rw-r--r--src/csharp/Grpc.Core/Server.cs2
-rw-r--r--src/csharp/Grpc.Core/ServerCredentials.cs2
-rw-r--r--src/csharp/Grpc.Core/ServerMethods.cs4
-rw-r--r--src/csharp/Grpc.Core/ServerPort.cs4
-rw-r--r--src/csharp/Grpc.Core/ServerServiceDefinition.cs8
-rw-r--r--src/csharp/Grpc.Core/Status.cs13
-rw-r--r--src/csharp/Grpc.Core/StatusCode.cs156
-rw-r--r--src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs9
-rw-r--r--src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs3
-rw-r--r--src/csharp/Grpc.Core/Utils/ExceptionHelper.cs57
-rw-r--r--src/csharp/Grpc.Core/Utils/Preconditions.cs25
-rw-r--r--src/csharp/Grpc.Core/Version.cs34
-rw-r--r--src/csharp/Grpc.Core/VersionInfo.cs37
-rw-r--r--src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs10
-rw-r--r--src/csharp/Grpc.Examples/MathExamples.cs10
-rw-r--r--src/csharp/Grpc.Examples/MathServiceImpl.cs7
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs8
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/app.config4
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/app.config4
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj38
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs86
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs4
-rw-r--r--src/csharp/Grpc.IntegrationTesting/app.config4
-rw-r--r--src/csharp/Grpc.IntegrationTesting/packages.config4
54 files changed, 751 insertions, 528 deletions
diff --git a/src/csharp/Grpc.Auth/GoogleCredential.cs b/src/csharp/Grpc.Auth/GoogleCredential.cs
deleted file mode 100644
index 9936cf583c..0000000000
--- a/src/csharp/Grpc.Auth/GoogleCredential.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-#region Copyright notice and license
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Security.Cryptography;
-using System.Threading;
-using System.Threading.Tasks;
-
-using Google.Apis.Auth.OAuth2;
-using Google.Apis.Auth.OAuth2.Responses;
-using Newtonsoft.Json.Linq;
-using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Security;
-
-namespace Grpc.Auth
-{
- // TODO(jtattermusch): Remove this class once possible.
- /// <summary>
- /// A temporary placeholder for Google credential from
- /// Google Auth library for .NET. It emulates the usage pattern
- /// for Usable auth.
- /// </summary>
- public class GoogleCredential
- {
- private const string GoogleApplicationCredentialsEnvName = "GOOGLE_APPLICATION_CREDENTIALS";
- private const string ClientEmailFieldName = "client_email";
- private const string PrivateKeyFieldName = "private_key";
-
- private ServiceCredential credential;
-
- private GoogleCredential(ServiceCredential credential)
- {
- this.credential = credential;
- }
-
- public static GoogleCredential GetApplicationDefault()
- {
- return new GoogleCredential(null);
- }
-
- public bool IsCreateScopedRequired
- {
- get
- {
- return true;
- }
- }
-
- public GoogleCredential CreateScoped(IEnumerable<string> scopes)
- {
- var credsPath = Environment.GetEnvironmentVariable(GoogleApplicationCredentialsEnvName);
- if (credsPath == null)
- {
- // Default to ComputeCredentials if path to JSON key is not set.
- // ComputeCredential is not scoped actually, but for our use case it's
- // fine to treat is as such.
- return new GoogleCredential(new ComputeCredential(new ComputeCredential.Initializer()));
- }
-
- JObject jsonCredentialParameters = JObject.Parse(File.ReadAllText(credsPath));
- string clientEmail = jsonCredentialParameters.GetValue(ClientEmailFieldName).Value<string>();
- string privateKeyString = jsonCredentialParameters.GetValue(PrivateKeyFieldName).Value<string>();
-
- var serviceCredential = new ServiceAccountCredential(
- new ServiceAccountCredential.Initializer(clientEmail)
- {
- Scopes = scopes,
- }.FromPrivateKey(privateKeyString));
- return new GoogleCredential(serviceCredential);
- }
-
- public Task<bool> RequestAccessTokenAsync(CancellationToken taskCancellationToken)
- {
- return credential.RequestAccessTokenAsync(taskCancellationToken);
- }
-
- public TokenResponse Token
- {
- get
- {
- return credential.Token;
- }
- }
-
- internal ServiceCredential InternalCredential
- {
- get
- {
- return credential;
- }
- }
- }
-}
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index 8e5036832d..930a34b0c3 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -11,7 +11,7 @@
<AssemblyName>Grpc.Auth</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<DocumentationFile>bin\$(Configuration)\Grpc.Auth.Xml</DocumentationFile>
- <NuGetPackageImportStamp>9b408026</NuGetPackageImportStamp>
+ <NuGetPackageImportStamp>4f8487a9</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -41,28 +41,32 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
- <Reference Include="BouncyCastle.Crypto">
+ <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth, Version=1.9.2.27817, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.2.27820, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Core, Version=1.9.2.27816, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Core.1.9.2\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks">
+ <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions">
+ <Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
+ <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
@@ -87,7 +91,6 @@
<Link>Version.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="GoogleCredential.cs" />
<Compile Include="OAuth2Interceptors.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
diff --git a/src/csharp/Grpc.Auth/OAuth2Interceptors.cs b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
index cc9d2c175f..d628a83246 100644
--- a/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
+++ b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
@@ -54,7 +54,7 @@ namespace Grpc.Auth
/// </summary>
public static MetadataInterceptorDelegate FromCredential(GoogleCredential googleCredential)
{
- var interceptor = new OAuth2Interceptor(googleCredential.InternalCredential, SystemClock.Default);
+ var interceptor = new OAuth2Interceptor(googleCredential, SystemClock.Default);
return new MetadataInterceptorDelegate(interceptor.InterceptHeaders);
}
@@ -66,7 +66,7 @@ namespace Grpc.Auth
public static MetadataInterceptorDelegate FromAccessToken(string oauth2Token)
{
Preconditions.CheckNotNull(oauth2Token);
- return new MetadataInterceptorDelegate((metadata) =>
+ return new MetadataInterceptorDelegate((authUri, metadata) =>
{
metadata.Add(OAuth2Interceptor.CreateBearerTokenHeader(oauth2Token));
});
@@ -80,10 +80,10 @@ namespace Grpc.Auth
private const string AuthorizationHeader = "Authorization";
private const string Schema = "Bearer";
- private ServiceCredential credential;
+ private ITokenAccess credential;
private IClock clock;
- public OAuth2Interceptor(ServiceCredential credential, IClock clock)
+ public OAuth2Interceptor(ITokenAccess credential, IClock clock)
{
this.credential = credential;
this.clock = clock;
@@ -94,23 +94,15 @@ namespace Grpc.Auth
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
- public string GetAccessToken(CancellationToken cancellationToken)
+ public string GetAccessToken(string authUri, CancellationToken cancellationToken)
{
- if (credential.Token == null || credential.Token.IsExpired(clock))
- {
- // TODO(jtattermusch): Parallel requests will spawn multiple requests to refresh the token once the token expires.
- // TODO(jtattermusch): Rethink synchronous wait to obtain the result.
- if (!credential.RequestAccessTokenAsync(cancellationToken).Result)
- {
- throw new InvalidOperationException("The access token has expired but we can't refresh it");
- }
- }
- return credential.Token.AccessToken;
+ // TODO(jtattermusch): Rethink synchronous wait to obtain the result.
+ return credential.GetAccessTokenForRequestAsync(authUri, cancellationToken: cancellationToken).GetAwaiter().GetResult();
}
- public void InterceptHeaders(Metadata metadata)
+ public void InterceptHeaders(string authUri, Metadata metadata)
{
- var accessToken = GetAccessToken(CancellationToken.None);
+ var accessToken = GetAccessToken(authUri, CancellationToken.None);
metadata.Add(CreateBearerTokenHeader(accessToken));
}
diff --git a/src/csharp/Grpc.Auth/app.config b/src/csharp/Grpc.Auth/app.config
index 0a82bb4f16..84d7534d65 100644
--- a/src/csharp/Grpc.Auth/app.config
+++ b/src/csharp/Grpc.Auth/app.config
@@ -10,6 +10,10 @@
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
</dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Google.Apis.Core" publicKeyToken="4b01fa6e34db77ab" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.9.2.38523" newVersion="1.9.2.38523" />
+ </dependentAssembly>
</assemblyBinding>
</runtime>
</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/packages.config b/src/csharp/Grpc.Auth/packages.config
index 29be953bf3..7a02c95db9 100644
--- a/src/csharp/Grpc.Auth/packages.config
+++ b/src/csharp/Grpc.Auth/packages.config
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
- <package id="Google.Apis.Auth" version="1.9.2" targetFramework="net45" />
- <package id="Google.Apis.Core" version="1.9.2" targetFramework="net45" />
+ <package id="Google.Apis.Auth" version="1.9.3" targetFramework="net45" />
+ <package id="Google.Apis.Core" version="1.9.3" targetFramework="net45" />
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
diff --git a/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs b/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
index df09857efe..52be77c846 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
@@ -67,9 +67,9 @@ namespace Grpc.Core.Internal.Tests
[Test]
public void ConstructorPreconditions()
{
- Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption(null, "abc"); });
- Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption(null, 1); });
- Assert.Throws(typeof(NullReferenceException), () => { new ChannelOption("abc", null); });
+ Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption(null, "abc"); });
+ Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption(null, 1); });
+ Assert.Throws(typeof(ArgumentNullException), () => { new ChannelOption("abc", null); });
}
[Test]
diff --git a/src/csharp/Grpc.Core.Tests/ChannelTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
index 60b45176e5..2787572924 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
@@ -50,7 +50,7 @@ namespace Grpc.Core.Tests
[Test]
public void Constructor_RejectsInvalidParams()
{
- Assert.Throws(typeof(NullReferenceException), () => new Channel(null, Credentials.Insecure));
+ Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, Credentials.Insecure));
}
[Test]
@@ -72,11 +72,11 @@ namespace Grpc.Core.Tests
}
[Test]
- public void Target()
+ public void ResolvedTarget()
{
using (var channel = new Channel("127.0.0.1", Credentials.Insecure))
{
- Assert.IsTrue(channel.Target.Contains("127.0.0.1"));
+ Assert.IsTrue(channel.ResolvedTarget.Contains("127.0.0.1"));
}
}
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index c5fc85b3fe..e49fdb5268 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -138,7 +138,7 @@ namespace Grpc.Core.Tests
helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
{
string result = "";
- await requestStream.ForEach(async (request) =>
+ await requestStream.ForEachAsync(async (request) =>
{
result += request;
});
@@ -147,7 +147,7 @@ namespace Grpc.Core.Tests
});
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);
}
@@ -159,7 +159,7 @@ namespace Grpc.Core.Tests
helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
{
barrier.SetResult(null);
- await requestStream.ToList();
+ await requestStream.ToListAsync();
return "";
});
diff --git a/src/csharp/Grpc.Core.Tests/CompressionTest.cs b/src/csharp/Grpc.Core.Tests/CompressionTest.cs
index ac0c3d6b5f..9547683f60 100644
--- a/src/csharp/Grpc.Core.Tests/CompressionTest.cs
+++ b/src/csharp/Grpc.Core.Tests/CompressionTest.cs
@@ -90,7 +90,7 @@ namespace Grpc.Core.Tests
{
helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) =>
{
- await requestStream.ToList();
+ await requestStream.ToListAsync();
context.WriteOptions = new WriteOptions(WriteFlags.NoCompress);
@@ -122,7 +122,7 @@ namespace Grpc.Core.Tests
await call.RequestStream.CompleteAsync();
- await call.ResponseStream.ToList();
+ await call.ResponseStream.ToListAsync();
}
}
}
diff --git a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
index a7f5075874..db5f953b0e 100644
--- a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
@@ -110,6 +110,14 @@ namespace Grpc.Core.Tests
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());
return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz");
});
@@ -118,5 +126,28 @@ namespace Grpc.Core.Tests
await call.RequestStream.CompleteAsync();
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);
+ }
}
}
diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
index b642286b11..bb69648d8b 100644
--- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
+++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
@@ -153,27 +153,23 @@ namespace Grpc.Core.Tests
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);
}
- 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);
}
- 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);
}
- 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);
}
diff --git a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs
index 8925041ba4..981b8ea3c8 100644
--- a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs
@@ -84,7 +84,7 @@ namespace Grpc.Core.Tests
{
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";
});
@@ -129,7 +129,7 @@ namespace Grpc.Core.Tests
});
var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
- var responses = await call.ResponseStream.ToList();
+ var responses = await call.ResponseStream.ToListAsync();
CollectionAssert.AreEqual(new[] { "A", "B" }, responses);
}
}
diff --git a/src/csharp/Grpc.Core/CallInvocationDetails.cs b/src/csharp/Grpc.Core/CallInvocationDetails.cs
index eb23a3a209..6565073fc5 100644
--- a/src/csharp/Grpc.Core/CallInvocationDetails.cs
+++ b/src/csharp/Grpc.Core/CallInvocationDetails.cs
@@ -40,30 +40,60 @@ namespace Grpc.Core
/// <summary>
/// Details about a client-side call to be invoked.
/// </summary>
- public class CallInvocationDetails<TRequest, TResponse>
+ public struct CallInvocationDetails<TRequest, TResponse>
{
readonly Channel channel;
readonly string method;
readonly string host;
readonly Marshaller<TRequest> requestMarshaller;
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) :
- 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)
{
- this.channel = Preconditions.CheckNotNull(channel);
- this.method = Preconditions.CheckNotNull(method);
+ this.channel = Preconditions.CheckNotNull(channel, "channel");
+ this.method = Preconditions.CheckNotNull(method, "method");
this.host = host;
- this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller);
- this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller);
- this.options = Preconditions.CheckNotNull(options);
+ this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller, "requestMarshaller");
+ this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller, "responseMarshaller");
+ this.options = options;
}
+ /// <summary>
+ /// Get channel associated with this call.
+ /// </summary>
public Channel Channel
{
get
@@ -72,6 +102,9 @@ namespace Grpc.Core
}
}
+ /// <summary>
+ /// Gets name of method to be called.
+ /// </summary>
public string Method
{
get
@@ -80,6 +113,9 @@ namespace Grpc.Core
}
}
+ /// <summary>
+ /// Get name of host.
+ /// </summary>
public string Host
{
get
@@ -88,6 +124,9 @@ namespace Grpc.Core
}
}
+ /// <summary>
+ /// Gets marshaller used to serialize requests.
+ /// </summary>
public Marshaller<TRequest> RequestMarshaller
{
get
@@ -96,6 +135,9 @@ namespace Grpc.Core
}
}
+ /// <summary>
+ /// Gets marshaller used to deserialized responses.
+ /// </summary>
public Marshaller<TResponse> ResponseMarshaller
{
get
@@ -104,6 +146,9 @@ namespace Grpc.Core
}
}
+ /// <summary>
+ /// Gets the call options.
+ /// </summary>
public CallOptions Options
{
get
@@ -111,5 +156,16 @@ namespace Grpc.Core
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;
+ }
}
}
diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs
index 0d82b5a28e..3dfe80b48c 100644
--- a/src/csharp/Grpc.Core/CallOptions.cs
+++ b/src/csharp/Grpc.Core/CallOptions.cs
@@ -42,29 +42,28 @@ namespace Grpc.Core
/// <summary>
/// Options for calls made by client.
/// </summary>
- public class CallOptions
+ public struct CallOptions
{
- readonly Metadata headers;
- readonly DateTime deadline;
- readonly CancellationToken cancellationToken;
- readonly WriteOptions writeOptions;
- readonly ContextPropagationToken propagationToken;
+ Metadata headers;
+ DateTime? deadline;
+ CancellationToken cancellationToken;
+ WriteOptions writeOptions;
+ ContextPropagationToken propagationToken;
/// <summary>
- /// Creates a new instance of <c>CallOptions</c>.
+ /// Creates a new instance of <c>CallOptions</c> struct.
/// </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>
/// <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>
- 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)
{
- // TODO(jtattermusch): consider only creating metadata object once it's really needed.
- this.headers = headers ?? new Metadata();
- this.deadline = deadline ?? (propagationToken != null ? propagationToken.Deadline : DateTime.MaxValue);
- this.cancellationToken = cancellationToken ?? (propagationToken != null ? propagationToken.CancellationToken : CancellationToken.None);
+ this.headers = headers;
+ this.deadline = deadline;
+ this.cancellationToken = cancellationToken;
this.writeOptions = writeOptions;
this.propagationToken = propagationToken;
}
@@ -80,7 +79,7 @@ namespace Grpc.Core
/// <summary>
/// Call deadline.
/// </summary>
- public DateTime Deadline
+ public DateTime? Deadline
{
get { return deadline; }
}
@@ -114,5 +113,66 @@ namespace Grpc.Core
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;
+ }
}
}
diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs
index 00a8cabf82..7067456638 100644
--- a/src/csharp/Grpc.Core/Calls.cs
+++ b/src/csharp/Grpc.Core/Calls.cs
@@ -31,8 +31,6 @@
#endregion
-using System;
-using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
@@ -40,9 +38,20 @@ namespace Grpc.Core
{
/// <summary>
/// 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>
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)
where TRequest : class
where TResponse : class
@@ -51,6 +60,14 @@ namespace Grpc.Core
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)
where TRequest : class
where TResponse : class
@@ -60,6 +77,15 @@ namespace Grpc.Core
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)
where TRequest : class
where TResponse : class
@@ -70,6 +96,13 @@ namespace Grpc.Core
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)
where TRequest : class
where TResponse : class
@@ -80,6 +113,15 @@ namespace Grpc.Core
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)
where TRequest : class
where TResponse : class
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index 9273ea4582..64c6adf2bf 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -49,6 +49,7 @@ namespace Grpc.Core
{
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<Channel>();
+ readonly string target;
readonly GrpcEnvironment environment;
readonly ChannelSafeHandle handle;
readonly List<ChannelOption> options;
@@ -58,12 +59,12 @@ namespace Grpc.Core
/// Creates a channel that connects to a specific host.
/// Port will default to 80 for an unsecure channel and to 443 for a secure channel.
/// </summary>
- /// <param name="host">The name or IP address of the host.</param>
+ /// <param name="target">Target of the channel.</param>
/// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
- public Channel(string host, Credentials credentials, IEnumerable<ChannelOption> options = null)
+ public Channel(string target, Credentials credentials, IEnumerable<ChannelOption> options = null)
{
- Preconditions.CheckNotNull(host);
+ this.target = Preconditions.CheckNotNull(target, "target");
this.environment = GrpcEnvironment.GetInstance();
this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
@@ -73,11 +74,11 @@ namespace Grpc.Core
{
if (nativeCredentials != null)
{
- this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, host, nativeChannelArgs);
+ this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, target, nativeChannelArgs);
}
else
{
- this.handle = ChannelSafeHandle.CreateInsecure(host, nativeChannelArgs);
+ this.handle = ChannelSafeHandle.CreateInsecure(target, nativeChannelArgs);
}
}
}
@@ -131,8 +132,8 @@ namespace Grpc.Core
return tcs.Task;
}
- /// <summary> Address of the remote endpoint in URI format.</summary>
- public string Target
+ /// <summary>Resolved address of the remote endpoint in URI format.</summary>
+ public string ResolvedTarget
{
get
{
@@ -140,6 +141,15 @@ namespace Grpc.Core
}
}
+ /// <summary>The original target used to create the channel.</summary>
+ public string Target
+ {
+ get
+ {
+ return this.target;
+ }
+ }
+
/// <summary>
/// Allows explicitly requesting channel to connect without starting an RPC.
/// Returned task completes once state Ready was seen. If the deadline is reached,
diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs
index 1e0f90287a..0cb2953f2c 100644
--- a/src/csharp/Grpc.Core/ChannelOptions.cs
+++ b/src/csharp/Grpc.Core/ChannelOptions.cs
@@ -63,8 +63,8 @@ namespace Grpc.Core
public ChannelOption(string name, string stringValue)
{
this.type = OptionType.String;
- this.name = Preconditions.CheckNotNull(name);
- this.stringValue = Preconditions.CheckNotNull(stringValue);
+ this.name = Preconditions.CheckNotNull(name, "name");
+ this.stringValue = Preconditions.CheckNotNull(stringValue, "stringValue");
}
/// <summary>
@@ -75,7 +75,7 @@ namespace Grpc.Core
public ChannelOption(string name, int intValue)
{
this.type = OptionType.Integer;
- this.name = Preconditions.CheckNotNull(name);
+ this.name = Preconditions.CheckNotNull(name, "name");
this.intValue = intValue;
}
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index 88494bb4ac..f46184406c 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -35,21 +35,26 @@ using System;
using System.Collections.Generic;
using Grpc.Core.Internal;
+using System.Text.RegularExpressions;
namespace Grpc.Core
{
- public delegate void MetadataInterceptorDelegate(Metadata metadata);
+ public delegate void MetadataInterceptorDelegate(string authUri, Metadata metadata);
/// <summary>
/// Base class for client-side stubs.
/// </summary>
public abstract class ClientBase
{
+ static readonly Regex TrailingPortPattern = new Regex(":[0-9]+/?$");
readonly Channel channel;
+ readonly string authUriBase;
public ClientBase(Channel channel)
{
this.channel = channel;
+ // TODO(jtattermush): we shouldn't need to hand-curate the channel.Target contents.
+ this.authUriBase = "https://" + TrailingPortPattern.Replace(channel.Target, "") + "/";
}
/// <summary>
@@ -63,6 +68,18 @@ namespace Grpc.Core
}
/// <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>
/// Channel associated with this client.
/// </summary>
public Channel Channel
@@ -83,10 +100,14 @@ namespace Grpc.Core
var interceptor = HeaderInterceptor;
if (interceptor != null)
{
- interceptor(options.Headers);
- options.Headers.Freeze();
+ if (options.Headers == null)
+ {
+ options = options.WithHeaders(new Metadata());
+ }
+ var authUri = authUriBase + method.ServiceName;
+ interceptor(authUri, options.Headers);
}
- return new CallInvocationDetails<TRequest, TResponse>(channel, method, options);
+ return new CallInvocationDetails<TRequest, TResponse>(channel, method, Host, options);
}
}
}
diff --git a/src/csharp/Grpc.Core/ContextPropagationToken.cs b/src/csharp/Grpc.Core/ContextPropagationToken.cs
index b6ea5115a4..2e4bfc9e47 100644
--- a/src/csharp/Grpc.Core/ContextPropagationToken.cs
+++ b/src/csharp/Grpc.Core/ContextPropagationToken.cs
@@ -52,7 +52,7 @@ namespace Grpc.Core
/// <summary>
/// Default propagation mask used by C core.
/// </summary>
- const ContextPropagationFlags DefaultCoreMask = (ContextPropagationFlags)0xffff;
+ private const ContextPropagationFlags DefaultCoreMask = (ContextPropagationFlags)0xffff;
/// <summary>
/// Default propagation mask used by C# - we want to propagate deadline
@@ -74,6 +74,9 @@ namespace Grpc.Core
this.options = options ?? ContextPropagationOptions.Default;
}
+ /// <summary>
+ /// Gets the native handle of the parent call.
+ /// </summary>
internal CallSafeHandle ParentCall
{
get
@@ -82,7 +85,10 @@ namespace Grpc.Core
}
}
- internal DateTime Deadline
+ /// <summary>
+ /// Gets the parent call's deadline.
+ /// </summary>
+ internal DateTime ParentDeadline
{
get
{
@@ -90,7 +96,10 @@ namespace Grpc.Core
}
}
- internal CancellationToken CancellationToken
+ /// <summary>
+ /// Gets the parent call's cancellation token.
+ /// </summary>
+ internal CancellationToken ParentCancellationToken
{
get
{
@@ -98,6 +107,9 @@ namespace Grpc.Core
}
}
+ /// <summary>
+ /// Get the context propagation options.
+ /// </summary>
internal ContextPropagationOptions Options
{
get
@@ -105,16 +117,6 @@ namespace Grpc.Core
return this.options;
}
}
-
- internal bool IsPropagateDeadline
- {
- get { return false; }
- }
-
- internal bool IsPropagateCancellation
- {
- get { return false; }
- }
}
/// <summary>
@@ -122,7 +124,37 @@ namespace Grpc.Core
/// </summary>
public class ContextPropagationOptions
{
+ /// <summary>
+ /// The context propagation options that will be used by default.
+ /// </summary>
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>
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index e535c47f55..9a8195e9d0 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -77,7 +77,6 @@
<Compile Include="ServerServiceDefinition.cs" />
<Compile Include="Utils\AsyncStreamExtensions.cs" />
<Compile Include="Utils\BenchmarkUtil.cs" />
- <Compile Include="Utils\ExceptionHelper.cs" />
<Compile Include="Internal\CredentialsSafeHandle.cs" />
<Compile Include="Credentials.cs" />
<Compile Include="Internal\ChannelArgsSafeHandle.cs" />
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index 1bb83c9962..30d8c80235 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -115,7 +115,7 @@ namespace Grpc.Core
/// </summary>
public static void SetLogger(ILogger customLogger)
{
- Preconditions.CheckNotNull(customLogger);
+ Preconditions.CheckNotNull(customLogger, "customLogger");
logger = customLogger;
}
@@ -192,23 +192,5 @@ namespace Grpc.Core
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.");
- }
- });
- }
}
}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 0db9d2a515..2c3e3d75ea 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -63,7 +63,7 @@ namespace Grpc.Core.Internal
public AsyncCall(CallInvocationDetails<TRequest, TResponse> callDetails)
: 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.
}
@@ -109,15 +109,9 @@ namespace Grpc.Core.Internal
}
}
- try
- {
- // Once the blocking call returns, the result should be available synchronously.
- return unaryResponseTcs.Task.Result;
- }
- catch (AggregateException ae)
- {
- throw ExceptionHelper.UnwrapRpcException(ae);
- }
+ // Once the blocking call returns, the result should be available synchronously.
+ // Note that GetAwaiter().GetResult() doesn't wrap exceptions in AggregateException.
+ return unaryResponseTcs.Task.GetAwaiter().GetResult();
}
}
@@ -324,12 +318,11 @@ namespace Grpc.Core.Internal
private void Initialize(CompletionQueueSafeHandle cq)
{
- var propagationToken = details.Options.PropagationToken;
- var parentCall = propagationToken != null ? propagationToken.ParentCall : CallSafeHandle.NullInstance;
+ var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance;
var call = details.Channel.Handle.CreateCall(details.Channel.Environment.CompletionRegistry,
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();
InitializeInternal(call);
RegisterCancellationCallback();
diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs
index e83d21f4a4..daf85d5f61 100644
--- a/src/csharp/Grpc.Core/Internal/Timespec.cs
+++ b/src/csharp/Grpc.Core/Internal/Timespec.cs
@@ -211,7 +211,7 @@ namespace Grpc.Core.Internal
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
{
diff --git a/src/csharp/Grpc.Core/KeyCertificatePair.cs b/src/csharp/Grpc.Core/KeyCertificatePair.cs
index 5def15a656..6f691975e9 100644
--- a/src/csharp/Grpc.Core/KeyCertificatePair.cs
+++ b/src/csharp/Grpc.Core/KeyCertificatePair.cs
@@ -54,8 +54,8 @@ namespace Grpc.Core
/// <param name="privateKey">PEM encoded private key.</param>
public KeyCertificatePair(string certificateChain, string privateKey)
{
- this.certificateChain = Preconditions.CheckNotNull(certificateChain);
- this.privateKey = Preconditions.CheckNotNull(privateKey);
+ this.certificateChain = Preconditions.CheckNotNull(certificateChain, "certificateChain");
+ this.privateKey = Preconditions.CheckNotNull(privateKey, "privateKey");
}
/// <summary>
diff --git a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
index c67765c78d..382481d871 100644
--- a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
+++ b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
@@ -42,16 +42,21 @@ namespace Grpc.Core.Logging
readonly Type forType;
readonly string forTypeString;
+ /// <summary>Creates a console logger not associated to any specific type.</summary>
public ConsoleLogger() : this(null)
{
}
+ /// <summary>Creates a console logger that logs messsage specific for given type.</summary>
private ConsoleLogger(Type forType)
{
this.forType = forType;
this.forTypeString = forType != null ? forType.FullName + " " : "";
}
-
+
+ /// <summary>
+ /// Returns a logger associated with the specified type.
+ /// </summary>
public ILogger ForType<T>()
{
if (typeof(T) == forType)
@@ -61,31 +66,37 @@ namespace Grpc.Core.Logging
return new ConsoleLogger(typeof(T));
}
+ /// <summary>Logs a message with severity Debug.</summary>
public void Debug(string message, params object[] formatArgs)
{
Log("D", message, formatArgs);
}
+ /// <summary>Logs a message with severity Info.</summary>
public void Info(string message, params object[] formatArgs)
{
Log("I", message, formatArgs);
}
+ /// <summary>Logs a message with severity Warning.</summary>
public void Warning(string message, params object[] 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)
{
Log("W", message + " " + exception, formatArgs);
}
+ /// <summary>Logs a message with severity Error.</summary>
public void Error(string message, params object[] 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)
{
Log("E", message + " " + exception, formatArgs);
diff --git a/src/csharp/Grpc.Core/Logging/ILogger.cs b/src/csharp/Grpc.Core/Logging/ILogger.cs
index 0d58f133e3..61e0c91388 100644
--- a/src/csharp/Grpc.Core/Logging/ILogger.cs
+++ b/src/csharp/Grpc.Core/Logging/ILogger.cs
@@ -42,16 +42,22 @@ namespace Grpc.Core.Logging
/// <summary>Returns a logger associated with the specified type.</summary>
ILogger ForType<T>();
+ /// <summary>Logs a message with severity Debug.</summary>
void Debug(string message, params object[] formatArgs);
+ /// <summary>Logs a message with severity Info.</summary>
void Info(string message, params object[] formatArgs);
+ /// <summary>Logs a message with severity Warning.</summary>
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);
+ /// <summary>Logs a message with severity Error.</summary>
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);
}
}
diff --git a/src/csharp/Grpc.Core/Marshaller.cs b/src/csharp/Grpc.Core/Marshaller.cs
index 8b1a929074..f38cb0863f 100644
--- a/src/csharp/Grpc.Core/Marshaller.cs
+++ b/src/csharp/Grpc.Core/Marshaller.cs
@@ -37,19 +37,27 @@ using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
- /// For serializing and deserializing messages.
+ /// Encapsulates the logic for serializing and deserializing messages.
/// </summary>
public struct Marshaller<T>
{
readonly Func<T, byte[]> serializer;
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)
{
- this.serializer = Preconditions.CheckNotNull(serializer);
- this.deserializer = Preconditions.CheckNotNull(deserializer);
+ this.serializer = Preconditions.CheckNotNull(serializer, "serializer");
+ this.deserializer = Preconditions.CheckNotNull(deserializer, "deserializer");
}
+ /// <summary>
+ /// Gets the serializer function.
+ /// </summary>
public Func<T, byte[]> Serializer
{
get
@@ -58,6 +66,9 @@ namespace Grpc.Core
}
}
+ /// <summary>
+ /// Gets the deserializer function.
+ /// </summary>
public Func<byte[], T> Deserializer
{
get
@@ -72,11 +83,17 @@ namespace Grpc.Core
/// </summary>
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)
{
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
{
get
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
index a58dbdbc93..9db2abf46e 100644
--- a/src/csharp/Grpc.Core/Metadata.cs
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -186,15 +186,15 @@ namespace Grpc.Core
public Entry(string key, byte[] valueBytes)
{
- this.key = Preconditions.CheckNotNull(key);
+ this.key = Preconditions.CheckNotNull(key, "key");
this.value = null;
- this.valueBytes = Preconditions.CheckNotNull(valueBytes);
+ this.valueBytes = Preconditions.CheckNotNull(valueBytes, "valueBytes");
}
public Entry(string key, string value)
{
- this.key = Preconditions.CheckNotNull(key);
- this.value = Preconditions.CheckNotNull(value);
+ this.key = Preconditions.CheckNotNull(key, "key");
+ this.value = Preconditions.CheckNotNull(value, "value");
this.valueBytes = null;
}
diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs
index cc047ac9f8..4c208b4a26 100644
--- a/src/csharp/Grpc.Core/Method.cs
+++ b/src/csharp/Grpc.Core/Method.cs
@@ -41,14 +41,21 @@ namespace Grpc.Core
/// </summary>
public enum MethodType
{
- Unary, // Unary request, unary response.
- ClientStreaming, // Streaming request, unary response.
- ServerStreaming, // Unary request, streaming response.
- DuplexStreaming // Streaming request, streaming response.
+ /// <summary>Single request sent from client, single response received from server.</summary>
+ Unary,
+
+ /// <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>
- /// A description of a service method.
+ /// A description of a remote method.
/// </summary>
public class Method<TRequest, TResponse>
{
@@ -59,16 +66,27 @@ namespace Grpc.Core
readonly Marshaller<TResponse> responseMarshaller;
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)
{
this.type = type;
- this.serviceName = Preconditions.CheckNotNull(serviceName);
- this.name = Preconditions.CheckNotNull(name);
- this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller);
- this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller);
- this.fullName = GetFullName(serviceName);
+ this.serviceName = Preconditions.CheckNotNull(serviceName, "serviceName");
+ this.name = Preconditions.CheckNotNull(name, "name");
+ this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller, "requestMarshaller");
+ this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller, "responseMarshaller");
+ this.fullName = GetFullName(serviceName, name);
}
+ /// <summary>
+ /// Gets the type of the method.
+ /// </summary>
public MethodType Type
{
get
@@ -77,6 +95,9 @@ namespace Grpc.Core
}
}
+ /// <summary>
+ /// Gets the name of the service to which this method belongs.
+ /// </summary>
public string ServiceName
{
get
@@ -85,6 +106,9 @@ namespace Grpc.Core
}
}
+ /// <summary>
+ /// Gets the unqualified name of the method.
+ /// </summary>
public string Name
{
get
@@ -93,6 +117,9 @@ namespace Grpc.Core
}
}
+ /// <summary>
+ /// Gets the marshaller used for request messages.
+ /// </summary>
public Marshaller<TRequest> RequestMarshaller
{
get
@@ -101,6 +128,9 @@ namespace Grpc.Core
}
}
+ /// <summary>
+ /// Gets the marshaller used for response messages.
+ /// </summary>
public Marshaller<TResponse> ResponseMarshaller
{
get
@@ -108,7 +138,11 @@ namespace Grpc.Core
return this.responseMarshaller;
}
}
-
+
+ /// <summary>
+ /// Gets the fully qualified name of the method. On the server side, methods are dispatched
+ /// based on this name.
+ /// </summary>
public string FullName
{
get
@@ -120,9 +154,9 @@ namespace Grpc.Core
/// <summary>
/// Gets full name of the method including the service name.
/// </summary>
- internal string GetFullName(string serviceName)
+ internal static string GetFullName(string serviceName, string methodName)
{
- return "/" + Preconditions.CheckNotNull(serviceName) + "/" + this.Name;
+ return "/" + serviceName + "/" + methodName;
}
}
}
diff --git a/src/csharp/Grpc.Core/RpcException.cs b/src/csharp/Grpc.Core/RpcException.cs
index c58578286b..cac417e626 100644
--- a/src/csharp/Grpc.Core/RpcException.cs
+++ b/src/csharp/Grpc.Core/RpcException.cs
@@ -36,22 +36,34 @@ using System;
namespace Grpc.Core
{
/// <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>
public class RpcException : Exception
{
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())
{
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)
{
this.status = status;
}
+ /// <summary>
+ /// Resulting status of the call.
+ /// </summary>
public Status Status
{
get
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index eb5b043d1c..c76f126026 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -192,7 +192,7 @@ namespace Grpc.Core
{
lock (myLock)
{
- Preconditions.CheckNotNull(serverPort.Credentials);
+ Preconditions.CheckNotNull(serverPort.Credentials, "serverPort");
Preconditions.CheckState(!startRequested);
var address = string.Format("{0}:{1}", serverPort.Host, serverPort.Port);
int boundPort;
diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs
index c11a1ede08..3c6703d30e 100644
--- a/src/csharp/Grpc.Core/ServerCredentials.cs
+++ b/src/csharp/Grpc.Core/ServerCredentials.cs
@@ -91,7 +91,7 @@ namespace Grpc.Core
{
this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly();
Preconditions.CheckArgument(this.keyCertificatePairs.Count > 0,
- "At least one KeyCertificatePair needs to be provided");
+ "At least one KeyCertificatePair needs to be provided.");
if (forceClientAuth)
{
Preconditions.CheckNotNull(rootCertificates,
diff --git a/src/csharp/Grpc.Core/ServerMethods.cs b/src/csharp/Grpc.Core/ServerMethods.cs
index d457770203..1f119a80ff 100644
--- a/src/csharp/Grpc.Core/ServerMethods.cs
+++ b/src/csharp/Grpc.Core/ServerMethods.cs
@@ -31,12 +31,8 @@
#endregion
-using System;
-using System.Threading;
using System.Threading.Tasks;
-using Grpc.Core.Internal;
-
namespace Grpc.Core
{
/// <summary>
diff --git a/src/csharp/Grpc.Core/ServerPort.cs b/src/csharp/Grpc.Core/ServerPort.cs
index 55e4bd0062..598404d045 100644
--- a/src/csharp/Grpc.Core/ServerPort.cs
+++ b/src/csharp/Grpc.Core/ServerPort.cs
@@ -62,9 +62,9 @@ namespace Grpc.Core
/// <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.host = Preconditions.CheckNotNull(host, "host");
this.port = port;
- this.credentials = Preconditions.CheckNotNull(credentials);
+ this.credentials = Preconditions.CheckNotNull(credentials, "credentials");
}
/// <summary>
diff --git a/src/csharp/Grpc.Core/ServerServiceDefinition.cs b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
index a00d156e52..94b0a320c3 100644
--- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs
+++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
@@ -79,7 +79,7 @@ namespace Grpc.Core
where TRequest : class
where TResponse : class
{
- callHandlers.Add(method.GetFullName(serviceName), ServerCalls.UnaryCall(method, handler));
+ callHandlers.Add(method.FullName, ServerCalls.UnaryCall(method, handler));
return this;
}
@@ -89,7 +89,7 @@ namespace Grpc.Core
where TRequest : class
where TResponse : class
{
- callHandlers.Add(method.GetFullName(serviceName), ServerCalls.ClientStreamingCall(method, handler));
+ callHandlers.Add(method.FullName, ServerCalls.ClientStreamingCall(method, handler));
return this;
}
@@ -99,7 +99,7 @@ namespace Grpc.Core
where TRequest : class
where TResponse : class
{
- callHandlers.Add(method.GetFullName(serviceName), ServerCalls.ServerStreamingCall(method, handler));
+ callHandlers.Add(method.FullName, ServerCalls.ServerStreamingCall(method, handler));
return this;
}
@@ -109,7 +109,7 @@ namespace Grpc.Core
where TRequest : class
where TResponse : class
{
- callHandlers.Add(method.GetFullName(serviceName), ServerCalls.DuplexStreamingCall(method, handler));
+ callHandlers.Add(method.FullName, ServerCalls.DuplexStreamingCall(method, handler));
return this;
}
diff --git a/src/csharp/Grpc.Core/Status.cs b/src/csharp/Grpc.Core/Status.cs
index 754f6cb3ca..6bd8dc820b 100644
--- a/src/csharp/Grpc.Core/Status.cs
+++ b/src/csharp/Grpc.Core/Status.cs
@@ -29,13 +29,12 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
-using System;
-using System.Runtime.InteropServices;
+using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
- /// Represents RPC result.
+ /// Represents RPC result, which consists of <see cref="StatusCode"/> and an optional detail string.
/// </summary>
public struct Status
{
@@ -52,6 +51,11 @@ namespace Grpc.Core
readonly StatusCode statusCode;
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)
{
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()
{
return string.Format("Status(StatusCode={0}, Detail=\"{1}\")", statusCode, detail);
diff --git a/src/csharp/Grpc.Core/StatusCode.cs b/src/csharp/Grpc.Core/StatusCode.cs
index a9696fa469..90606955af 100644
--- a/src/csharp/Grpc.Core/StatusCode.cs
+++ b/src/csharp/Grpc.Core/StatusCode.cs
@@ -31,8 +31,6 @@
#endregion
-using System;
-
namespace Grpc.Core
{
/// <summary>
@@ -41,101 +39,101 @@ namespace Grpc.Core
/// </summary>
public enum StatusCode
{
- /* Not an error; returned on success */
+ /// <summary>Not an error; returned on success.</summary>
OK = 0,
- /* The operation was cancelled (typically by the caller). */
+
+ /// <summary>The operation was cancelled (typically by the caller).</summary>
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
- 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 error. An example of where this error may be returned is
+ /// if a Status value received from another address space belongs to
+ /// 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,
- /* Client specified an invalid argument. Note that this differs
- from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments
- that are problematic regardless of the state of the system
- (e.g., a malformed file name). */
+
+ /// <summary>
+ /// Client specified an invalid argument. Note that this differs
+ /// 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,
- /* Deadline expired before operation could complete. For operations
- that change the state of the system, this error may be returned
- 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>
+ /// Deadline expired before operation could complete. For operations
+ /// that change the state of the system, this error may be returned
+ /// 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,
- /* 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,
- /* 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,
- /* The caller does not have permission to execute the specified
- operation. PERMISSION_DENIED must not be used for rejections
- caused by exhausting some resource (use RESOURCE_EXHAUSTED
- instead for those errors). PERMISSION_DENIED must not be
- used if the caller can not be identified (use UNAUTHENTICATED
- instead for those errors). */
+
+ /// <summary>
+ /// The caller does not have permission to execute the specified
+ /// operation. PERMISSION_DENIED must not be used for rejections
+ /// caused by exhausting some resource (use RESOURCE_EXHAUSTED
+ /// 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,
- /* 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,
- /* 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,
- /* Operation was rejected because the system is not in a state
- required for the operation's execution. For example, directory
- to be deleted may be non-empty, an rmdir operation is applied to
- a non-directory, etc.
-
- A litmus test that may help a service implementor in deciding
- between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
- (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. */
+
+ /// <summary>
+ /// Operation was rejected because the system is not in a state
+ /// required for the operation's execution. For example, directory
+ /// to be deleted may be non-empty, an rmdir operation is applied to
+ /// a non-directory, etc.
+ /// </summary>
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,
- ABORTED, and UNAVAILABLE. */
+ /// <summary>
+ /// The operation was aborted, typically due to a concurrency issue
+ /// like sequencer check failures, transaction aborts, etc.
+ /// </summary>
Aborted = 10,
- /* Operation was attempted past the valid range. E.g., seeking or
- reading past end of file.
-
- Unlike INVALID_ARGUMENT, this error indicates a problem that may
- be fixed if the system state changes. For example, a 32-bit file
- 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. */
+
+ /// <summary>
+ /// Operation was attempted past the valid range. E.g., seeking or
+ /// reading past end of file.
+ /// </summary>
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,
- /* 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 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,
- /* 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,
- ABORTED, and UNAVAILABLE. */
+ /// <summary>
+ /// 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,
- /* Unrecoverable data loss or corruption. */
+
+ /// <summary>Unrecoverable data loss or corruption.</summary>
DataLoss = 15
}
}
diff --git a/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs b/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs
index 8a748b45a8..cdf1e51026 100644
--- a/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs
+++ b/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs
@@ -33,7 +33,6 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
namespace Grpc.Core.Utils
@@ -46,7 +45,7 @@ namespace Grpc.Core.Utils
/// <summary>
/// Reads the entire stream and executes an async action for each element.
/// </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
{
while (await streamReader.MoveNext())
@@ -58,7 +57,7 @@ namespace Grpc.Core.Utils
/// <summary>
/// Reads the entire stream and creates a list containing all the elements read.
/// </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
{
var result = new List<T>();
@@ -73,7 +72,7 @@ namespace Grpc.Core.Utils
/// Writes all elements from given enumerable to the stream.
/// Completes the stream afterwards unless close = false.
/// </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
{
foreach (var element in elements)
@@ -89,7 +88,7 @@ namespace Grpc.Core.Utils
/// <summary>
/// Writes all elements from given enumerable to the stream.
/// </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
{
foreach (var element in elements)
diff --git a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
index 82653c3a1f..eb3a5b16e3 100644
--- a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
+++ b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
@@ -39,6 +39,9 @@ using System.Threading.Tasks;
namespace Grpc.Core.Utils
{
+ /// <summary>
+ /// Utility methods to run microbenchmarks.
+ /// </summary>
public static class BenchmarkUtil
{
/// <summary>
diff --git a/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs b/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs
deleted file mode 100644
index c4d6bee058..0000000000
--- a/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs
+++ /dev/null
@@ -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;
- }
- }
-}
diff --git a/src/csharp/Grpc.Core/Utils/Preconditions.cs b/src/csharp/Grpc.Core/Utils/Preconditions.cs
index aeb5d210a7..374262f87a 100644
--- a/src/csharp/Grpc.Core/Utils/Preconditions.cs
+++ b/src/csharp/Grpc.Core/Utils/Preconditions.cs
@@ -32,17 +32,16 @@
#endregion
using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Threading.Tasks;
namespace Grpc.Core.Utils
{
+ /// <summary>
+ /// Utility methods to simplify checking preconditions in the code.
+ /// </summary>
public static class Preconditions
{
/// <summary>
- /// Throws ArgumentException if condition is false.
+ /// Throws <see cref="ArgumentException"/> if condition is false.
/// </summary>
public static void CheckArgument(bool condition)
{
@@ -53,7 +52,7 @@ namespace Grpc.Core.Utils
}
/// <summary>
- /// Throws ArgumentException with given message if condition is false.
+ /// Throws <see cref="ArgumentException"/> with given message if condition is false.
/// </summary>
public static void CheckArgument(bool condition, string errorMessage)
{
@@ -64,31 +63,31 @@ namespace Grpc.Core.Utils
}
/// <summary>
- /// Throws NullReferenceException if reference is null.
+ /// Throws <see cref="ArgumentNullException"/> if reference is null.
/// </summary>
public static T CheckNotNull<T>(T reference)
{
if (reference == null)
{
- throw new NullReferenceException();
+ throw new ArgumentNullException();
}
return reference;
}
/// <summary>
- /// Throws NullReferenceException with given message if reference is null.
+ /// Throws <see cref="ArgumentNullException"/> if reference is null.
/// </summary>
- public static T CheckNotNull<T>(T reference, string errorMessage)
+ public static T CheckNotNull<T>(T reference, string paramName)
{
if (reference == null)
{
- throw new NullReferenceException(errorMessage);
+ throw new ArgumentNullException(paramName);
}
return reference;
}
/// <summary>
- /// Throws InvalidOperationException if condition is false.
+ /// Throws <see cref="InvalidOperationException"/> if condition is false.
/// </summary>
public static void CheckState(bool condition)
{
@@ -99,7 +98,7 @@ namespace Grpc.Core.Utils
}
/// <summary>
- /// Throws InvalidOperationException with given message if condition is false.
+ /// Throws <see cref="InvalidOperationException"/> with given message if condition is false.
/// </summary>
public static void CheckState(bool condition, string errorMessage)
{
diff --git a/src/csharp/Grpc.Core/Version.cs b/src/csharp/Grpc.Core/Version.cs
index d2a029fbb4..d02b301cac 100644
--- a/src/csharp/Grpc.Core/Version.cs
+++ b/src/csharp/Grpc.Core/Version.cs
@@ -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.Runtime.CompilerServices;
// The current version of gRPC C#.
[assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentVersion + ".0")]
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index 939372e237..b6dbd3b49c 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -1,8 +1,41 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
+#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
namespace Grpc.Core
{
+ /// <summary>
+ /// Provides info about current version of gRPC.
+ /// </summary>
public static class VersionInfo
{
/// <summary>
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index 73d2a1ca9b..fdef950f09 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -109,7 +109,7 @@ namespace math.Tests
{
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 },
responses.ConvertAll((n) => n.Num_));
}
@@ -151,7 +151,7 @@ namespace math.Tests
using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(),
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.
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(
n => Num.CreateBuilder().SetNum_(n).Build());
- await call.RequestStream.WriteAll(numbers);
+ await call.RequestStream.WriteAllAsync(numbers);
var result = await call.ResponseAsync;
Assert.AreEqual(60, result.Num_);
}
@@ -185,8 +185,8 @@ namespace math.Tests
using (var call = client.DivMany())
{
- await call.RequestStream.WriteAll(divArgsList);
- var result = await call.ResponseStream.ToList();
+ await call.RequestStream.WriteAllAsync(divArgsList);
+ var result = await call.ResponseStream.ToListAsync();
CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient));
CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder));
diff --git a/src/csharp/Grpc.Examples/MathExamples.cs b/src/csharp/Grpc.Examples/MathExamples.cs
index 06d81a4d83..dc1bf43995 100644
--- a/src/csharp/Grpc.Examples/MathExamples.cs
+++ b/src/csharp/Grpc.Examples/MathExamples.cs
@@ -54,7 +54,7 @@ namespace math
{
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));
}
}
@@ -70,7 +70,7 @@ namespace math
using (var call = client.Sum())
{
- await call.RequestStream.WriteAll(numbers);
+ await call.RequestStream.WriteAllAsync(numbers);
Console.WriteLine("Sum Result: " + await call.ResponseAsync);
}
}
@@ -85,8 +85,8 @@ namespace math
};
using (var call = client.DivMany())
{
- await call.RequestStream.WriteAll(divArgsList);
- Console.WriteLine("DivMany Result: " + string.Join("|", await call.ResponseStream.ToList()));
+ await call.RequestStream.WriteAllAsync(divArgsList);
+ Console.WriteLine("DivMany Result: " + string.Join("|", await call.ResponseStream.ToListAsync()));
}
}
@@ -102,7 +102,7 @@ namespace math
Num sum;
using (var sumCall = client.Sum())
{
- await sumCall.RequestStream.WriteAll(numbers);
+ await sumCall.RequestStream.WriteAllAsync(numbers);
sum = await sumCall.ResponseAsync;
}
diff --git a/src/csharp/Grpc.Examples/MathServiceImpl.cs b/src/csharp/Grpc.Examples/MathServiceImpl.cs
index dd26b1d350..7b2684615c 100644
--- a/src/csharp/Grpc.Examples/MathServiceImpl.cs
+++ b/src/csharp/Grpc.Examples/MathServiceImpl.cs
@@ -75,7 +75,7 @@ namespace math
public async Task<Num> Sum(IAsyncStreamReader<Num> requestStream, ServerCallContext context)
{
long sum = 0;
- await requestStream.ForEach(async num =>
+ await requestStream.ForEachAsync(async num =>
{
sum += num.Num_;
});
@@ -84,10 +84,7 @@ namespace math
public async Task DivMany(IAsyncStreamReader<DivArgs> requestStream, IServerStreamWriter<DivReply> responseStream, ServerCallContext context)
{
- await requestStream.ForEach(async divArgs =>
- {
- await responseStream.WriteAsync(DivInternal(divArgs));
- });
+ await requestStream.ForEachAsync(async divArgs => await responseStream.WriteAsync(DivInternal(divArgs)));
}
static DivReply DivInternal(DivArgs args)
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
index 7184415655..c4caa3b57a 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
@@ -92,11 +92,11 @@ namespace Grpc.HealthCheck.Tests
public void NullsRejected()
{
var impl = new HealthServiceImpl();
- Assert.Throws(typeof(NullReferenceException), () => 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(ArgumentNullException), () => impl.SetStatus("", null, HealthCheckResponse.Types.ServingStatus.SERVING));
- Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus(null, ""));
- Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus("", null));
+ Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus(null, ""));
+ Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus("", null));
}
private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string host, string service)
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/app.config b/src/csharp/Grpc.IntegrationTesting.Client/app.config
index 0a82bb4f16..84d7534d65 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/app.config
+++ b/src/csharp/Grpc.IntegrationTesting.Client/app.config
@@ -10,6 +10,10 @@
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
</dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Google.Apis.Core" publicKeyToken="4b01fa6e34db77ab" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.9.2.38523" newVersion="1.9.2.38523" />
+ </dependentAssembly>
</assemblyBinding>
</runtime>
</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/app.config b/src/csharp/Grpc.IntegrationTesting.Server/app.config
index 0a82bb4f16..84d7534d65 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/app.config
+++ b/src/csharp/Grpc.IntegrationTesting.Server/app.config
@@ -10,6 +10,10 @@
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
</dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Google.Apis.Core" publicKeyToken="4b01fa6e34db77ab" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.9.2.38523" newVersion="1.9.2.38523" />
+ </dependentAssembly>
</assemblyBinding>
</runtime>
</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 06a75a3351..2020a76d39 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -8,7 +8,7 @@
<RootNamespace>Grpc.IntegrationTesting</RootNamespace>
<AssemblyName>Grpc.IntegrationTesting</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <NuGetPackageImportStamp>041c163e</NuGetPackageImportStamp>
+ <NuGetPackageImportStamp>6566287f</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -38,20 +38,33 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
- <Reference Include="BouncyCastle.Crypto">
+ <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth, Version=1.9.2.27817, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll</HintPath>
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.2.27820, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Core, Version=1.9.2.27816, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Core.1.9.2\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -78,15 +91,6 @@
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest" />
- <Reference Include="Microsoft.Threading.Tasks">
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
- </Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions">
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
- </Reference>
- <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>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 6802de489d..385ca92086 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -43,6 +43,7 @@ using Grpc.Auth;
using Grpc.Core;
using Grpc.Core.Utils;
using NUnit.Framework;
+using Google.Apis.Auth.OAuth2;
namespace Grpc.IntegrationTesting
{
@@ -97,10 +98,10 @@ namespace Grpc.IntegrationTesting
}
var interopClient = new InteropClient(options);
- interopClient.Run();
+ interopClient.Run().Wait();
}
- private void Run()
+ private async Task Run()
{
Credentials credentials = null;
if (options.useTls)
@@ -120,17 +121,7 @@ namespace Grpc.IntegrationTesting
using (Channel channel = new Channel(options.serverHost, options.serverPort.Value, credentials, channelOptions))
{
TestService.TestServiceClient client = new TestService.TestServiceClient(channel);
- if (options.testCase == "service_account_creds" || options.testCase == "compute_engine_creds")
- {
- var credential = GoogleCredential.GetApplicationDefault();
- if (credential.IsCreateScopedRequired)
- {
- credential = credential.CreateScoped(new[] { AuthScope });
- }
- client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
- }
-
- RunTestCaseAsync(options.testCase, client).Wait();
+ await RunTestCaseAsync(options.testCase, client);
}
GrpcEnvironment.Shutdown();
}
@@ -158,16 +149,19 @@ namespace Grpc.IntegrationTesting
await RunEmptyStreamAsync(client);
break;
case "service_account_creds":
- RunServiceAccountCreds(client);
+ await RunServiceAccountCredsAsync(client);
break;
case "compute_engine_creds":
- RunComputeEngineCreds(client);
+ await RunComputeEngineCredsAsync(client);
+ break;
+ case "jwt_token_creds":
+ await RunJwtTokenCredsAsync(client);
break;
case "oauth2_auth_token":
- RunOAuth2AuthToken(client);
+ await RunOAuth2AuthTokenAsync(client);
break;
case "per_rpc_creds":
- RunPerRpcCreds(client);
+ await RunPerRpcCredsAsync(client);
break;
case "cancel_after_begin":
await RunCancelAfterBeginAsync(client);
@@ -215,7 +209,7 @@ namespace Grpc.IntegrationTesting
using (var call = client.StreamingInputCall())
{
- await call.RequestStream.WriteAll(bodySizes);
+ await call.RequestStream.WriteAllAsync(bodySizes);
var response = await call.ResponseAsync;
Assert.AreEqual(74922, response.AggregatedPayloadSize);
@@ -237,7 +231,7 @@ namespace Grpc.IntegrationTesting
using (var call = client.StreamingOutputCall(request))
{
- var responseList = await call.ResponseStream.ToList();
+ var responseList = await call.ResponseStream.ToListAsync();
foreach (var res in responseList)
{
Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type);
@@ -303,15 +297,19 @@ namespace Grpc.IntegrationTesting
{
await call.RequestStream.CompleteAsync();
- var responseList = await call.ResponseStream.ToList();
+ var responseList = await call.ResponseStream.ToListAsync();
Assert.AreEqual(0, responseList.Count);
}
Console.WriteLine("Passed!");
}
- public static void RunServiceAccountCreds(TestService.ITestServiceClient client)
+ public static async Task RunServiceAccountCredsAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running service_account_creds");
+ var credential = await GoogleCredential.GetApplicationDefaultAsync();
+ credential = credential.CreateScoped(new[] { AuthScope });
+ client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
+
var request = SimpleRequest.CreateBuilder()
.SetResponseType(PayloadType.COMPRESSABLE)
.SetResponseSize(314159)
@@ -329,9 +327,13 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static void RunComputeEngineCreds(TestService.ITestServiceClient client)
+ public static async Task RunComputeEngineCredsAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running compute_engine_creds");
+ var credential = await GoogleCredential.GetApplicationDefaultAsync();
+ Assert.IsFalse(credential.IsCreateScopedRequired);
+ client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
+
var request = SimpleRequest.CreateBuilder()
.SetResponseType(PayloadType.COMPRESSABLE)
.SetResponseSize(314159)
@@ -349,12 +351,35 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static void RunOAuth2AuthToken(TestService.TestServiceClient client)
+ public static async Task RunJwtTokenCredsAsync(TestService.TestServiceClient client)
+ {
+ Console.WriteLine("running jwt_token_creds");
+ var credential = await GoogleCredential.GetApplicationDefaultAsync();
+ // check this a credential with scope support, but don't add the scope.
+ Assert.IsTrue(credential.IsCreateScopedRequired);
+ client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
+
+ var request = SimpleRequest.CreateBuilder()
+ .SetResponseType(PayloadType.COMPRESSABLE)
+ .SetResponseSize(314159)
+ .SetPayload(CreateZerosPayload(271828))
+ .SetFillUsername(true)
+ .SetFillOauthScope(true)
+ .Build();
+
+ var response = client.UnaryCall(request);
+
+ Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
+ Assert.AreEqual(314159, response.Payload.Body.Length);
+ Assert.AreEqual(ServiceAccountUser, response.Username);
+ Console.WriteLine("Passed!");
+ }
+
+ public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running oauth2_auth_token");
- var credential = GoogleCredential.GetApplicationDefault().CreateScoped(new[] { AuthScope });
- Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result);
- string oauth2Token = credential.Token.AccessToken;
+ ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope });
+ string oauth2Token = await credential.GetAccessTokenForRequestAsync();
client.HeaderInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
@@ -370,13 +395,12 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static void RunPerRpcCreds(TestService.TestServiceClient client)
+ public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client)
{
Console.WriteLine("running per_rpc_creds");
- var credential = GoogleCredential.GetApplicationDefault().CreateScoped(new[] { AuthScope });
- Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result);
- string oauth2Token = credential.Token.AccessToken;
+ ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope });
+ string oauth2Token = await credential.GetAccessTokenForRequestAsync();
var headerInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
var request = SimpleRequest.CreateBuilder()
@@ -385,7 +409,7 @@ namespace Grpc.IntegrationTesting
.Build();
var headers = new Metadata();
- headerInterceptor(headers);
+ headerInterceptor("", headers);
var response = client.UnaryCall(request, headers: headers);
Assert.AreEqual(AuthScopeResponse, response.OauthScope);
diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
index ccf9fe6ced..ceebd5dd8c 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
@@ -71,7 +71,7 @@ namespace grpc.testing
public async Task<StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<StreamingInputCallRequest> requestStream, ServerCallContext context)
{
int sum = 0;
- await requestStream.ForEach(async request =>
+ await requestStream.ForEachAsync(async request =>
{
sum += request.Payload.Body.Length;
});
@@ -80,7 +80,7 @@ namespace grpc.testing
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)
{
diff --git a/src/csharp/Grpc.IntegrationTesting/app.config b/src/csharp/Grpc.IntegrationTesting/app.config
index 0a82bb4f16..84d7534d65 100644
--- a/src/csharp/Grpc.IntegrationTesting/app.config
+++ b/src/csharp/Grpc.IntegrationTesting/app.config
@@ -10,6 +10,10 @@
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
</dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Google.Apis.Core" publicKeyToken="4b01fa6e34db77ab" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.9.2.38523" newVersion="1.9.2.38523" />
+ </dependentAssembly>
</assemblyBinding>
</runtime>
</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
index 7d1f84f303..0867b091b9 100644
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting/packages.config
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
- <package id="Google.Apis.Auth" version="1.9.2" targetFramework="net45" />
- <package id="Google.Apis.Core" version="1.9.2" targetFramework="net45" />
+ <package id="Google.Apis.Auth" version="1.9.3" targetFramework="net45" />
+ <package id="Google.Apis.Core" version="1.9.3" targetFramework="net45" />
<package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" />
<package id="Ix-Async" version="1.2.3" targetFramework="net45" />
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />