aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp
diff options
context:
space:
mode:
Diffstat (limited to 'src/csharp')
-rw-r--r--src/csharp/Grpc.Auth/GoogleCredential.cs21
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.csproj53
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.nuspec9
-rw-r--r--src/csharp/Grpc.Auth/OAuth2Interceptors.cs (renamed from src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs)27
-rw-r--r--src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs2
-rw-r--r--src/csharp/Grpc.Auth/app.config2
-rw-r--r--src/csharp/Grpc.Auth/packages.config12
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelTest.cs (renamed from src/csharp/Grpc.Core.Tests/TimespecTest.cs)66
-rw-r--r--src/csharp/Grpc.Core.Tests/ClientServerTest.cs176
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj38
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs202
-rw-r--r--src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs77
-rw-r--r--src/csharp/Grpc.Core.Tests/ServerTest.cs39
-rw-r--r--src/csharp/Grpc.Core.Tests/TimeoutsTest.cs212
-rw-r--r--src/csharp/Grpc.Core.Tests/packages.config1
-rw-r--r--src/csharp/Grpc.Core/CallInvocationDetails.cs (renamed from src/csharp/Grpc.Core/Call.cs)53
-rw-r--r--src/csharp/Grpc.Core/CallOptions.cs89
-rw-r--r--src/csharp/Grpc.Core/Calls.cs48
-rw-r--r--src/csharp/Grpc.Core/Channel.cs128
-rw-r--r--src/csharp/Grpc.Core/ChannelOptions.cs4
-rw-r--r--src/csharp/Grpc.Core/ChannelState.cs69
-rw-r--r--src/csharp/Grpc.Core/ClientBase.cs10
-rw-r--r--src/csharp/Grpc.Core/Credentials.cs75
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj29
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.nuspec7
-rw-r--r--src/csharp/Grpc.Core/GrpcEnvironment.cs33
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs89
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs13
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallServer.cs28
-rw-r--r--src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs60
-rw-r--r--src/csharp/Grpc.Core/Internal/CallSafeHandle.cs21
-rw-r--r--src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs47
-rw-r--r--src/csharp/Grpc.Core/Internal/CompletionRegistry.cs5
-rw-r--r--src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs18
-rw-r--r--src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs10
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs (renamed from src/csharp/Grpc.Core/Internal/GrpcLog.cs)37
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCallHandler.cs33
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs9
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs8
-rw-r--r--src/csharp/Grpc.Core/Internal/Timespec.cs183
-rw-r--r--src/csharp/Grpc.Core/KeyCertificatePair.cs83
-rw-r--r--src/csharp/Grpc.Core/Logging/ConsoleLogger.cs103
-rw-r--r--src/csharp/Grpc.Core/Logging/ILogger.cs57
-rw-r--r--src/csharp/Grpc.Core/Metadata.cs1
-rw-r--r--src/csharp/Grpc.Core/Method.cs28
-rw-r--r--src/csharp/Grpc.Core/Properties/AssemblyInfo.cs8
-rw-r--r--src/csharp/Grpc.Core/Server.cs179
-rw-r--r--src/csharp/Grpc.Core/ServerCallContext.cs26
-rw-r--r--src/csharp/Grpc.Core/ServerCredentials.cs103
-rw-r--r--src/csharp/Grpc.Core/ServerPort.cs120
-rw-r--r--src/csharp/Grpc.Core/ServerServiceDefinition.cs12
-rw-r--r--src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs10
-rw-r--r--src/csharp/Grpc.Core/packages.config1
-rw-r--r--src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj21
-rw-r--r--src/csharp/Grpc.Examples.MathClient/MathClient.cs2
-rw-r--r--src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj21
-rw-r--r--src/csharp/Grpc.Examples.MathServer/MathServer.cs15
-rw-r--r--src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj13
-rw-r--r--src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs136
-rw-r--r--src/csharp/Grpc.Examples/Grpc.Examples.csproj13
-rw-r--r--src/csharp/Grpc.Examples/MathGrpc.cs74
-rw-r--r--src/csharp/Grpc.Examples/MathServiceImpl.cs9
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj11
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs10
-rw-r--r--src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj11
-rw-r--r--src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec6
-rw-r--r--src/csharp/Grpc.HealthCheck/HealthGrpc.cs29
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj23
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/app.config2
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj23
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/app.config2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj87
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs267
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs38
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropServer.cs10
-rw-r--r--src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs100
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestCredentials.cs3
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestGrpc.cs118
-rw-r--r--src/csharp/Grpc.IntegrationTesting/app.config2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/packages.config14
-rw-r--r--src/csharp/Grpc.sln127
-rw-r--r--src/csharp/build_packages.bat2
-rw-r--r--src/csharp/buildall.bat7
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c82
-rw-r--r--src/csharp/keys/Grpc.public.snkbin0 -> 160 bytes
-rw-r--r--src/csharp/keys/README.md5
86 files changed, 3069 insertions, 988 deletions
diff --git a/src/csharp/Grpc.Auth/GoogleCredential.cs b/src/csharp/Grpc.Auth/GoogleCredential.cs
index 7edf19ed67..9936cf583c 100644
--- a/src/csharp/Grpc.Auth/GoogleCredential.cs
+++ b/src/csharp/Grpc.Auth/GoogleCredential.cs
@@ -89,17 +89,15 @@ namespace Grpc.Auth
return new GoogleCredential(new ComputeCredential(new ComputeCredential.Initializer()));
}
- JObject o1 = JObject.Parse(File.ReadAllText(credsPath));
- string clientEmail = o1.GetValue(ClientEmailFieldName).Value<string>();
- string privateKeyString = o1.GetValue(PrivateKeyFieldName).Value<string>();
- var privateKey = ParsePrivateKeyFromString(privateKeyString);
+ 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,
- Key = privateKey
- });
+ }.FromPrivateKey(privateKeyString));
return new GoogleCredential(serviceCredential);
}
@@ -123,16 +121,5 @@ namespace Grpc.Auth
return credential;
}
}
-
- private RSACryptoServiceProvider ParsePrivateKeyFromString(string base64PrivateKey)
- {
- // TODO(jtattermusch): temporary code to create RSACryptoServiceProvider.
- base64PrivateKey = base64PrivateKey.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("\n", "").Replace("-----END PRIVATE KEY-----", "");
- RsaPrivateCrtKeyParameters key = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(base64PrivateKey));
- RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(key);
- RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
- rsa.ImportParameters(rsaParameters);
- return rsa;
- }
}
}
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index fdec2e7bd7..8e5036832d 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -11,6 +11,7 @@
<AssemblyName>Grpc.Auth</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<DocumentationFile>bin\$(Configuration)\Grpc.Auth.Xml</DocumentationFile>
+ <NuGetPackageImportStamp>9b408026</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -23,25 +24,37 @@
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>full</DebugType>
+ <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
<ItemGroup>
<Reference Include="BouncyCastle.Crypto">
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth">
- <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll</HintPath>
+ <Reference Include="Google.Apis.Auth, Version=1.9.2.27817, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth.PlatformServices">
- <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.2.27820, 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>
</Reference>
- <Reference Include="Google.Apis.Core">
- <HintPath>..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+ <Reference Include="Google.Apis.Core, Version=1.9.2.27816, 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>
</Reference>
<Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
@@ -52,18 +65,20 @@
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
- <Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+ <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
+ <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
- <Reference Include="System.Net.Http.Extensions">
- <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll</HintPath>
+ <Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
</Reference>
- <Reference Include="System.Net.Http.Primitives">
- <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll</HintPath>
+ <Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
@@ -73,7 +88,7 @@
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="GoogleCredential.cs" />
- <Compile Include="OAuth2InterceptorFactory.cs" />
+ <Compile Include="OAuth2Interceptors.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@@ -87,9 +102,11 @@
<None Include="Grpc.Auth.nuspec" />
<None Include="packages.config" />
</ItemGroup>
- <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
- <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
- <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
- <Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
+ <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
</Target>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
index 1262bdbdab..2dc10d24c2 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
@@ -15,15 +15,14 @@
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2 Auth OAuth2</tags>
<dependencies>
- <dependency id="BouncyCastle" version="1.7.0" />
- <dependency id="Google.Apis.Auth" version="1.9.1" />
+ <dependency id="Google.Apis.Auth" version="1.9.2" />
<dependency id="Grpc.Core" version="$version$" />
</dependencies>
</metadata>
<files>
- <file src="bin/Release/Grpc.Auth.dll" target="lib/net45" />
- <file src="bin/Release/Grpc.Auth.pdb" target="lib/net45" />
- <file src="bin/Release/Grpc.Auth.xml" target="lib/net45" />
+ <file src="bin/ReleaseSigned/Grpc.Auth.dll" target="lib/net45" />
+ <file src="bin/ReleaseSigned/Grpc.Auth.pdb" target="lib/net45" />
+ <file src="bin/ReleaseSigned/Grpc.Auth.xml" target="lib/net45" />
<file src="**\*.cs" target="src" />
</files>
</package>
diff --git a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
index 420c4cb537..cc9d2c175f 100644
--- a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
+++ b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
@@ -47,18 +47,32 @@ using Grpc.Core.Utils;
namespace Grpc.Auth
{
- public static class OAuth2InterceptorFactory
+ public static class OAuth2Interceptors
{
/// <summary>
- /// Creates OAuth2 interceptor.
+ /// Creates OAuth2 interceptor that will obtain access token from GoogleCredentials.
/// </summary>
- public static MetadataInterceptorDelegate Create(GoogleCredential googleCredential)
+ public static MetadataInterceptorDelegate FromCredential(GoogleCredential googleCredential)
{
var interceptor = new OAuth2Interceptor(googleCredential.InternalCredential, SystemClock.Default);
return new MetadataInterceptorDelegate(interceptor.InterceptHeaders);
}
/// <summary>
+ /// Creates OAuth2 interceptor that will use given OAuth2 token.
+ /// </summary>
+ /// <param name="oauth2Token"></param>
+ /// <returns></returns>
+ public static MetadataInterceptorDelegate FromAccessToken(string oauth2Token)
+ {
+ Preconditions.CheckNotNull(oauth2Token);
+ return new MetadataInterceptorDelegate((metadata) =>
+ {
+ metadata.Add(OAuth2Interceptor.CreateBearerTokenHeader(oauth2Token));
+ });
+ }
+
+ /// <summary>
/// Injects OAuth2 authorization header into initial metadata (= request headers).
/// </summary>
private class OAuth2Interceptor
@@ -97,7 +111,12 @@ namespace Grpc.Auth
public void InterceptHeaders(Metadata metadata)
{
var accessToken = GetAccessToken(CancellationToken.None);
- metadata.Add(new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken));
+ metadata.Add(CreateBearerTokenHeader(accessToken));
+ }
+
+ public static Metadata.Entry CreateBearerTokenHeader(string accessToken)
+ {
+ return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken);
}
}
}
diff --git a/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
index 70cb32d5b2..83396c546b 100644
--- a/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
@@ -9,5 +9,3 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-
-[assembly: InternalsVisibleTo("Grpc.Auth.Tests")]
diff --git a/src/csharp/Grpc.Auth/app.config b/src/csharp/Grpc.Auth/app.config
index 966b777192..0a82bb4f16 100644
--- a/src/csharp/Grpc.Auth/app.config
+++ b/src/csharp/Grpc.Auth/app.config
@@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
diff --git a/src/csharp/Grpc.Auth/packages.config b/src/csharp/Grpc.Auth/packages.config
index 7d348872ba..29be953bf3 100644
--- a/src/csharp/Grpc.Auth/packages.config
+++ b/src/csharp/Grpc.Auth/packages.config
@@ -1,11 +1,11 @@
<?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.1" targetFramework="net45" />
- <package id="Google.Apis.Core" version="1.9.1" targetFramework="net45" />
- <package id="Microsoft.Bcl" version="1.1.9" 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="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.14" targetFramework="net45" />
- <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" />
- <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
+ <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+ <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
index a34b407a01..60b45176e5 100644
--- a/src/csharp/Grpc.Core.Tests/TimespecTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
@@ -32,70 +32,60 @@
#endregion
using System;
-using System.Runtime.InteropServices;
+using Grpc.Core;
using Grpc.Core.Internal;
+using Grpc.Core.Utils;
using NUnit.Framework;
-namespace Grpc.Core.Internal.Tests
+namespace Grpc.Core.Tests
{
- public class TimespecTest
+ public class ChannelTest
{
- [Test]
- public void Now()
+ [TestFixtureTearDown]
+ public void CleanupClass()
{
- var timespec = Timespec.Now;
+ GrpcEnvironment.Shutdown();
}
[Test]
- public void InfFuture()
+ public void Constructor_RejectsInvalidParams()
{
- var timespec = Timespec.InfFuture;
+ Assert.Throws(typeof(NullReferenceException), () => new Channel(null, Credentials.Insecure));
}
[Test]
- public void TimespecSizeIsNativeSize()
+ public void State_IdleAfterCreation()
{
- Assert.AreEqual(Timespec.NativeSize, Marshal.SizeOf(typeof(Timespec)));
- }
-
- [Test]
- public void ToDateTime()
- {
- Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
- new Timespec(IntPtr.Zero, 0).ToDateTime());
-
- Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50),
- new Timespec(new IntPtr(10), 5000).ToDateTime());
-
- Assert.AreEqual(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc),
- new Timespec(new IntPtr(1437452508), 0).ToDateTime());
+ using (var channel = new Channel("localhost", Credentials.Insecure))
+ {
+ Assert.AreEqual(ChannelState.Idle, channel.State);
+ }
}
[Test]
- public void Add()
+ public void WaitForStateChangedAsync_InvalidArgument()
{
- var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = 123456789 };
- var result = t.Add(TimeSpan.FromTicks(TimeSpan.TicksPerSecond * 10));
- Assert.AreEqual(result.tv_sec, new IntPtr(12355));
- Assert.AreEqual(result.tv_nsec, 123456789);
+ using (var channel = new Channel("localhost", Credentials.Insecure))
+ {
+ Assert.Throws(typeof(ArgumentException), () => channel.WaitForStateChangedAsync(ChannelState.FatalFailure));
+ }
}
[Test]
- public void Add_Nanos()
+ public void Target()
{
- var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = 123456789 };
- var result = t.Add(TimeSpan.FromTicks(10));
- Assert.AreEqual(result.tv_sec, new IntPtr(12345));
- Assert.AreEqual(result.tv_nsec, 123456789 + 1000);
+ using (var channel = new Channel("127.0.0.1", Credentials.Insecure))
+ {
+ Assert.IsTrue(channel.Target.Contains("127.0.0.1"));
+ }
}
[Test]
- public void Add_NanosOverflow()
+ public void Dispose_IsIdempotent()
{
- var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = 999999999 };
- var result = t.Add(TimeSpan.FromTicks(TimeSpan.TicksPerSecond * 10 + 10));
- Assert.AreEqual(result.tv_sec, new IntPtr(12356));
- Assert.AreEqual(result.tv_nsec, 999);
+ var channel = new Channel("localhost", Credentials.Insecure);
+ channel.Dispose();
+ channel.Dispose();
}
}
}
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index 8ba2c8a9a2..64ea21800f 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -45,24 +45,27 @@ namespace Grpc.Core.Tests
{
public class ClientServerTest
{
- const string Host = "localhost";
- const string ServiceName = "/tests.Test";
+ const string Host = "127.0.0.1";
+ const string ServiceName = "tests.Test";
static readonly Method<string, string> EchoMethod = new Method<string, string>(
MethodType.Unary,
- "/tests.Test/Echo",
+ ServiceName,
+ "Echo",
Marshallers.StringMarshaller,
Marshallers.StringMarshaller);
static readonly Method<string, string> ConcatAndEchoMethod = new Method<string, string>(
MethodType.ClientStreaming,
- "/tests.Test/ConcatAndEcho",
+ ServiceName,
+ "ConcatAndEcho",
Marshallers.StringMarshaller,
Marshallers.StringMarshaller);
static readonly Method<string, string> NonexistentMethod = new Method<string, string>(
MethodType.Unary,
- "/tests.Test/NonexistentMethod",
+ ServiceName,
+ "NonexistentMethod",
Marshallers.StringMarshaller,
Marshallers.StringMarshaller);
@@ -77,11 +80,13 @@ namespace Grpc.Core.Tests
[SetUp]
public void Init()
{
- server = new Server();
- server.AddServiceDefinition(ServiceDefinition);
- int port = server.AddListeningPort(Host, Server.PickUnusedPort);
+ server = new Server
+ {
+ Services = { ServiceDefinition },
+ Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
+ };
server.Start();
- channel = new Channel(Host, port);
+ channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
}
[TearDown]
@@ -100,17 +105,17 @@ namespace Grpc.Core.Tests
[Test]
public void UnaryCall()
{
- var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
- Assert.AreEqual("ABC", Calls.BlockingUnaryCall(internalCall, "ABC", CancellationToken.None));
+ var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
+ Assert.AreEqual("ABC", Calls.BlockingUnaryCall(callDetails, "ABC"));
}
[Test]
public void UnaryCall_ServerHandlerThrows()
{
- var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
try
{
- Calls.BlockingUnaryCall(internalCall, "THROW", CancellationToken.None);
+ Calls.BlockingUnaryCall(callDetails, "THROW");
Assert.Fail();
}
catch (RpcException e)
@@ -122,10 +127,10 @@ namespace Grpc.Core.Tests
[Test]
public void UnaryCall_ServerHandlerThrowsRpcException()
{
- var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
try
{
- Calls.BlockingUnaryCall(internalCall, "THROW_UNAUTHENTICATED", CancellationToken.None);
+ Calls.BlockingUnaryCall(callDetails, "THROW_UNAUTHENTICATED");
Assert.Fail();
}
catch (RpcException e)
@@ -137,10 +142,10 @@ namespace Grpc.Core.Tests
[Test]
public void UnaryCall_ServerHandlerSetsStatus()
{
- var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
try
{
- Calls.BlockingUnaryCall(internalCall, "SET_UNAUTHENTICATED", CancellationToken.None);
+ Calls.BlockingUnaryCall(callDetails, "SET_UNAUTHENTICATED");
Assert.Fail();
}
catch (RpcException e)
@@ -150,67 +155,57 @@ namespace Grpc.Core.Tests
}
[Test]
- public void AsyncUnaryCall()
+ public async Task AsyncUnaryCall()
{
- var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
- var result = Calls.AsyncUnaryCall(internalCall, "ABC", CancellationToken.None).ResponseAsync.Result;
+ var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
+ var result = await Calls.AsyncUnaryCall(callDetails, "ABC");
Assert.AreEqual("ABC", result);
}
[Test]
- public void AsyncUnaryCall_ServerHandlerThrows()
+ public async Task AsyncUnaryCall_ServerHandlerThrows()
{
- Task.Run(async () =>
+ var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
+ try
{
- var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
- try
- {
- await Calls.AsyncUnaryCall(internalCall, "THROW", CancellationToken.None);
- Assert.Fail();
- }
- catch (RpcException e)
- {
- Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
- }
- }).Wait();
+ await Calls.AsyncUnaryCall(callDetails, "THROW");
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
+ }
}
[Test]
- public void ClientStreamingCall()
+ public async Task ClientStreamingCall()
{
- Task.Run(async () =>
- {
- var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
- var call = Calls.AsyncClientStreamingCall(internalCall, CancellationToken.None);
+ var callDetails = new CallInvocationDetails<string, string>(channel, ConcatAndEchoMethod, new CallOptions());
+ var call = Calls.AsyncClientStreamingCall(callDetails);
- await call.RequestStream.WriteAll(new string[] { "A", "B", "C" });
- Assert.AreEqual("ABC", await call.ResponseAsync);
- }).Wait();
+ await call.RequestStream.WriteAll(new string[] { "A", "B", "C" });
+ Assert.AreEqual("ABC", await call.ResponseAsync);
}
[Test]
- public void ClientStreamingCall_CancelAfterBegin()
+ public async Task ClientStreamingCall_CancelAfterBegin()
{
- Task.Run(async () =>
- {
- var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
+ var cts = new CancellationTokenSource();
+ var callDetails = new CallInvocationDetails<string, string>(channel, ConcatAndEchoMethod, new CallOptions(cancellationToken: cts.Token));
+ var call = Calls.AsyncClientStreamingCall(callDetails);
- var cts = new CancellationTokenSource();
- var call = Calls.AsyncClientStreamingCall(internalCall, cts.Token);
+ // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
+ await Task.Delay(1000);
+ cts.Cancel();
- // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
- await Task.Delay(1000);
- cts.Cancel();
-
- try
- {
- await call.ResponseAsync;
- }
- catch (RpcException e)
- {
- Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
- }
- }).Wait();
+ try
+ {
+ await call.ResponseAsync;
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
+ }
}
[Test]
@@ -218,11 +213,11 @@ namespace Grpc.Core.Tests
{
var headers = new Metadata
{
- new Metadata.Entry("asciiHeader", "abcdefg"),
- new Metadata.Entry("binaryHeader-bin", new byte[] { 1, 2, 3, 0, 0xff }),
+ new Metadata.Entry("ascii-header", "abcdefg"),
+ new Metadata.Entry("binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff }),
};
- var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, headers);
- var call = Calls.AsyncUnaryCall(internalCall, "ABC", CancellationToken.None);
+ var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions(headers: headers));
+ var call = Calls.AsyncUnaryCall(callDetails, "ABC");
Assert.AreEqual("ABC", call.ResponseAsync.Result);
@@ -242,25 +237,25 @@ namespace Grpc.Core.Tests
{
channel.Dispose();
- var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
- Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(internalCall, "ABC", CancellationToken.None));
+ var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
+ Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(callDetails, "ABC"));
}
[Test]
public void UnaryCallPerformance()
{
- var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+ var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
BenchmarkUtil.RunBenchmark(100, 100,
- () => { Calls.BlockingUnaryCall(internalCall, "ABC", default(CancellationToken)); });
+ () => { Calls.BlockingUnaryCall(callDetails, "ABC"); });
}
[Test]
public void UnknownMethodHandler()
{
- var internalCall = new Call<string, string>(ServiceName, NonexistentMethod, channel, Metadata.Empty);
+ var callDetails = new CallInvocationDetails<string, string>(channel, NonexistentMethod, new CallOptions());
try
{
- Calls.BlockingUnaryCall(internalCall, "ABC", default(CancellationToken));
+ Calls.BlockingUnaryCall(callDetails, "ABC");
Assert.Fail();
}
catch (RpcException e)
@@ -272,11 +267,43 @@ namespace Grpc.Core.Tests
[Test]
public void UserAgentStringPresent()
{
- var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
- string userAgent = Calls.BlockingUnaryCall(internalCall, "RETURN-USER-AGENT", CancellationToken.None);
+ var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
+ string userAgent = Calls.BlockingUnaryCall(callDetails, "RETURN-USER-AGENT");
Assert.IsTrue(userAgent.StartsWith("grpc-csharp/"));
}
+ [Test]
+ public void PeerInfoPresent()
+ {
+ var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
+ string peer = Calls.BlockingUnaryCall(callDetails, "RETURN-PEER");
+ Assert.IsTrue(peer.Contains(Host));
+ }
+
+ [Test]
+ public async Task Channel_WaitForStateChangedAsync()
+ {
+ Assert.Throws(typeof(TaskCanceledException),
+ async () => await channel.WaitForStateChangedAsync(channel.State, DateTime.UtcNow.AddMilliseconds(10)));
+
+ var stateChangedTask = channel.WaitForStateChangedAsync(channel.State);
+
+ var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
+ await Calls.AsyncUnaryCall(callDetails, "abc");
+
+ await stateChangedTask;
+ Assert.AreEqual(ChannelState.Ready, channel.State);
+ }
+
+ [Test]
+ public async Task Channel_ConnectAsync()
+ {
+ await channel.ConnectAsync();
+ Assert.AreEqual(ChannelState.Ready, channel.State);
+ await channel.ConnectAsync(DateTime.UtcNow.AddMilliseconds(1000));
+ Assert.AreEqual(ChannelState.Ready, channel.State);
+ }
+
private static async Task<string> EchoHandler(string request, ServerCallContext context)
{
foreach (Metadata.Entry metadataEntry in context.RequestHeaders)
@@ -292,6 +319,11 @@ namespace Grpc.Core.Tests
return context.RequestHeaders.Where(entry => entry.Key == "user-agent").Single().Value;
}
+ if (request == "RETURN-PEER")
+ {
+ return context.Peer;
+ }
+
if (request == "THROW")
{
throw new Exception("This was thrown on purpose by a test");
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 927954c448..f2bf459dc5 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -17,20 +17,43 @@
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>full</DebugType>
+ <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="nunit.core">
+ <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="nunit.core.interfaces">
+ <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
+ <Reference Include="nunit.util">
+ <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="NUnit.VisualStudio.TestAdapter">
+ <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Interactive.Async">
<HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
@@ -44,13 +67,16 @@
<Compile Include="ClientServerTest.cs" />
<Compile Include="ServerTest.cs" />
<Compile Include="GrpcEnvironmentTest.cs" />
- <Compile Include="TimespecTest.cs" />
<Compile Include="PInvokeTest.cs" />
<Compile Include="Internal\MetadataArraySafeHandleTest.cs" />
<Compile Include="Internal\CompletionQueueSafeHandleTest.cs" />
<Compile Include="Internal\CompletionQueueEventTest.cs" />
<Compile Include="Internal\ChannelArgsSafeHandleTest.cs" />
<Compile Include="ChannelOptionsTest.cs" />
+ <Compile Include="Internal\TimespecTest.cs" />
+ <Compile Include="TimeoutsTest.cs" />
+ <Compile Include="NUnitVersionTest.cs" />
+ <Compile Include="ChannelTest.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@@ -60,7 +86,9 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
- <None Include="packages.config" />
+ <None Include="packages.config">
+ <SubType>Designer</SubType>
+ </None>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
diff --git a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
new file mode 100644
index 0000000000..874df02baa
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
@@ -0,0 +1,202 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+using Grpc.Core.Internal;
+using NUnit.Framework;
+
+namespace Grpc.Core.Internal.Tests
+{
+ public class TimespecTest
+ {
+ [Test]
+ public void Now_IsInUtc()
+ {
+ Assert.AreEqual(DateTimeKind.Utc, Timespec.Now.ToDateTime().Kind);
+ }
+
+ [Test]
+ public void Now_AgreesWithUtcNow()
+ {
+ var timespec = Timespec.Now;
+ var utcNow = DateTime.UtcNow;
+
+ TimeSpan difference = utcNow - timespec.ToDateTime();
+
+ // This test is inherently a race - but the two timestamps
+ // should really be way less that a minute apart.
+ Assert.IsTrue(difference.TotalSeconds < 60);
+ }
+
+ [Test]
+ public void InfFuture()
+ {
+ var timespec = Timespec.InfFuture;
+ }
+
+ [Test]
+ public void InfPast()
+ {
+ var timespec = Timespec.InfPast;
+ }
+
+ [Test]
+ public void TimespecSizeIsNativeSize()
+ {
+ Assert.AreEqual(Timespec.NativeSize, Marshal.SizeOf(typeof(Timespec)));
+ }
+
+ [Test]
+ public void ToDateTime()
+ {
+ Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
+ new Timespec(IntPtr.Zero, 0).ToDateTime());
+
+ Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50),
+ new Timespec(new IntPtr(10), 5000).ToDateTime());
+
+ Assert.AreEqual(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc),
+ new Timespec(new IntPtr(1437452508), 0).ToDateTime());
+
+ // before epoch
+ Assert.AreEqual(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10),
+ new Timespec(new IntPtr(-5), 1000).ToDateTime());
+
+ // infinity
+ Assert.AreEqual(DateTime.MaxValue, Timespec.InfFuture.ToDateTime());
+ Assert.AreEqual(DateTime.MinValue, Timespec.InfPast.ToDateTime());
+
+ // nanos are rounded to ticks are rounded up
+ Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(1),
+ new Timespec(IntPtr.Zero, 99).ToDateTime());
+
+ // Illegal inputs
+ Assert.Throws(typeof(InvalidOperationException),
+ () => new Timespec(new IntPtr(0), -2).ToDateTime());
+ Assert.Throws(typeof(InvalidOperationException),
+ () => new Timespec(new IntPtr(0), 1000 * 1000 * 1000).ToDateTime());
+ Assert.Throws(typeof(InvalidOperationException),
+ () => new Timespec(new IntPtr(0), 0, GPRClockType.Monotonic).ToDateTime());
+ }
+
+ [Test]
+ public void ToDateTime_ReturnsUtc()
+ {
+ Assert.AreEqual(DateTimeKind.Utc, new Timespec(new IntPtr(1437452508), 0).ToDateTime().Kind);
+ Assert.AreNotEqual(DateTimeKind.Unspecified, new Timespec(new IntPtr(1437452508), 0).ToDateTime().Kind);
+ }
+
+ [Test]
+ public void ToDateTime_Overflow()
+ {
+ // we can only get overflow in ticks arithmetic on 64-bit
+ if (IntPtr.Size == 8)
+ {
+ var timespec = new Timespec(new IntPtr(long.MaxValue - 100), 0);
+ Assert.AreNotEqual(Timespec.InfFuture, timespec);
+ Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime());
+
+ Assert.AreEqual(DateTime.MinValue, new Timespec(new IntPtr(long.MinValue + 100), 0).ToDateTime());
+ }
+ else
+ {
+ Console.WriteLine("Test cannot be run on this platform, skipping the test.");
+ }
+ }
+
+ [Test]
+ public void ToDateTime_OutOfDateTimeRange()
+ {
+ // we can only get out of range on 64-bit, on 32 bit the max
+ // timestamp is ~ Jan 19 2038, which is far within range of DateTime
+ // same case for min value.
+ if (IntPtr.Size == 8)
+ {
+ // DateTime range goes up to year 9999, 20000 years from now should
+ // be out of range.
+ long seconds = 20000L * 365L * 24L * 3600L;
+
+ var timespec = new Timespec(new IntPtr(seconds), 0);
+ Assert.AreNotEqual(Timespec.InfFuture, timespec);
+ Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime());
+
+ Assert.AreEqual(DateTime.MinValue, new Timespec(new IntPtr(-seconds), 0).ToDateTime());
+ }
+ else
+ {
+ Console.WriteLine("Test cannot be run on this platform, skipping the test");
+ }
+ }
+
+ [Test]
+ public void FromDateTime()
+ {
+ Assert.AreEqual(new Timespec(IntPtr.Zero, 0),
+ Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
+
+ Assert.AreEqual(new Timespec(new IntPtr(10), 5000),
+ Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50)));
+
+ Assert.AreEqual(new Timespec(new IntPtr(1437452508), 0),
+ Timespec.FromDateTime(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc)));
+
+ // before epoch
+ Assert.AreEqual(new Timespec(new IntPtr(-5), 1000),
+ Timespec.FromDateTime(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10)));
+
+ // infinity
+ Assert.AreEqual(Timespec.InfFuture, Timespec.FromDateTime(DateTime.MaxValue));
+ Assert.AreEqual(Timespec.InfPast, Timespec.FromDateTime(DateTime.MinValue));
+
+ // illegal inputs
+ Assert.Throws(typeof(ArgumentException),
+ () => Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified)));
+ }
+
+ [Test]
+ public void FromDateTime_OutOfTimespecRange()
+ {
+ // we can only get overflow in Timespec on 32-bit
+ if (IntPtr.Size == 4)
+ {
+ Assert.AreEqual(Timespec.InfFuture, Timespec.FromDateTime(new DateTime(2040, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
+ Assert.AreEqual(Timespec.InfPast, Timespec.FromDateTime(new DateTime(1800, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
+ }
+ else
+ {
+ Console.WriteLine("Test cannot be run on this platform, skipping the test.");
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs
new file mode 100644
index 0000000000..3fa6ad09c0
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs
@@ -0,0 +1,77 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ /// <summary>
+ /// Tests if the version of nunit-console used is sufficient to run async tests.
+ /// </summary>
+ public class NUnitVersionTest
+ {
+ private int testRunCount = 0;
+
+ [TestFixtureTearDown]
+ public void Cleanup()
+ {
+ if (testRunCount != 2)
+ {
+ Console.Error.WriteLine("You are using and old version of NUnit that doesn't support async tests and skips them instead. " +
+ "This test has failed to indicate that.");
+ Console.Error.Flush();
+ Environment.Exit(1);
+ }
+ }
+
+ [Test]
+ public void NUnitVersionTest1()
+ {
+ testRunCount++;
+ }
+
+ // Old version of NUnit will skip this test
+ [Test]
+ public async Task NUnitVersionTest2()
+ {
+ testRunCount++;
+ await Task.Delay(10);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/ServerTest.cs b/src/csharp/Grpc.Core.Tests/ServerTest.cs
index 1119aa370e..485006ebac 100644
--- a/src/csharp/Grpc.Core.Tests/ServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ServerTest.cs
@@ -32,6 +32,7 @@
#endregion
using System;
+using System.Linq;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
@@ -44,11 +45,45 @@ namespace Grpc.Core.Tests
[Test]
public void StartAndShutdownServer()
{
- Server server = new Server();
- server.AddListeningPort("localhost", Server.PickUnusedPort);
+ Server server = new Server
+ {
+ Ports = { new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure) }
+ };
server.Start();
server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown();
}
+
+ [Test]
+ public void PickUnusedPort()
+ {
+ Server server = new Server
+ {
+ Ports = { new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure) }
+ };
+
+ var boundPort = server.Ports.Single();
+ Assert.AreEqual(0, boundPort.Port);
+ Assert.Greater(boundPort.BoundPort, 0);
+
+ server.Start();
+ server.ShutdownAsync();
+ GrpcEnvironment.Shutdown();
+ }
+
+ [Test]
+ public void CannotModifyAfterStarted()
+ {
+ Server server = new Server
+ {
+ Ports = { new ServerPort("localhost", ServerPort.PickUnused, ServerCredentials.Insecure) }
+ };
+ server.Start();
+ Assert.Throws(typeof(InvalidOperationException), () => server.Ports.Add("localhost", 9999, ServerCredentials.Insecure));
+ Assert.Throws(typeof(InvalidOperationException), () => server.Services.Add(ServerServiceDefinition.CreateBuilder("serviceName").Build()));
+
+ server.ShutdownAsync().Wait();
+ GrpcEnvironment.Shutdown();
+ }
}
}
diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs
new file mode 100644
index 0000000000..fc395b0acd
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs
@@ -0,0 +1,212 @@
+#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.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ /// <summary>
+ /// Tests for Deadline support.
+ /// </summary>
+ public class TimeoutsTest
+ {
+ const string Host = "localhost";
+ const string ServiceName = "tests.Test";
+
+ static readonly Method<string, string> TestMethod = new Method<string, string>(
+ MethodType.Unary,
+ ServiceName,
+ "Test",
+ Marshallers.StringMarshaller,
+ Marshallers.StringMarshaller);
+
+ static readonly ServerServiceDefinition ServiceDefinition = ServerServiceDefinition.CreateBuilder(ServiceName)
+ .AddMethod(TestMethod, TestMethodHandler)
+ .Build();
+
+ // provides a way how to retrieve an out-of-band result value from server handler
+ static TaskCompletionSource<string> stringFromServerHandlerTcs;
+
+ Server server;
+ Channel channel;
+
+ [SetUp]
+ public void Init()
+ {
+ server = new Server
+ {
+ Services = { ServiceDefinition },
+ Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
+ };
+ server.Start();
+ channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
+
+ stringFromServerHandlerTcs = new TaskCompletionSource<string>();
+ }
+
+ [TearDown]
+ public void Cleanup()
+ {
+ channel.Dispose();
+ server.ShutdownAsync().Wait();
+ }
+
+ [TestFixtureTearDown]
+ public void CleanupClass()
+ {
+ GrpcEnvironment.Shutdown();
+ }
+
+ [Test]
+ public void InfiniteDeadline()
+ {
+ // no deadline specified, check server sees infinite deadline
+ var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions());
+ Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(callDetails, "RETURN_DEADLINE"));
+
+ // DateTime.MaxValue deadline specified, check server sees infinite deadline
+ var callDetails2 = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions());
+ Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(callDetails2, "RETURN_DEADLINE"));
+ }
+
+ [Test]
+ public void DeadlineTransferredToServer()
+ {
+ var remainingTimeClient = TimeSpan.FromDays(7);
+ var deadline = DateTime.UtcNow + remainingTimeClient;
+ Thread.Sleep(1000);
+ var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions(deadline: deadline));
+
+ var serverDeadlineTicksString = Calls.BlockingUnaryCall(callDetails, "RETURN_DEADLINE");
+ var serverDeadline = new DateTime(long.Parse(serverDeadlineTicksString), DateTimeKind.Utc);
+
+ // A fairly relaxed check that the deadline set by client and deadline seen by server
+ // are in agreement. C core takes care of the work with transferring deadline over the wire,
+ // so we don't need an exact check here.
+ Assert.IsTrue(Math.Abs((deadline - serverDeadline).TotalMilliseconds) < 5000);
+ }
+
+ [Test]
+ public void DeadlineInThePast()
+ {
+ var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions(deadline: DateTime.MinValue));
+
+ try
+ {
+ Calls.BlockingUnaryCall(callDetails, "TIMEOUT");
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ // We can't guarantee the status code always DeadlineExceeded. See issue #2685.
+ Assert.Contains(e.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal });
+ }
+ }
+
+ [Test]
+ public void DeadlineExceededStatusOnTimeout()
+ {
+ var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5));
+ var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions(deadline: deadline));
+
+ try
+ {
+ Calls.BlockingUnaryCall(callDetails, "TIMEOUT");
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ // We can't guarantee the status code always DeadlineExceeded. See issue #2685.
+ Assert.Contains(e.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal });
+ }
+ }
+
+ [Test]
+ public void ServerReceivesCancellationOnTimeout()
+ {
+ var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5));
+ var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions(deadline: deadline));
+
+ try
+ {
+ Calls.BlockingUnaryCall(callDetails, "CHECK_CANCELLATION_RECEIVED");
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ // We can't guarantee the status code is always DeadlineExceeded. See issue #2685.
+ Assert.Contains(e.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal });
+ }
+ Assert.AreEqual("CANCELLED", stringFromServerHandlerTcs.Task.Result);
+ }
+
+ private static async Task<string> TestMethodHandler(string request, ServerCallContext context)
+ {
+ if (request == "TIMEOUT")
+ {
+ await Task.Delay(60000);
+ return "";
+ }
+
+ if (request == "RETURN_DEADLINE")
+ {
+ if (context.Deadline == DateTime.MaxValue)
+ {
+ return "DATETIME_MAXVALUE";
+ }
+
+ return context.Deadline.Ticks.ToString();
+ }
+
+ if (request == "CHECK_CANCELLATION_RECEIVED")
+ {
+ // wait until cancellation token is fired.
+ var tcs = new TaskCompletionSource<object>();
+ context.CancellationToken.Register(() => { tcs.SetResult(null); });
+ await tcs.Task;
+ stringFromServerHandlerTcs.SetResult("CANCELLED");
+ return "";
+ }
+
+ return "";
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/packages.config b/src/csharp/Grpc.Core.Tests/packages.config
index 28af8d78c6..62077f41be 100644
--- a/src/csharp/Grpc.Core.Tests/packages.config
+++ b/src/csharp/Grpc.Core.Tests/packages.config
@@ -2,4 +2,5 @@
<packages>
<package id="Ix-Async" version="1.2.3" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="net45" />
+ <package id="NUnitTestAdapter" version="2.0.0" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Call.cs b/src/csharp/Grpc.Core/CallInvocationDetails.cs
index 37b452f020..eb23a3a209 100644
--- a/src/csharp/Grpc.Core/Call.cs
+++ b/src/csharp/Grpc.Core/CallInvocationDetails.cs
@@ -38,23 +38,30 @@ using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
- /// Abstraction of a call to be invoked on a client.
+ /// Details about a client-side call to be invoked.
/// </summary>
- public class Call<TRequest, TResponse>
+ public class CallInvocationDetails<TRequest, TResponse>
{
- readonly string name;
+ readonly Channel channel;
+ readonly string method;
+ readonly string host;
readonly Marshaller<TRequest> requestMarshaller;
readonly Marshaller<TResponse> responseMarshaller;
- readonly Channel channel;
- readonly Metadata headers;
+ readonly CallOptions options;
+
+ public CallInvocationDetails(Channel channel, Method<TRequest, TResponse> method, CallOptions options) :
+ this(channel, method.FullName, null, method.RequestMarshaller, method.ResponseMarshaller, options)
+ {
+ }
- public Call(string serviceName, Method<TRequest, TResponse> method, Channel channel, Metadata headers)
+ public CallInvocationDetails(Channel channel, string method, string host, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller, CallOptions options)
{
- this.name = method.GetFullName(serviceName);
- this.requestMarshaller = method.RequestMarshaller;
- this.responseMarshaller = method.ResponseMarshaller;
this.channel = Preconditions.CheckNotNull(channel);
- this.headers = Preconditions.CheckNotNull(headers);
+ this.method = Preconditions.CheckNotNull(method);
+ this.host = host;
+ this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller);
+ this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller);
+ this.options = Preconditions.CheckNotNull(options);
}
public Channel Channel
@@ -65,25 +72,19 @@ namespace Grpc.Core
}
}
- /// <summary>
- /// Full methods name including the service name.
- /// </summary>
- public string Name
+ public string Method
{
get
{
- return name;
+ return this.method;
}
}
- /// <summary>
- /// Headers to send at the beginning of the call.
- /// </summary>
- public Metadata Headers
+ public string Host
{
get
{
- return headers;
+ return this.host;
}
}
@@ -91,7 +92,7 @@ namespace Grpc.Core
{
get
{
- return requestMarshaller;
+ return this.requestMarshaller;
}
}
@@ -99,7 +100,15 @@ namespace Grpc.Core
{
get
{
- return responseMarshaller;
+ return this.responseMarshaller;
+ }
+ }
+
+ public CallOptions Options
+ {
+ get
+ {
+ return options;
}
}
}
diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs
new file mode 100644
index 0000000000..8e9739335f
--- /dev/null
+++ b/src/csharp/Grpc.Core/CallOptions.cs
@@ -0,0 +1,89 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Threading;
+
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Options for calls made by client.
+ /// </summary>
+ public class CallOptions
+ {
+ readonly Metadata headers;
+ readonly DateTime deadline;
+ readonly CancellationToken cancellationToken;
+
+ /// <summary>
+ /// Creates a new instance of <c>CallOptions</c>.
+ /// </summary>
+ /// <param name="headers">Headers to be sent with the call.</param>
+ /// <param name="deadline">Deadline for the call to finish. null means no deadline.</param>
+ /// <param name="cancellationToken">Can be used to request cancellation of the call.</param>
+ public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ // TODO(jtattermusch): consider only creating metadata object once it's really needed.
+ this.headers = headers != null ? headers : new Metadata();
+ this.deadline = deadline.HasValue ? deadline.Value : DateTime.MaxValue;
+ this.cancellationToken = cancellationToken;
+ }
+
+ /// <summary>
+ /// Headers to send at the beginning of the call.
+ /// </summary>
+ public Metadata Headers
+ {
+ get { return headers; }
+ }
+
+ /// <summary>
+ /// Call deadline.
+ /// </summary>
+ public DateTime Deadline
+ {
+ get { return deadline; }
+ }
+
+ /// <summary>
+ /// Token that can be used for cancelling the call.
+ /// </summary>
+ public CancellationToken CancellationToken
+ {
+ get { return cancellationToken; }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs
index 359fe53741..00a8cabf82 100644
--- a/src/csharp/Grpc.Core/Calls.cs
+++ b/src/csharp/Grpc.Core/Calls.cs
@@ -43,70 +43,52 @@ namespace Grpc.Core
/// </summary>
public static class Calls
{
- public static TResponse BlockingUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token)
+ public static TResponse BlockingUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req)
where TRequest : class
where TResponse : class
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
- // TODO(jtattermusch): this gives a race that cancellation can be requested before the call even starts.
- RegisterCancellationCallback(asyncCall, token);
- return asyncCall.UnaryCall(call.Channel, call.Name, req, call.Headers);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call);
+ return asyncCall.UnaryCall(req);
}
- public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token)
+ public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req)
where TRequest : class
where TResponse : class
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
- asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
- var asyncResult = asyncCall.UnaryCallAsync(req, call.Headers);
- RegisterCancellationCallback(asyncCall, token);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call);
+ var asyncResult = asyncCall.UnaryCallAsync(req);
return new AsyncUnaryCall<TResponse>(asyncResult, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
}
- public static AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token)
+ public static AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req)
where TRequest : class
where TResponse : class
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
- asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
- asyncCall.StartServerStreamingCall(req, call.Headers);
- RegisterCancellationCallback(asyncCall, token);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call);
+ asyncCall.StartServerStreamingCall(req);
var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall);
return new AsyncServerStreamingCall<TResponse>(responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
}
- public static AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, CancellationToken token)
+ public static AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call)
where TRequest : class
where TResponse : class
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
- asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
- var resultTask = asyncCall.ClientStreamingCallAsync(call.Headers);
- RegisterCancellationCallback(asyncCall, token);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call);
+ var resultTask = asyncCall.ClientStreamingCallAsync();
var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
return new AsyncClientStreamingCall<TRequest, TResponse>(requestStream, resultTask, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
}
- public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, CancellationToken token)
+ public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call)
where TRequest : class
where TResponse : class
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
- asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
- asyncCall.StartDuplexStreamingCall(call.Headers);
- RegisterCancellationCallback(asyncCall, token);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call);
+ asyncCall.StartDuplexStreamingCall();
var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall);
return new AsyncDuplexStreamingCall<TRequest, TResponse>(requestStream, responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
}
-
- private static void RegisterCancellationCallback<TRequest, TResponse>(AsyncCall<TRequest, TResponse> asyncCall, CancellationToken token)
- {
- if (token.CanBeCanceled)
- {
- token.Register(() => asyncCall.Cancel());
- }
- }
}
}
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index e5c6abd2cb..9273ea4582 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -37,6 +37,8 @@ using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
+using Grpc.Core.Logging;
+using Grpc.Core.Utils;
namespace Grpc.Core
{
@@ -45,89 +47,134 @@ namespace Grpc.Core
/// </summary>
public class Channel : IDisposable
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<Channel>();
+
readonly GrpcEnvironment environment;
readonly ChannelSafeHandle handle;
readonly List<ChannelOption> options;
- readonly string target;
bool disposed;
/// <summary>
/// Creates a channel that connects to a specific host.
- /// Port will default to 80 for an unsecure channel and to 443 a secure channel.
+ /// Port will default to 80 for an unsecure channel and to 443 for a secure channel.
/// </summary>
- /// <param name="host">The DNS name of IP address of the host.</param>
- /// <param name="credentials">Optional credentials to create a secure channel.</param>
+ /// <param name="host">The name or IP address of the host.</param>
+ /// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
- public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null)
+ public Channel(string host, Credentials credentials, IEnumerable<ChannelOption> options = null)
{
+ Preconditions.CheckNotNull(host);
this.environment = GrpcEnvironment.GetInstance();
this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
EnsureUserAgentChannelOption(this.options);
+ using (CredentialsSafeHandle nativeCredentials = credentials.ToNativeCredentials())
using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options))
{
- if (credentials != null)
+ if (nativeCredentials != null)
{
- using (CredentialsSafeHandle nativeCredentials = credentials.ToNativeCredentials())
- {
- this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, host, nativeChannelArgs);
- }
+ this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, host, nativeChannelArgs);
}
else
{
- this.handle = ChannelSafeHandle.Create(host, nativeChannelArgs);
+ this.handle = ChannelSafeHandle.CreateInsecure(host, nativeChannelArgs);
}
}
- this.target = GetOverridenTarget(host, this.options);
}
/// <summary>
/// Creates a channel that connects to a specific host and port.
/// </summary>
- /// <param name="host">DNS name or IP address</param>
- /// <param name="port">the port</param>
- /// <param name="credentials">Optional credentials to create a secure channel.</param>
+ /// <param name="host">The name or IP address of the host.</param>
+ /// <param name="port">The port.</param>
+ /// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
- public Channel(string host, int port, Credentials credentials = null, IEnumerable<ChannelOption> options = null) :
+ public Channel(string host, int port, Credentials credentials, IEnumerable<ChannelOption> options = null) :
this(string.Format("{0}:{1}", host, port), credentials, options)
{
}
- public void Dispose()
+ /// <summary>
+ /// Gets current connectivity state of this channel.
+ /// </summary>
+ public ChannelState State
{
- Dispose(true);
- GC.SuppressFinalize(this);
+ get
+ {
+ return handle.CheckConnectivityState(false);
+ }
}
- internal string Target
+ /// <summary>
+ /// Returned tasks completes once channel state has become different from
+ /// given lastObservedState.
+ /// If deadline is reached or and error occurs, returned task is cancelled.
+ /// </summary>
+ public Task WaitForStateChangedAsync(ChannelState lastObservedState, DateTime? deadline = null)
{
- get
+ Preconditions.CheckArgument(lastObservedState != ChannelState.FatalFailure,
+ "FatalFailure is a terminal state. No further state changes can occur.");
+ var tcs = new TaskCompletionSource<object>();
+ var deadlineTimespec = deadline.HasValue ? Timespec.FromDateTime(deadline.Value) : Timespec.InfFuture;
+ var handler = new BatchCompletionDelegate((success, ctx) =>
{
- return target;
- }
+ if (success)
+ {
+ tcs.SetResult(null);
+ }
+ else
+ {
+ tcs.SetCanceled();
+ }
+ });
+ handle.WatchConnectivityState(lastObservedState, deadlineTimespec, environment.CompletionQueue, environment.CompletionRegistry, handler);
+ return tcs.Task;
}
- internal ChannelSafeHandle Handle
+ /// <summary> Address of the remote endpoint in URI format.</summary>
+ public string Target
{
get
{
- return this.handle;
+ return handle.GetTarget();
}
}
- internal CompletionQueueSafeHandle CompletionQueue
+ /// <summary>
+ /// Allows explicitly requesting channel to connect without starting an RPC.
+ /// Returned task completes once state Ready was seen. If the deadline is reached,
+ /// or channel enters the FatalFailure state, the task is cancelled.
+ /// There is no need to call this explicitly unless your use case requires that.
+ /// Starting an RPC on a new channel will request connection implicitly.
+ /// </summary>
+ public async Task ConnectAsync(DateTime? deadline = null)
{
- get
+ var currentState = handle.CheckConnectivityState(true);
+ while (currentState != ChannelState.Ready)
{
- return this.environment.CompletionQueue;
+ if (currentState == ChannelState.FatalFailure)
+ {
+ throw new OperationCanceledException("Channel has reached FatalFailure state.");
+ }
+ await WaitForStateChangedAsync(currentState, deadline);
+ currentState = handle.CheckConnectivityState(false);
}
}
- internal CompletionRegistry CompletionRegistry
+ /// <summary>
+ /// Destroys the underlying channel.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ internal ChannelSafeHandle Handle
{
get
{
- return this.environment.CompletionRegistry;
+ return this.handle;
}
}
@@ -161,26 +208,5 @@ namespace Grpc.Core
// TODO(jtattermusch): it would be useful to also provide .NET/mono version.
return string.Format("grpc-csharp/{0}", VersionInfo.CurrentVersion);
}
-
- /// <summary>
- /// Look for SslTargetNameOverride option and return its value instead of originalTarget
- /// if found.
- /// </summary>
- private static string GetOverridenTarget(string originalTarget, IEnumerable<ChannelOption> options)
- {
- if (options == null)
- {
- return originalTarget;
- }
- foreach (var option in options)
- {
- if (option.Type == ChannelOption.OptionType.String
- && option.Name == ChannelOptions.SslTargetNameOverride)
- {
- return option.StringValue;
- }
- }
- return originalTarget;
- }
}
}
diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs
index 9fe03d2805..1e0f90287a 100644
--- a/src/csharp/Grpc.Core/ChannelOptions.cs
+++ b/src/csharp/Grpc.Core/ChannelOptions.cs
@@ -30,7 +30,6 @@
#endregion
using System;
using System.Collections.Generic;
-using System.Collections.Immutable;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -135,6 +134,9 @@ namespace Grpc.Core
/// <summary>Initial sequence number for http2 transports</summary>
public const string Http2InitialSequenceNumber = "grpc.http2.initial_sequence_number";
+ /// <summary>Default authority for calls.</summary>
+ public const string DefaultAuthority = "grpc.default_authority";
+
/// <summary>Primary user agent: goes at the start of the user-agent metadata</summary>
public const string PrimaryUserAgentString = "grpc.primary_user_agent";
diff --git a/src/csharp/Grpc.Core/ChannelState.cs b/src/csharp/Grpc.Core/ChannelState.cs
new file mode 100644
index 0000000000..d293b98f75
--- /dev/null
+++ b/src/csharp/Grpc.Core/ChannelState.cs
@@ -0,0 +1,69 @@
+#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
+{
+ /// <summary>
+ /// Connectivity state of a channel.
+ /// Based on grpc_connectivity_state from grpc/grpc.h
+ /// </summary>
+ public enum ChannelState
+ {
+ /// <summary>
+ /// Channel is idle
+ /// </summary>
+ Idle,
+
+ /// <summary>
+ /// Channel is connecting
+ /// </summary>
+ Connecting,
+
+ /// <summary>
+ /// Channel is ready for work
+ /// </summary>
+ Ready,
+
+ /// <summary>
+ /// Channel has seen a failure but expects to recover
+ /// </summary>
+ TransientFailure,
+
+ /// <summary>
+ /// Channel has seen a failure that it cannot recover from
+ /// </summary>
+ FatalFailure
+ }
+}
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index a099f96aea..88494bb4ac 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -76,19 +76,17 @@ namespace Grpc.Core
/// <summary>
/// Creates a new call to given method.
/// </summary>
- protected Call<TRequest, TResponse> CreateCall<TRequest, TResponse>(string serviceName, Method<TRequest, TResponse> method, Metadata metadata)
+ protected CallInvocationDetails<TRequest, TResponse> CreateCall<TRequest, TResponse>(Method<TRequest, TResponse> method, CallOptions options)
where TRequest : class
where TResponse : class
{
var interceptor = HeaderInterceptor;
if (interceptor != null)
{
- metadata = metadata ?? new Metadata();
- interceptor(metadata);
- metadata.Freeze();
+ interceptor(options.Headers);
+ options.Headers.Freeze();
}
- metadata = metadata ?? Metadata.Empty;
- return new Call<TRequest, TResponse>(serviceName, method, channel, metadata);
+ return new CallInvocationDetails<TRequest, TResponse>(channel, method, options);
}
}
}
diff --git a/src/csharp/Grpc.Core/Credentials.cs b/src/csharp/Grpc.Core/Credentials.cs
index e64c1e3dc1..4fcac0c4c0 100644
--- a/src/csharp/Grpc.Core/Credentials.cs
+++ b/src/csharp/Grpc.Core/Credentials.cs
@@ -41,39 +41,98 @@ namespace Grpc.Core
/// </summary>
public abstract class Credentials
{
+ static readonly Credentials InsecureInstance = new InsecureCredentialsImpl();
+
+ /// <summary>
+ /// Returns instance of credential that provides no security and
+ /// will result in creating an unsecure channel with no encryption whatsoever.
+ /// </summary>
+ public static Credentials Insecure
+ {
+ get
+ {
+ return InsecureInstance;
+ }
+ }
+
/// <summary>
- /// Creates native object for the credentials.
+ /// Creates native object for the credentials. May return null if insecure channel
+ /// should be created.
/// </summary>
/// <returns>The native credentials.</returns>
internal abstract CredentialsSafeHandle ToNativeCredentials();
+
+ private sealed class InsecureCredentialsImpl : Credentials
+ {
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ return null;
+ }
+ }
}
/// <summary>
/// Client-side SSL credentials.
/// </summary>
- public class SslCredentials : Credentials
+ public sealed class SslCredentials : Credentials
{
- string pemRootCerts;
+ readonly string rootCertificates;
+ readonly KeyCertificatePair keyCertificatePair;
- public SslCredentials(string pemRootCerts)
+ /// <summary>
+ /// Creates client-side SSL credentials loaded from
+ /// disk file pointed to by the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable.
+ /// If that fails, gets the roots certificates from a well known place on disk.
+ /// </summary>
+ public SslCredentials() : this(null, null)
{
- this.pemRootCerts = pemRootCerts;
+ }
+
+ /// <summary>
+ /// Creates client-side SSL credentials from
+ /// a string containing PEM encoded root certificates.
+ /// </summary>
+ public SslCredentials(string rootCertificates) : this(rootCertificates, null)
+ {
+ }
+
+ /// <summary>
+ /// Creates client-side SSL credentials.
+ /// </summary>
+ /// <param name="rootCertificates">string containing PEM encoded server root certificates.</param>
+ /// <param name="keyCertificatePair">a key certificate pair.</param>
+ public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair)
+ {
+ this.rootCertificates = rootCertificates;
+ this.keyCertificatePair = keyCertificatePair;
}
/// <summary>
/// PEM encoding of the server root certificates.
/// </summary>
- public string RootCerts
+ public string RootCertificates
+ {
+ get
+ {
+ return this.rootCertificates;
+ }
+ }
+
+ /// <summary>
+ /// Client side key and certificate pair.
+ /// If null, client will not use key and certificate pair.
+ /// </summary>
+ public KeyCertificatePair KeyCertificatePair
{
get
{
- return this.pemRootCerts;
+ return this.keyCertificatePair;
}
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
- return CredentialsSafeHandle.CreateSslCredentials(pemRootCerts);
+ return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
}
}
}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index fd68b91851..52defd1965 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -21,24 +21,29 @@
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>full</DebugType>
+ <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <DefineConstants>SIGNED</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Interactive.Async">
<HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
- <Reference Include="System.Collections.Immutable">
- <HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
- </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AsyncDuplexStreamingCall.cs" />
@@ -47,12 +52,11 @@
<Compile Include="IServerStreamWriter.cs" />
<Compile Include="IAsyncStreamWriter.cs" />
<Compile Include="IAsyncStreamReader.cs" />
- <Compile Include="Internal\GrpcLog.cs" />
+ <Compile Include="ServerPort.cs" />
<Compile Include="Version.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RpcException.cs" />
<Compile Include="Calls.cs" />
- <Compile Include="Call.cs" />
<Compile Include="AsyncClientStreamingCall.cs" />
<Compile Include="GrpcEnvironment.cs" />
<Compile Include="Status.cs" />
@@ -103,6 +107,14 @@
<Compile Include="ChannelOptions.cs" />
<Compile Include="AsyncUnaryCall.cs" />
<Compile Include="VersionInfo.cs" />
+ <Compile Include="Internal\CStringSafeHandle.cs" />
+ <Compile Include="KeyCertificatePair.cs" />
+ <Compile Include="Logging\ILogger.cs" />
+ <Compile Include="Logging\ConsoleLogger.cs" />
+ <Compile Include="Internal\NativeLogRedirector.cs" />
+ <Compile Include="ChannelState.cs" />
+ <Compile Include="CallInvocationDetails.cs" />
+ <Compile Include="CallOptions.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Grpc.Core.nuspec" />
@@ -133,4 +145,5 @@
</Target>
<Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" />
<Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" />
+ <ItemGroup />
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
index 5ace6dcf89..fe49efc7ec 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -15,15 +15,14 @@
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2</tags>
<dependencies>
- <dependency id="System.Collections.Immutable" version="1.1.36" />
<dependency id="Ix-Async" version="1.2.3" />
<dependency id="grpc.native.csharp_ext" version="$GrpcNativeCsharpExtVersion$" />
</dependencies>
</metadata>
<files>
- <file src="bin/Release/Grpc.Core.dll" target="lib/net45" />
- <file src="bin/Release/Grpc.Core.pdb" target="lib/net45" />
- <file src="bin/Release/Grpc.Core.xml" target="lib/net45" />
+ <file src="bin/ReleaseSigned/Grpc.Core.dll" target="lib/net45" />
+ <file src="bin/ReleaseSigned/Grpc.Core.pdb" target="lib/net45" />
+ <file src="bin/ReleaseSigned/Grpc.Core.xml" target="lib/net45" />
<file src="**\*.cs" target="src" />
</files>
</package>
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index 47d1651aab..034a66be3c 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -35,6 +35,7 @@ using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Grpc.Core.Internal;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core
@@ -55,6 +56,8 @@ namespace Grpc.Core
static object staticLock = new object();
static GrpcEnvironment instance;
+ static ILogger logger = new ConsoleLogger();
+
readonly GrpcThreadPool threadPool;
readonly CompletionRegistry completionRegistry;
readonly DebugStats debugStats = new DebugStats();
@@ -93,17 +96,38 @@ namespace Grpc.Core
}
/// <summary>
+ /// Gets application-wide logger used by gRPC.
+ /// </summary>
+ /// <value>The logger.</value>
+ public static ILogger Logger
+ {
+ get
+ {
+ return logger;
+ }
+ }
+
+ /// <summary>
+ /// Sets the application-wide logger that should be used by gRPC.
+ /// </summary>
+ public static void SetLogger(ILogger customLogger)
+ {
+ Preconditions.CheckNotNull(customLogger);
+ logger = customLogger;
+ }
+
+ /// <summary>
/// Creates gRPC environment.
/// </summary>
private GrpcEnvironment()
{
- GrpcLog.RedirectNativeLogs(Console.Error);
+ NativeLogRedirector.Redirect();
grpcsharp_init();
completionRegistry = new CompletionRegistry(this);
threadPool = new GrpcThreadPool(this, THREAD_POOL_SIZE);
threadPool.Start();
// TODO: use proper logging here
- Console.WriteLine("GRPC initialized.");
+ Logger.Info("gRPC initialized.");
}
/// <summary>
@@ -154,8 +178,7 @@ namespace Grpc.Core
debugStats.CheckOK();
- // TODO: use proper logging here
- Console.WriteLine("GRPC shutdown.");
+ Logger.Info("gRPC shutdown.");
}
/// <summary>
@@ -171,7 +194,7 @@ namespace Grpc.Core
}
catch (Exception e)
{
- Console.WriteLine("Error occured while shutting down GrpcEnvironment: " + 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 f983dbb759..414b5c4282 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -38,6 +38,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
@@ -47,7 +48,9 @@ namespace Grpc.Core.Internal
/// </summary>
internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse>
{
- Channel channel;
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCall<TRequest, TResponse>>();
+
+ readonly CallInvocationDetails<TRequest, TResponse> callDetails;
// Completion of a pending unary response if not null.
TaskCompletionSource<TResponse> unaryResponseTcs;
@@ -57,26 +60,18 @@ namespace Grpc.Core.Internal
bool readObserverCompleted; // True if readObserver has already been completed.
- public AsyncCall(Func<TRequest, byte[]> serializer, Func<byte[], TResponse> deserializer) : base(serializer, deserializer)
+ public AsyncCall(CallInvocationDetails<TRequest, TResponse> callDetails)
+ : base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer)
{
- }
-
- public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName)
- {
- this.channel = channel;
- var call = CallSafeHandle.Create(channel.Handle, channel.CompletionRegistry, cq, methodName, channel.Target, Timespec.InfFuture);
- channel.Environment.DebugStats.ActiveClientCalls.Increment();
- InitializeInternal(call);
+ this.callDetails = callDetails;
}
// TODO: this method is not Async, so it shouldn't be in AsyncCall class, but
// it is reusing fair amount of code in this class, so we are leaving it here.
- // TODO: for other calls, you need to call Initialize, this methods calls initialize
- // on its own, so there's a usage inconsistency.
/// <summary>
/// Blocking unary request - unary response call.
/// </summary>
- public TResponse UnaryCall(Channel channel, string methodName, TRequest msg, Metadata headers)
+ public TResponse UnaryCall(TRequest msg)
{
using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create())
{
@@ -86,13 +81,15 @@ namespace Grpc.Core.Internal
lock (myLock)
{
- Initialize(channel, cq, methodName);
+ Preconditions.CheckState(!started);
started = true;
+ Initialize(cq);
+
halfcloseRequested = true;
readingDone = true;
}
- using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers))
{
using (var ctx = BatchContextSafeHandle.Create())
{
@@ -106,7 +103,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured while invoking completion delegate: " + e);
+ Logger.Error(e, "Exception occured while invoking completion delegate.");
}
}
}
@@ -126,20 +123,22 @@ namespace Grpc.Core.Internal
/// <summary>
/// Starts a unary request - unary response call.
/// </summary>
- public Task<TResponse> UnaryCallAsync(TRequest msg, Metadata headers)
+ public Task<TResponse> UnaryCallAsync(TRequest msg)
{
lock (myLock)
{
- Preconditions.CheckNotNull(call);
-
+ Preconditions.CheckState(!started);
started = true;
+
+ Initialize(callDetails.Channel.Environment.CompletionQueue);
+
halfcloseRequested = true;
readingDone = true;
byte[] payload = UnsafeSerialize(msg);
unaryResponseTcs = new TaskCompletionSource<TResponse>();
- using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers))
{
call.StartUnary(payload, HandleUnaryResponse, metadataArray);
}
@@ -151,17 +150,19 @@ namespace Grpc.Core.Internal
/// Starts a streamed request - unary response call.
/// Use StartSendMessage and StartSendCloseFromClient to stream requests.
/// </summary>
- public Task<TResponse> ClientStreamingCallAsync(Metadata headers)
+ public Task<TResponse> ClientStreamingCallAsync()
{
lock (myLock)
{
- Preconditions.CheckNotNull(call);
-
+ Preconditions.CheckState(!started);
started = true;
+
+ Initialize(callDetails.Channel.Environment.CompletionQueue);
+
readingDone = true;
unaryResponseTcs = new TaskCompletionSource<TResponse>();
- using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers))
{
call.StartClientStreaming(HandleUnaryResponse, metadataArray);
}
@@ -173,19 +174,21 @@ namespace Grpc.Core.Internal
/// <summary>
/// Starts a unary request - streamed response call.
/// </summary>
- public void StartServerStreamingCall(TRequest msg, Metadata headers)
+ public void StartServerStreamingCall(TRequest msg)
{
lock (myLock)
{
- Preconditions.CheckNotNull(call);
-
+ Preconditions.CheckState(!started);
started = true;
+
+ Initialize(callDetails.Channel.Environment.CompletionQueue);
+
halfcloseRequested = true;
halfclosed = true; // halfclose not confirmed yet, but it will be once finishedHandler is called.
byte[] payload = UnsafeSerialize(msg);
- using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers))
{
call.StartServerStreaming(payload, HandleFinished, metadataArray);
}
@@ -196,15 +199,16 @@ namespace Grpc.Core.Internal
/// Starts a streaming request - streaming response call.
/// Use StartSendMessage and StartSendCloseFromClient to stream requests.
/// </summary>
- public void StartDuplexStreamingCall(Metadata headers)
+ public void StartDuplexStreamingCall()
{
lock (myLock)
{
- Preconditions.CheckNotNull(call);
-
+ Preconditions.CheckState(!started);
started = true;
- using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ Initialize(callDetails.Channel.Environment.CompletionQueue);
+
+ using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers))
{
call.StartDuplexStreaming(HandleFinished, metadataArray);
}
@@ -306,7 +310,26 @@ namespace Grpc.Core.Internal
protected override void OnReleaseResources()
{
- channel.Environment.DebugStats.ActiveClientCalls.Decrement();
+ callDetails.Channel.Environment.DebugStats.ActiveClientCalls.Decrement();
+ }
+
+ private void Initialize(CompletionQueueSafeHandle cq)
+ {
+ var call = callDetails.Channel.Handle.CreateCall(callDetails.Channel.Environment.CompletionRegistry, cq,
+ callDetails.Method, callDetails.Host, Timespec.FromDateTime(callDetails.Options.Deadline));
+ callDetails.Channel.Environment.DebugStats.ActiveClientCalls.Increment();
+ InitializeInternal(call);
+ RegisterCancellationCallback();
+ }
+
+ // Make sure that once cancellationToken for this call is cancelled, Cancel() will be called.
+ private void RegisterCancellationCallback()
+ {
+ var token = callDetails.Options.CancellationToken;
+ if (token.CanBeCanceled)
+ {
+ token.Register(() => this.Cancel());
+ }
}
/// <summary>
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index 64713c8c52..38f2a5baeb 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -38,6 +38,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
@@ -48,6 +49,8 @@ namespace Grpc.Core.Internal
/// </summary>
internal abstract class AsyncCallBase<TWrite, TRead>
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCallBase<TWrite, TRead>>();
+
readonly Func<TWrite, byte[]> serializer;
readonly Func<byte[], TRead> deserializer;
@@ -233,9 +236,9 @@ namespace Grpc.Core.Internal
payload = serializer(msg);
return true;
}
- catch (Exception)
+ catch (Exception e)
{
- Console.WriteLine("Exception occured while trying to serialize message");
+ Logger.Error(e, "Exception occured while trying to serialize message");
payload = null;
return false;
}
@@ -248,9 +251,9 @@ namespace Grpc.Core.Internal
msg = deserializer(payload);
return true;
}
- catch (Exception)
+ catch (Exception e)
{
- Console.WriteLine("Exception occured while trying to deserialize message");
+ Logger.Error(e, "Exception occured while trying to deserialize message.");
msg = default(TRead);
return false;
}
@@ -264,7 +267,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured while invoking completion delegate: " + e);
+ Logger.Error(e, "Exception occured while invoking completion delegate.");
}
}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index f809f4a84c..513902ee36 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -48,6 +48,7 @@ namespace Grpc.Core.Internal
internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest>
{
readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>();
+ readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
readonly GrpcEnvironment environment;
public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, GrpcEnvironment environment) : base(serializer, deserializer)
@@ -118,6 +119,26 @@ namespace Grpc.Core.Internal
}
}
+ /// <summary>
+ /// Gets cancellation token that gets cancelled once close completion
+ /// is received and the cancelled flag is set.
+ /// </summary>
+ public CancellationToken CancellationToken
+ {
+ get
+ {
+ return cancellationTokenSource.Token;
+ }
+ }
+
+ public string Peer
+ {
+ get
+ {
+ return call.GetPeer();
+ }
+ }
+
protected override void OnReleaseResources()
{
environment.DebugStats.ActiveServerCalls.Decrement();
@@ -138,6 +159,8 @@ namespace Grpc.Core.Internal
{
// Once we cancel, we don't have to care that much
// about reads and writes.
+
+ // TODO(jtattermusch): is this still necessary?
Cancel();
}
@@ -145,6 +168,11 @@ namespace Grpc.Core.Internal
}
// TODO(jtattermusch): handle error
+ if (cancelled)
+ {
+ cancellationTokenSource.Cancel();
+ }
+
finishedServersideTcs.SetResult(null);
}
}
diff --git a/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs
new file mode 100644
index 0000000000..92fbe8cf0f
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs
@@ -0,0 +1,60 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+namespace Grpc.Core.Internal
+{
+ /// <summary>
+ /// Owned char* object.
+ /// </summary>
+ internal class CStringSafeHandle : SafeHandleZeroIsInvalid
+ {
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void gprsharp_free(IntPtr ptr);
+
+ private CStringSafeHandle()
+ {
+ }
+
+ public string GetValue()
+ {
+ return Marshal.PtrToStringAnsi(handle);
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ gprsharp_free(handle);
+ return true;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index 19dbb83f24..714749b171 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -46,9 +46,6 @@ namespace Grpc.Core.Internal
CompletionRegistry completionRegistry;
[DllImport("grpc_csharp_ext.dll")]
- static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
-
- [DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_cancel(CallSafeHandle call);
[DllImport("grpc_csharp_ext.dll")]
@@ -92,19 +89,15 @@ namespace Grpc.Core.Internal
BatchContextSafeHandle ctx);
[DllImport("grpc_csharp_ext.dll")]
+ static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call);
+
+ [DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_call_destroy(IntPtr call);
private CallSafeHandle()
{
}
- public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionRegistry registry, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
- {
- var result = grpcsharp_channel_create_call(channel, cq, method, host, deadline);
- result.SetCompletionRegistry(registry);
- return result;
- }
-
public void SetCompletionRegistry(CompletionRegistry completionRegistry)
{
this.completionRegistry = completionRegistry;
@@ -190,6 +183,14 @@ namespace Grpc.Core.Internal
grpcsharp_call_cancel_with_status(this, status.StatusCode, status.Detail).CheckOk();
}
+ public string GetPeer()
+ {
+ using (var cstring = grpcsharp_call_get_peer(this))
+ {
+ return cstring.GetValue();
+ }
+ }
+
protected override bool ReleaseHandle()
{
grpcsharp_call_destroy(handle);
diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
index f046f4c6d0..7324ebdf57 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
@@ -41,21 +41,34 @@ namespace Grpc.Core.Internal
internal class ChannelSafeHandle : SafeHandleZeroIsInvalid
{
[DllImport("grpc_csharp_ext.dll")]
- static extern ChannelSafeHandle grpcsharp_channel_create(string target, ChannelArgsSafeHandle channelArgs);
+ static extern ChannelSafeHandle grpcsharp_insecure_channel_create(string target, ChannelArgsSafeHandle channelArgs);
[DllImport("grpc_csharp_ext.dll")]
static extern ChannelSafeHandle grpcsharp_secure_channel_create(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs);
[DllImport("grpc_csharp_ext.dll")]
+ static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern ChannelState grpcsharp_channel_check_connectivity_state(ChannelSafeHandle channel, int tryToConnect);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_channel_watch_connectivity_state(ChannelSafeHandle channel, ChannelState lastObservedState,
+ Timespec deadline, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern CStringSafeHandle grpcsharp_channel_get_target(ChannelSafeHandle call);
+
+ [DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_channel_destroy(IntPtr channel);
private ChannelSafeHandle()
{
}
- public static ChannelSafeHandle Create(string target, ChannelArgsSafeHandle channelArgs)
+ public static ChannelSafeHandle CreateInsecure(string target, ChannelArgsSafeHandle channelArgs)
{
- return grpcsharp_channel_create(target, channelArgs);
+ return grpcsharp_insecure_channel_create(target, channelArgs);
}
public static ChannelSafeHandle CreateSecure(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs)
@@ -63,6 +76,34 @@ namespace Grpc.Core.Internal
return grpcsharp_secure_channel_create(credentials, target, channelArgs);
}
+ public CallSafeHandle CreateCall(CompletionRegistry registry, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
+ {
+ var result = grpcsharp_channel_create_call(this, cq, method, host, deadline);
+ result.SetCompletionRegistry(registry);
+ return result;
+ }
+
+ public ChannelState CheckConnectivityState(bool tryToConnect)
+ {
+ return grpcsharp_channel_check_connectivity_state(this, tryToConnect ? 1 : 0);
+ }
+
+ public void WatchConnectivityState(ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq,
+ CompletionRegistry completionRegistry, BatchCompletionDelegate callback)
+ {
+ var ctx = BatchContextSafeHandle.Create();
+ completionRegistry.RegisterBatchCompletion(ctx, callback);
+ grpcsharp_channel_watch_connectivity_state(this, lastObservedState, deadline, cq, ctx);
+ }
+
+ public string GetTarget()
+ {
+ using (var cstring = grpcsharp_channel_get_target(this))
+ {
+ return cstring.GetValue();
+ }
+ }
+
protected override bool ReleaseHandle()
{
grpcsharp_channel_destroy(handle);
diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
index f6d8aa0600..2796c959a3 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
@@ -35,6 +35,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.InteropServices;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
@@ -45,6 +46,8 @@ namespace Grpc.Core.Internal
internal class CompletionRegistry
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<CompletionRegistry>();
+
readonly GrpcEnvironment environment;
readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>();
@@ -81,7 +84,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured while invoking completion delegate: " + e);
+ Logger.Error(e, "Exception occured while invoking completion delegate.");
}
finally
{
diff --git a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
index f361199068..8b4fa85e5d 100644
--- a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
@@ -50,9 +50,23 @@ namespace Grpc.Core.Internal
{
}
- public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts)
+ public static CredentialsSafeHandle CreateNullCredentials()
{
- return grpcsharp_ssl_credentials_create(pemRootCerts, null, null);
+ var creds = new CredentialsSafeHandle();
+ creds.SetHandle(IntPtr.Zero);
+ return creds;
+ }
+
+ public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair)
+ {
+ if (keyCertPair != null)
+ {
+ return grpcsharp_ssl_credentials_create(pemRootCerts, keyCertPair.CertificateChain, keyCertPair.PrivateKey);
+ }
+ else
+ {
+ return grpcsharp_ssl_credentials_create(pemRootCerts, null, null);
+ }
}
protected override bool ReleaseHandle()
diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
index b77e893044..cb4c7c821e 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
@@ -36,7 +36,7 @@ using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
-using Grpc.Core.Internal;
+using Grpc.Core.Logging;
namespace Grpc.Core.Internal
{
@@ -45,6 +45,8 @@ namespace Grpc.Core.Internal
/// </summary>
internal class GrpcThreadPool
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<GrpcThreadPool>();
+
readonly GrpcEnvironment environment;
readonly object myLock = new object();
readonly List<Thread> threads = new List<Thread>();
@@ -82,7 +84,7 @@ namespace Grpc.Core.Internal
{
cq.Shutdown();
- Console.WriteLine("Waiting for GRPC threads to finish.");
+ Logger.Info("Waiting for GRPC threads to finish.");
foreach (var thread in threads)
{
thread.Join();
@@ -129,12 +131,12 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured while invoking completion delegate: " + e);
+ Logger.Error(e, "Exception occured while invoking completion delegate");
}
}
}
while (ev.type != GRPCCompletionType.Shutdown);
- Console.WriteLine("Completion queue has shutdown successfully, thread " + Thread.CurrentThread.Name + " exiting.");
+ Logger.Info("Completion queue has shutdown successfully, thread {0} exiting.", Thread.CurrentThread.Name);
}
}
}
diff --git a/src/csharp/Grpc.Core/Internal/GrpcLog.cs b/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
index 2f3c8ad71c..b8a55c5fe8 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcLog.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
@@ -44,30 +44,26 @@ namespace Grpc.Core.Internal
/// <summary>
/// Logs from gRPC C core library can get lost if your application is not a console app.
- /// This class allows redirection of logs to arbitrary destination.
+ /// This class allows redirection of logs to gRPC logger.
/// </summary>
- internal static class GrpcLog
+ internal static class NativeLogRedirector
{
static object staticLock = new object();
static GprLogDelegate writeCallback;
- static TextWriter dest;
[DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_redirect_log(GprLogDelegate callback);
/// <summary>
- /// Sets text writer as destination for logs from native gRPC C core library.
- /// Only first invocation has effect.
+ /// Redirects logs from native gRPC C core library to a general logger.
/// </summary>
- /// <param name="textWriter"></param>
- public static void RedirectNativeLogs(TextWriter textWriter)
+ public static void Redirect()
{
lock (staticLock)
{
if (writeCallback == null)
{
writeCallback = new GprLogDelegate(HandleWrite);
- dest = textWriter;
grpcsharp_redirect_log(writeCallback);
}
}
@@ -77,13 +73,30 @@ namespace Grpc.Core.Internal
{
try
{
- // TODO: DateTime format used here is different than in C core.
- dest.WriteLine(string.Format("{0}{1} {2} {3}:{4}: {5}",
- Marshal.PtrToStringAnsi(severityStringPtr), DateTime.Now,
+ var logger = GrpcEnvironment.Logger;
+ string severityString = Marshal.PtrToStringAnsi(severityStringPtr);
+ string message = string.Format("{0} {1}:{2}: {3}",
threadId,
Marshal.PtrToStringAnsi(fileStringPtr),
line,
- Marshal.PtrToStringAnsi(msgPtr)));
+ Marshal.PtrToStringAnsi(msgPtr));
+
+ switch (severityString)
+ {
+ case "D":
+ logger.Debug(message);
+ break;
+ case "I":
+ logger.Info(message);
+ break;
+ case "E":
+ logger.Error(message);
+ break;
+ default:
+ // severity not recognized, default to error.
+ logger.Error(message);
+ break;
+ }
}
catch (Exception e)
{
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index 3680b1e791..19f0e3c57f 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -37,6 +37,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
@@ -50,6 +51,8 @@ namespace Grpc.Core.Internal
where TRequest : class
where TResponse : class
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<UnaryServerCallHandler<TRequest, TResponse>>();
+
readonly Method<TRequest, TResponse> method;
readonly UnaryServerMethod<TRequest, TResponse> handler;
@@ -72,7 +75,7 @@ namespace Grpc.Core.Internal
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
- var context = HandlerUtils.NewContext(newRpc);
+ var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken);
try
{
Preconditions.CheckArgument(await requestStream.MoveNext());
@@ -85,7 +88,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured in handler: " + e);
+ Logger.Error(e, "Exception occured in handler.");
status = HandlerUtils.StatusFromException(e);
}
try
@@ -104,6 +107,8 @@ namespace Grpc.Core.Internal
where TRequest : class
where TResponse : class
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<ServerStreamingServerCallHandler<TRequest, TResponse>>();
+
readonly Method<TRequest, TResponse> method;
readonly ServerStreamingServerMethod<TRequest, TResponse> handler;
@@ -126,7 +131,7 @@ namespace Grpc.Core.Internal
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
- var context = HandlerUtils.NewContext(newRpc);
+ var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken);
try
{
Preconditions.CheckArgument(await requestStream.MoveNext());
@@ -138,7 +143,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured in handler: " + e);
+ Logger.Error(e, "Exception occured in handler.");
status = HandlerUtils.StatusFromException(e);
}
@@ -158,6 +163,8 @@ namespace Grpc.Core.Internal
where TRequest : class
where TResponse : class
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<ClientStreamingServerCallHandler<TRequest, TResponse>>();
+
readonly Method<TRequest, TResponse> method;
readonly ClientStreamingServerMethod<TRequest, TResponse> handler;
@@ -180,7 +187,7 @@ namespace Grpc.Core.Internal
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
- var context = HandlerUtils.NewContext(newRpc);
+ var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken);
try
{
var result = await handler(requestStream, context);
@@ -196,7 +203,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured in handler: " + e);
+ Logger.Error(e, "Exception occured in handler.");
status = HandlerUtils.StatusFromException(e);
}
@@ -216,6 +223,8 @@ namespace Grpc.Core.Internal
where TRequest : class
where TResponse : class
{
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<DuplexStreamingServerCallHandler<TRequest, TResponse>>();
+
readonly Method<TRequest, TResponse> method;
readonly DuplexStreamingServerMethod<TRequest, TResponse> handler;
@@ -238,7 +247,7 @@ namespace Grpc.Core.Internal
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
- var context = HandlerUtils.NewContext(newRpc);
+ var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken);
try
{
await handler(requestStream, responseStream, context);
@@ -246,7 +255,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Console.WriteLine("Exception occured in handler: " + e);
+ Logger.Error(e, "Exception occured in handler.");
status = HandlerUtils.StatusFromException(e);
}
try
@@ -295,11 +304,13 @@ namespace Grpc.Core.Internal
return new Status(StatusCode.Unknown, "Exception was thrown by handler.");
}
- public static ServerCallContext NewContext(ServerRpcNew newRpc)
+ public static ServerCallContext NewContext(ServerRpcNew newRpc, string peer, CancellationToken cancellationToken)
{
+ DateTime realtimeDeadline = newRpc.Deadline.ToClockType(GPRClockType.Realtime).ToDateTime();
+
return new ServerCallContext(
- newRpc.Method, newRpc.Host, newRpc.Deadline.ToDateTime(),
- newRpc.RequestMetadata, CancellationToken.None);
+ newRpc.Method, newRpc.Host, peer, realtimeDeadline,
+ newRpc.RequestMetadata, cancellationToken);
}
}
}
diff --git a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
index 961180741a..37a4f5256b 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
@@ -42,7 +42,7 @@ namespace Grpc.Core.Internal
internal class ServerCredentialsSafeHandle : SafeHandleZeroIsInvalid
{
[DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
- static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs);
+ static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, bool forceClientAuth);
[DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_server_credentials_release(IntPtr credentials);
@@ -51,12 +51,13 @@ namespace Grpc.Core.Internal
{
}
- public static ServerCredentialsSafeHandle CreateSslCredentials(string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray)
+ public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, bool forceClientAuth)
{
Preconditions.CheckArgument(keyCertPairCertChainArray.Length == keyCertPairPrivateKeyArray.Length);
- return grpcsharp_ssl_server_credentials_create(null,
+ return grpcsharp_ssl_server_credentials_create(pemRootCerts,
keyCertPairCertChainArray, keyCertPairPrivateKeyArray,
- new UIntPtr((ulong)keyCertPairCertChainArray.Length));
+ new UIntPtr((ulong)keyCertPairCertChainArray.Length),
+ forceClientAuth);
}
protected override bool ReleaseHandle()
diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
index 9e1170e6dd..f9b44b1acf 100644
--- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
@@ -48,7 +48,7 @@ namespace Grpc.Core.Internal
static extern ServerSafeHandle grpcsharp_server_create(CompletionQueueSafeHandle cq, ChannelArgsSafeHandle args);
[DllImport("grpc_csharp_ext.dll")]
- static extern int grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr);
+ static extern int grpcsharp_server_add_insecure_http2_port(ServerSafeHandle server, string addr);
[DllImport("grpc_csharp_ext.dll")]
static extern int grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds);
@@ -77,12 +77,12 @@ namespace Grpc.Core.Internal
return grpcsharp_server_create(cq, args);
}
- public int AddListeningPort(string addr)
+ public int AddInsecurePort(string addr)
{
- return grpcsharp_server_add_http2_port(this, addr);
+ return grpcsharp_server_add_insecure_http2_port(this, addr);
}
- public int AddListeningPort(string addr, ServerCredentialsSafeHandle credentials)
+ public int AddSecurePort(string addr, ServerCredentialsSafeHandle credentials)
{
return grpcsharp_server_add_secure_http2_port(this, addr, credentials);
}
diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs
index da2819f14d..e83d21f4a4 100644
--- a/src/csharp/Grpc.Core/Internal/Timespec.cs
+++ b/src/csharp/Grpc.Core/Internal/Timespec.cs
@@ -32,6 +32,8 @@ using System;
using System.Runtime.InteropServices;
using System.Threading;
+using Grpc.Core.Utils;
+
namespace Grpc.Core.Internal
{
/// <summary>
@@ -40,32 +42,43 @@ namespace Grpc.Core.Internal
[StructLayout(LayoutKind.Sequential)]
internal struct Timespec
{
- const int NanosPerSecond = 1000 * 1000 * 1000;
- const int NanosPerTick = 100;
+ const long NanosPerSecond = 1000 * 1000 * 1000;
+ const long NanosPerTick = 100;
+ const long TicksPerSecond = NanosPerSecond / NanosPerTick;
static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
[DllImport("grpc_csharp_ext.dll")]
- static extern Timespec gprsharp_now();
+ static extern Timespec gprsharp_now(GPRClockType clockType);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern Timespec gprsharp_inf_future(GPRClockType clockType);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern Timespec gprsharp_inf_past(GPRClockType clockType);
[DllImport("grpc_csharp_ext.dll")]
- static extern Timespec gprsharp_inf_future();
+ static extern Timespec gprsharp_convert_clock_type(Timespec t, GPRClockType targetClock);
[DllImport("grpc_csharp_ext.dll")]
static extern int gprsharp_sizeof_timespec();
- public Timespec(IntPtr tv_sec, int tv_nsec)
+ public Timespec(IntPtr tv_sec, int tv_nsec) : this(tv_sec, tv_nsec, GPRClockType.Realtime)
+ {
+ }
+
+ public Timespec(IntPtr tv_sec, int tv_nsec, GPRClockType clock_type)
{
this.tv_sec = tv_sec;
this.tv_nsec = tv_nsec;
- this.clock_type = GPRClockType.Realtime;
+ this.clock_type = clock_type;
}
// NOTE: on linux 64bit sizeof(gpr_timespec) = 16, on windows 32bit sizeof(gpr_timespec) = 8
// so IntPtr seems to have the right size to work on both.
- public System.IntPtr tv_sec;
- public int tv_nsec;
- public GPRClockType clock_type;
+ private System.IntPtr tv_sec;
+ private int tv_nsec;
+ private GPRClockType clock_type;
/// <summary>
/// Timespec a long time in the future.
@@ -74,54 +87,164 @@ namespace Grpc.Core.Internal
{
get
{
- return gprsharp_inf_future();
+ return gprsharp_inf_future(GPRClockType.Realtime);
+ }
+ }
+
+ /// <summary>
+ /// Timespec a long time in the past.
+ /// </summary>
+ public static Timespec InfPast
+ {
+ get
+ {
+ return gprsharp_inf_past(GPRClockType.Realtime);
}
}
+ /// <summary>
+ /// Return Timespec representing the current time.
+ /// </summary>
public static Timespec Now
{
get
{
- return gprsharp_now();
+ return gprsharp_now(GPRClockType.Realtime);
}
}
-
- public DateTime ToDateTime()
+
+ /// <summary>
+ /// Seconds since unix epoch.
+ /// </summary>
+ public IntPtr TimevalSeconds
{
- return UnixEpoch.AddTicks(tv_sec.ToInt64() * (NanosPerSecond / NanosPerTick) + tv_nsec / NanosPerTick);
+ get
+ {
+ return tv_sec;
+ }
}
- internal static int NativeSize
+ /// <summary>
+ /// The nanoseconds part of timeval.
+ /// </summary>
+ public int TimevalNanos
{
get
{
- return gprsharp_sizeof_timespec();
+ return tv_nsec;
}
}
/// <summary>
- /// Creates a GPR deadline from current instant and given timeout.
+ /// Converts the timespec to desired clock type.
/// </summary>
- /// <returns>The from timeout.</returns>
- public static Timespec DeadlineFromTimeout(TimeSpan timeout)
+ public Timespec ToClockType(GPRClockType targetClock)
+ {
+ return gprsharp_convert_clock_type(this, targetClock);
+ }
+
+ /// <summary>
+ /// Converts Timespec to DateTime.
+ /// Timespec needs to be of type GPRClockType.Realtime and needs to represent a legal value.
+ /// DateTime has lower resolution (100ns), so rounding can occurs.
+ /// Value are always rounded up to the nearest DateTime value in the future.
+ ///
+ /// For Timespec.InfFuture or if timespec is after the largest representable DateTime, DateTime.MaxValue is returned.
+ /// For Timespec.InfPast or if timespec is before the lowest representable DateTime, DateTime.MinValue is returned.
+ ///
+ /// Unless DateTime.MaxValue or DateTime.MinValue is returned, the resulting DateTime is always in UTC
+ /// (DateTimeKind.Utc)
+ /// </summary>
+ public DateTime ToDateTime()
{
- if (timeout == Timeout.InfiniteTimeSpan)
+ Preconditions.CheckState(tv_nsec >= 0 && tv_nsec < NanosPerSecond);
+ Preconditions.CheckState(clock_type == GPRClockType.Realtime);
+
+ // fast path for InfFuture
+ if (this.Equals(InfFuture))
+ {
+ return DateTime.MaxValue;
+ }
+
+ // fast path for InfPast
+ if (this.Equals(InfPast))
+ {
+ return DateTime.MinValue;
+ }
+
+ try
+ {
+ // convert nanos to ticks, round up to the nearest tick
+ long ticksFromNanos = tv_nsec / NanosPerTick + ((tv_nsec % NanosPerTick != 0) ? 1 : 0);
+ long ticksTotal = checked(tv_sec.ToInt64() * TicksPerSecond + ticksFromNanos);
+ return UnixEpoch.AddTicks(ticksTotal);
+ }
+ catch (OverflowException)
+ {
+ // ticks out of long range
+ return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue;
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ // resulting date time would be larger than MaxValue
+ return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue;
+ }
+ }
+
+ /// <summary>
+ /// Creates DateTime to Timespec.
+ /// DateTime has to be in UTC (DateTimeKind.Utc) unless it's DateTime.MaxValue or DateTime.MinValue.
+ /// For DateTime.MaxValue of date time after the largest representable Timespec, Timespec.InfFuture is returned.
+ /// For DateTime.MinValue of date time before the lowest representable Timespec, Timespec.InfPast is returned.
+ /// </summary>
+ /// <returns>The date time.</returns>
+ /// <param name="dateTime">Date time.</param>
+ public static Timespec FromDateTime(DateTime dateTime)
+ {
+ if (dateTime == DateTime.MaxValue)
{
return Timespec.InfFuture;
}
- return Timespec.Now.Add(timeout);
+
+ if (dateTime == DateTime.MinValue)
+ {
+ return Timespec.InfPast;
+ }
+
+ Preconditions.CheckArgument(dateTime.Kind == DateTimeKind.Utc, "dateTime");
+
+ try
+ {
+ TimeSpan timeSpan = dateTime - UnixEpoch;
+ long ticks = timeSpan.Ticks;
+
+ long seconds = ticks / TicksPerSecond;
+ int nanos = (int)((ticks % TicksPerSecond) * NanosPerTick);
+ if (nanos < 0)
+ {
+ // correct the result based on C# modulo semantics for negative dividend
+ seconds--;
+ nanos += (int)NanosPerSecond;
+ }
+ // new IntPtr possibly throws OverflowException
+ return new Timespec(new IntPtr(seconds), nanos);
+ }
+ catch (OverflowException)
+ {
+ return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfPast;
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfPast;
+ }
}
- public Timespec Add(TimeSpan timeSpan)
+ internal static int NativeSize
{
- long nanos = (long)tv_nsec + (timeSpan.Ticks % TimeSpan.TicksPerSecond) * NanosPerTick;
- long overflow_sec = (nanos > NanosPerSecond) ? 1 : 0;
-
- Timespec result;
- result.tv_nsec = (int)(nanos % NanosPerSecond);
- result.tv_sec = new IntPtr(tv_sec.ToInt64() + (timeSpan.Ticks / TimeSpan.TicksPerSecond) + overflow_sec);
- result.clock_type = GPRClockType.Realtime;
- return result;
+ get
+ {
+ return gprsharp_sizeof_timespec();
+ }
}
}
}
diff --git a/src/csharp/Grpc.Core/KeyCertificatePair.cs b/src/csharp/Grpc.Core/KeyCertificatePair.cs
new file mode 100644
index 0000000000..5def15a656
--- /dev/null
+++ b/src/csharp/Grpc.Core/KeyCertificatePair.cs
@@ -0,0 +1,83 @@
+#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 Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Key certificate pair (in PEM encoding).
+ /// </summary>
+ public sealed class KeyCertificatePair
+ {
+ readonly string certificateChain;
+ readonly string privateKey;
+
+ /// <summary>
+ /// Creates a new certificate chain - private key pair.
+ /// </summary>
+ /// <param name="certificateChain">PEM encoded certificate chain.</param>
+ /// <param name="privateKey">PEM encoded private key.</param>
+ public KeyCertificatePair(string certificateChain, string privateKey)
+ {
+ this.certificateChain = Preconditions.CheckNotNull(certificateChain);
+ this.privateKey = Preconditions.CheckNotNull(privateKey);
+ }
+
+ /// <summary>
+ /// PEM encoded certificate chain.
+ /// </summary>
+ public string CertificateChain
+ {
+ get
+ {
+ return certificateChain;
+ }
+ }
+
+ /// <summary>
+ /// PEM encoded private key.
+ /// </summary>
+ public string PrivateKey
+ {
+ get
+ {
+ return privateKey;
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
new file mode 100644
index 0000000000..c67765c78d
--- /dev/null
+++ b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
@@ -0,0 +1,103 @@
+#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;
+
+namespace Grpc.Core.Logging
+{
+ /// <summary>Logger that logs to System.Console.</summary>
+ public class ConsoleLogger : ILogger
+ {
+ readonly Type forType;
+ readonly string forTypeString;
+
+ public ConsoleLogger() : this(null)
+ {
+ }
+
+ private ConsoleLogger(Type forType)
+ {
+ this.forType = forType;
+ this.forTypeString = forType != null ? forType.FullName + " " : "";
+ }
+
+ public ILogger ForType<T>()
+ {
+ if (typeof(T) == forType)
+ {
+ return this;
+ }
+ return new ConsoleLogger(typeof(T));
+ }
+
+ public void Debug(string message, params object[] formatArgs)
+ {
+ Log("D", message, formatArgs);
+ }
+
+ public void Info(string message, params object[] formatArgs)
+ {
+ Log("I", message, formatArgs);
+ }
+
+ public void Warning(string message, params object[] formatArgs)
+ {
+ Log("W", message, formatArgs);
+ }
+
+ public void Warning(Exception exception, string message, params object[] formatArgs)
+ {
+ Log("W", message + " " + exception, formatArgs);
+ }
+
+ public void Error(string message, params object[] formatArgs)
+ {
+ Log("E", message, formatArgs);
+ }
+
+ public void Error(Exception exception, string message, params object[] formatArgs)
+ {
+ Log("E", message + " " + exception, formatArgs);
+ }
+
+ private void Log(string severityString, string message, object[] formatArgs)
+ {
+ Console.Error.WriteLine("{0}{1} {2}{3}",
+ severityString,
+ DateTime.Now,
+ forTypeString,
+ string.Format(message, formatArgs));
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Logging/ILogger.cs b/src/csharp/Grpc.Core/Logging/ILogger.cs
new file mode 100644
index 0000000000..0d58f133e3
--- /dev/null
+++ b/src/csharp/Grpc.Core/Logging/ILogger.cs
@@ -0,0 +1,57 @@
+#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;
+
+namespace Grpc.Core.Logging
+{
+ /// <summary>For logging messages.</summary>
+ public interface ILogger
+ {
+ /// <summary>Returns a logger associated with the specified type.</summary>
+ ILogger ForType<T>();
+
+ void Debug(string message, params object[] formatArgs);
+
+ void Info(string message, params object[] formatArgs);
+
+ void Warning(string message, params object[] formatArgs);
+
+ void Warning(Exception exception, string message, params object[] formatArgs);
+
+ void Error(string message, params object[] formatArgs);
+
+ void Error(Exception exception, string message, params object[] formatArgs);
+ }
+}
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
index 2f308cbb11..6fd0a7109d 100644
--- a/src/csharp/Grpc.Core/Metadata.cs
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -32,7 +32,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Collections.Immutable;
using System.Collections.Specialized;
using System.Runtime.InteropServices;
using System.Text;
diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs
index 77d36191c3..cc047ac9f8 100644
--- a/src/csharp/Grpc.Core/Method.cs
+++ b/src/csharp/Grpc.Core/Method.cs
@@ -53,16 +53,20 @@ namespace Grpc.Core
public class Method<TRequest, TResponse>
{
readonly MethodType type;
+ readonly string serviceName;
readonly string name;
readonly Marshaller<TRequest> requestMarshaller;
readonly Marshaller<TResponse> responseMarshaller;
+ readonly string fullName;
- public Method(MethodType type, string name, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller)
+ public Method(MethodType type, string serviceName, string name, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller)
{
this.type = type;
- this.name = name;
- this.requestMarshaller = requestMarshaller;
- this.responseMarshaller = responseMarshaller;
+ this.serviceName = Preconditions.CheckNotNull(serviceName);
+ this.name = Preconditions.CheckNotNull(name);
+ this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller);
+ this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller);
+ this.fullName = GetFullName(serviceName);
}
public MethodType Type
@@ -72,6 +76,14 @@ namespace Grpc.Core
return this.type;
}
}
+
+ public string ServiceName
+ {
+ get
+ {
+ return this.serviceName;
+ }
+ }
public string Name
{
@@ -97,6 +109,14 @@ namespace Grpc.Core
}
}
+ public string FullName
+ {
+ get
+ {
+ return this.fullName;
+ }
+ }
+
/// <summary>
/// Gets full name of the method including the service name.
/// </summary>
diff --git a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
index 2b3d7530f2..29db85d7aa 100644
--- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
@@ -10,4 +10,12 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
+#if SIGNED
+[assembly: InternalsVisibleTo("Grpc.Core.Tests,PublicKey=" +
+ "00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" +
+ "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" +
+ "27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" +
+ "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")]
+#else
[assembly: InternalsVisibleTo("Grpc.Core.Tests")]
+#endif \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index fd30735359..eb5b043d1c 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -32,12 +32,13 @@
#endregion
using System;
-using System.Collections.Concurrent;
+using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Grpc.Core.Internal;
+using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core
@@ -47,16 +48,17 @@ namespace Grpc.Core
/// </summary>
public class Server
{
- /// <summary>
- /// Pass this value as port to have the server choose an unused listening port for you.
- /// </summary>
- public const int PickUnusedPort = 0;
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<Server>();
+ readonly ServiceDefinitionCollection serviceDefinitions;
+ readonly ServerPortCollection ports;
readonly GrpcEnvironment environment;
readonly List<ChannelOption> options;
readonly ServerSafeHandle handle;
readonly object myLock = new object();
+ readonly List<ServerServiceDefinition> serviceDefinitionsList = new List<ServerServiceDefinition>();
+ readonly List<ServerPort> serverPortList = new List<ServerPort>();
readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>();
readonly TaskCompletionSource<object> shutdownTcs = new TaskCompletionSource<object>();
@@ -69,6 +71,8 @@ namespace Grpc.Core
/// <param name="options">Channel options.</param>
public Server(IEnumerable<ChannelOption> options = null)
{
+ this.serviceDefinitions = new ServiceDefinitionCollection(this);
+ this.ports = new ServerPortCollection(this);
this.environment = GrpcEnvironment.GetInstance();
this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
using (var channelArgs = ChannelOptions.CreateChannelArgs(this.options))
@@ -78,45 +82,27 @@ namespace Grpc.Core
}
/// <summary>
- /// Adds a service definition to the server. This is how you register
- /// handlers for a service with the server.
- /// Only call this before Start().
+ /// Services that will be exported by the server once started. Register a service with this
+ /// server by adding its definition to this collection.
/// </summary>
- public void AddServiceDefinition(ServerServiceDefinition serviceDefinition)
+ public ServiceDefinitionCollection Services
{
- lock (myLock)
+ get
{
- Preconditions.CheckState(!startRequested);
- foreach (var entry in serviceDefinition.CallHandlers)
- {
- callHandlers.Add(entry.Key, entry.Value);
- }
+ return serviceDefinitions;
}
}
/// <summary>
- /// Add a non-secure port on which server should listen.
- /// Only call this before Start().
+ /// Ports on which the server will listen once started. Register a port with this
+ /// server by adding its definition to this collection.
/// </summary>
- /// <returns>The port on which server will be listening.</returns>
- /// <param name="host">the host</param>
- /// <param name="port">the port. If zero, an unused port is chosen automatically.</param>
- public int AddListeningPort(string host, int port)
+ public ServerPortCollection Ports
{
- return AddListeningPortInternal(host, port, null);
- }
-
- /// <summary>
- /// Add a non-secure port on which server should listen.
- /// Only call this before Start().
- /// </summary>
- /// <returns>The port on which server will be listening.</returns>
- /// <param name="host">the host</param>
- /// <param name="port">the port. If zero, an unused port is chosen automatically.</param>
- public int AddListeningPort(string host, int port, ServerCredentials credentials)
- {
- Preconditions.CheckNotNull(credentials);
- return AddListeningPortInternal(host, port, credentials);
+ get
+ {
+ return ports;
+ }
}
/// <summary>
@@ -183,23 +169,47 @@ namespace Grpc.Core
handle.Dispose();
}
- private int AddListeningPortInternal(string host, int port, ServerCredentials credentials)
+ /// <summary>
+ /// Adds a service definition.
+ /// </summary>
+ private void AddServiceDefinitionInternal(ServerServiceDefinition serviceDefinition)
{
lock (myLock)
{
- Preconditions.CheckState(!startRequested);
- var address = string.Format("{0}:{1}", host, port);
- if (credentials != null)
+ Preconditions.CheckState(!startRequested);
+ foreach (var entry in serviceDefinition.CallHandlers)
{
- using (var nativeCredentials = credentials.ToNativeCredentials())
- {
- return handle.AddListeningPort(address, nativeCredentials);
- }
+ callHandlers.Add(entry.Key, entry.Value);
}
- else
+ serviceDefinitionsList.Add(serviceDefinition);
+ }
+ }
+
+ /// <summary>
+ /// Adds a listening port.
+ /// </summary>
+ private int AddPortInternal(ServerPort serverPort)
+ {
+ lock (myLock)
+ {
+ Preconditions.CheckNotNull(serverPort.Credentials);
+ Preconditions.CheckState(!startRequested);
+ var address = string.Format("{0}:{1}", serverPort.Host, serverPort.Port);
+ int boundPort;
+ using (var nativeCredentials = serverPort.Credentials.ToNativeCredentials())
{
- return handle.AddListeningPort(address);
+ if (nativeCredentials != null)
+ {
+ boundPort = handle.AddSecurePort(address, nativeCredentials);
+ }
+ else
+ {
+ boundPort = handle.AddInsecurePort(address);
+ }
}
+ var newServerPort = new ServerPort(serverPort, boundPort);
+ this.serverPortList.Add(newServerPort);
+ return boundPort;
}
}
@@ -233,7 +243,7 @@ namespace Grpc.Core
}
catch (Exception e)
{
- Console.WriteLine("Exception while handling RPC: " + e);
+ Logger.Warning(e, "Exception while handling RPC.");
}
}
@@ -263,5 +273,82 @@ namespace Grpc.Core
{
shutdownTcs.SetResult(null);
}
+
+ /// <summary>
+ /// Collection of service definitions.
+ /// </summary>
+ public class ServiceDefinitionCollection : IEnumerable<ServerServiceDefinition>
+ {
+ readonly Server server;
+
+ internal ServiceDefinitionCollection(Server server)
+ {
+ this.server = server;
+ }
+
+ /// <summary>
+ /// Adds a service definition to the server. This is how you register
+ /// handlers for a service with the server. Only call this before Start().
+ /// </summary>
+ public void Add(ServerServiceDefinition serviceDefinition)
+ {
+ server.AddServiceDefinitionInternal(serviceDefinition);
+ }
+
+ public IEnumerator<ServerServiceDefinition> GetEnumerator()
+ {
+ return server.serviceDefinitionsList.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return server.serviceDefinitionsList.GetEnumerator();
+ }
+ }
+
+ /// <summary>
+ /// Collection of server ports.
+ /// </summary>
+ public class ServerPortCollection : IEnumerable<ServerPort>
+ {
+ readonly Server server;
+
+ internal ServerPortCollection(Server server)
+ {
+ this.server = server;
+ }
+
+ /// <summary>
+ /// Adds a new port on which server should listen.
+ /// Only call this before Start().
+ /// <returns>The port on which server will be listening.</returns>
+ /// </summary>
+ public int Add(ServerPort serverPort)
+ {
+ return server.AddPortInternal(serverPort);
+ }
+
+ /// <summary>
+ /// Adds a new port on which server should listen.
+ /// <returns>The port on which server will be listening.</returns>
+ /// </summary>
+ /// <param name="host">the host</param>
+ /// <param name="port">the port. If zero, an unused port is chosen automatically.</param>
+ /// <param name="credentials">credentials to use to secure this port.</param>
+ public int Add(string host, int port, ServerCredentials credentials)
+ {
+ return Add(new ServerPort(host, port, credentials));
+ }
+
+ public IEnumerator<ServerPort> GetEnumerator()
+ {
+ return server.serverPortList.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return server.serverPortList.GetEnumerator();
+ }
+ }
}
}
diff --git a/src/csharp/Grpc.Core/ServerCallContext.cs b/src/csharp/Grpc.Core/ServerCallContext.cs
index 17a2eefd07..032b1390db 100644
--- a/src/csharp/Grpc.Core/ServerCallContext.cs
+++ b/src/csharp/Grpc.Core/ServerCallContext.cs
@@ -47,6 +47,7 @@ namespace Grpc.Core
private readonly string method;
private readonly string host;
+ private readonly string peer;
private readonly DateTime deadline;
private readonly Metadata requestHeaders;
private readonly CancellationToken cancellationToken;
@@ -54,16 +55,17 @@ namespace Grpc.Core
private Status status = Status.DefaultSuccess;
- public ServerCallContext(string method, string host, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken)
+ public ServerCallContext(string method, string host, string peer, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken)
{
this.method = method;
this.host = host;
+ this.peer = peer;
this.deadline = deadline;
this.requestHeaders = requestHeaders;
this.cancellationToken = cancellationToken;
}
- /// <summary> Name of method called in this RPC. </summary>
+ /// <summary>Name of method called in this RPC.</summary>
public string Method
{
get
@@ -72,7 +74,7 @@ namespace Grpc.Core
}
}
- /// <summary> Name of host called in this RPC. </summary>
+ /// <summary>Name of host called in this RPC.</summary>
public string Host
{
get
@@ -81,7 +83,16 @@ namespace Grpc.Core
}
}
- /// <summary> Deadline for this RPC. </summary>
+ /// <summary>Address of the remote endpoint in URI format.</summary>
+ public string Peer
+ {
+ get
+ {
+ return this.peer;
+ }
+ }
+
+ /// <summary>Deadline for this RPC.</summary>
public DateTime Deadline
{
get
@@ -90,7 +101,7 @@ namespace Grpc.Core
}
}
- /// <summary> Initial metadata sent by client. </summary>
+ /// <summary>Initial metadata sent by client.</summary>
public Metadata RequestHeaders
{
get
@@ -99,8 +110,7 @@ namespace Grpc.Core
}
}
- // TODO(jtattermusch): support signalling cancellation.
- /// <summary> Cancellation token signals when call is cancelled. </summary>
+ ///<summary>Cancellation token signals when call is cancelled.</summary>
public CancellationToken CancellationToken
{
get
@@ -109,7 +119,7 @@ namespace Grpc.Core
}
}
- /// <summary> Trailers to send back to client after RPC finishes.</summary>
+ /// <summary>Trailers to send back to client after RPC finishes.</summary>
public Metadata ResponseTrailers
{
get
diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs
index ab7d0b4914..c11a1ede08 100644
--- a/src/csharp/Grpc.Core/ServerCredentials.cs
+++ b/src/csharp/Grpc.Core/ServerCredentials.cs
@@ -33,8 +33,8 @@
using System;
using System.Collections.Generic;
-using System.Collections.Immutable;
using Grpc.Core.Internal;
+using Grpc.Core.Utils;
namespace Grpc.Core
{
@@ -43,67 +43,118 @@ namespace Grpc.Core
/// </summary>
public abstract class ServerCredentials
{
+ static readonly ServerCredentials InsecureInstance = new InsecureServerCredentialsImpl();
+
+ /// <summary>
+ /// Returns instance of credential that provides no security and
+ /// will result in creating an unsecure server port with no encryption whatsoever.
+ /// </summary>
+ public static ServerCredentials Insecure
+ {
+ get
+ {
+ return InsecureInstance;
+ }
+ }
+
/// <summary>
/// Creates native object for the credentials.
/// </summary>
/// <returns>The native credentials.</returns>
internal abstract ServerCredentialsSafeHandle ToNativeCredentials();
+
+ private sealed class InsecureServerCredentialsImpl : ServerCredentials
+ {
+ internal override ServerCredentialsSafeHandle ToNativeCredentials()
+ {
+ return null;
+ }
+ }
}
/// <summary>
- /// Key certificate pair (in PEM encoding).
+ /// Server-side SSL credentials.
/// </summary>
- public class KeyCertificatePair
+ public class SslServerCredentials : ServerCredentials
{
- readonly string certChain;
- readonly string privateKey;
+ readonly IList<KeyCertificatePair> keyCertificatePairs;
+ readonly string rootCertificates;
+ readonly bool forceClientAuth;
- public KeyCertificatePair(string certChain, string privateKey)
+ /// <summary>
+ /// Creates server-side SSL credentials.
+ /// </summary>
+ /// <param name="keyCertificatePairs">Key-certificates to use.</param>
+ /// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param>
+ /// <param name="forceClientAuth">If true, client will be rejected unless it proves its unthenticity using against rootCertificates.</param>
+ public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates, bool forceClientAuth)
{
- this.certChain = certChain;
- this.privateKey = privateKey;
+ this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly();
+ Preconditions.CheckArgument(this.keyCertificatePairs.Count > 0,
+ "At least one KeyCertificatePair needs to be provided");
+ if (forceClientAuth)
+ {
+ Preconditions.CheckNotNull(rootCertificates,
+ "Cannot force client authentication unless you provide rootCertificates.");
+ }
+ this.rootCertificates = rootCertificates;
+ this.forceClientAuth = forceClientAuth;
}
- public string CertChain
+ /// <summary>
+ /// Creates server-side SSL credentials.
+ /// This constructor should be use if you do not wish to autheticate client
+ /// using client root certificates.
+ /// </summary>
+ /// <param name="keyCertificatePairs">Key-certificates to use.</param>
+ public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs) : this(keyCertificatePairs, null, false)
+ {
+ }
+
+ /// <summary>
+ /// Key-certificate pairs.
+ /// </summary>
+ public IList<KeyCertificatePair> KeyCertificatePairs
{
get
{
- return certChain;
+ return this.keyCertificatePairs;
}
}
- public string PrivateKey
+ /// <summary>
+ /// PEM encoded client root certificates.
+ /// </summary>
+ public string RootCertificates
{
get
{
- return privateKey;
+ return this.rootCertificates;
}
}
- }
-
- /// <summary>
- /// Server-side SSL credentials.
- /// </summary>
- public class SslServerCredentials : ServerCredentials
- {
- ImmutableList<KeyCertificatePair> keyCertPairs;
- public SslServerCredentials(ImmutableList<KeyCertificatePair> keyCertPairs)
+ /// <summary>
+ /// If true, the authenticity of client check will be enforced.
+ /// </summary>
+ public bool ForceClientAuthentication
{
- this.keyCertPairs = keyCertPairs;
+ get
+ {
+ return this.forceClientAuth;
+ }
}
internal override ServerCredentialsSafeHandle ToNativeCredentials()
{
- int count = keyCertPairs.Count;
+ int count = keyCertificatePairs.Count;
string[] certChains = new string[count];
string[] keys = new string[count];
for (int i = 0; i < count; i++)
{
- certChains[i] = keyCertPairs[i].CertChain;
- keys[i] = keyCertPairs[i].PrivateKey;
+ certChains[i] = keyCertificatePairs[i].CertificateChain;
+ keys[i] = keyCertificatePairs[i].PrivateKey;
}
- return ServerCredentialsSafeHandle.CreateSslCredentials(certChains, keys);
+ return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys, forceClientAuth);
}
}
}
diff --git a/src/csharp/Grpc.Core/ServerPort.cs b/src/csharp/Grpc.Core/ServerPort.cs
new file mode 100644
index 0000000000..55e4bd0062
--- /dev/null
+++ b/src/csharp/Grpc.Core/ServerPort.cs
@@ -0,0 +1,120 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// A port exposed by a server.
+ /// </summary>
+ public class ServerPort
+ {
+ /// <summary>
+ /// Pass this value as port to have the server choose an unused listening port for you.
+ /// Ports added to a server will contain the bound port in their <see cref="BoundPort"/> property.
+ /// </summary>
+ public const int PickUnused = 0;
+
+ readonly string host;
+ readonly int port;
+ readonly ServerCredentials credentials;
+ readonly int boundPort;
+
+ /// <summary>
+ /// Creates a new port on which server should listen.
+ /// </summary>
+ /// <returns>The port on which server will be listening.</returns>
+ /// <param name="host">the host</param>
+ /// <param name="port">the port. If zero, an unused port is chosen automatically.</param>
+ /// <param name="credentials">credentials to use to secure this port.</param>
+ public ServerPort(string host, int port, ServerCredentials credentials)
+ {
+ this.host = Preconditions.CheckNotNull(host);
+ this.port = port;
+ this.credentials = Preconditions.CheckNotNull(credentials);
+ }
+
+ /// <summary>
+ /// Creates a port from an existing <c>ServerPort</c> instance and boundPort value.
+ /// </summary>
+ internal ServerPort(ServerPort serverPort, int boundPort)
+ {
+ this.host = serverPort.host;
+ this.port = serverPort.port;
+ this.credentials = serverPort.credentials;
+ this.boundPort = boundPort;
+ }
+
+ /// <value>The host.</value>
+ public string Host
+ {
+ get
+ {
+ return host;
+ }
+ }
+
+ /// <value>The port.</value>
+ public int Port
+ {
+ get
+ {
+ return port;
+ }
+ }
+
+ /// <value>The server credentials.</value>
+ public ServerCredentials Credentials
+ {
+ get
+ {
+ return credentials;
+ }
+ }
+
+ /// <value>
+ /// The port actually bound by the server. This is useful if you let server
+ /// pick port automatically. <see cref="PickUnused"/>
+ /// </value>
+ public int BoundPort
+ {
+ get
+ {
+ return boundPort;
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/ServerServiceDefinition.cs b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
index b180186c12..a00d156e52 100644
--- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs
+++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
@@ -33,7 +33,7 @@
using System;
using System.Collections.Generic;
-using System.Collections.Immutable;
+using System.Collections.ObjectModel;
using Grpc.Core.Internal;
namespace Grpc.Core
@@ -43,14 +43,14 @@ namespace Grpc.Core
/// </summary>
public class ServerServiceDefinition
{
- readonly ImmutableDictionary<string, IServerCallHandler> callHandlers;
+ readonly ReadOnlyDictionary<string, IServerCallHandler> callHandlers;
- private ServerServiceDefinition(ImmutableDictionary<string, IServerCallHandler> callHandlers)
+ private ServerServiceDefinition(Dictionary<string, IServerCallHandler> callHandlers)
{
- this.callHandlers = callHandlers;
+ this.callHandlers = new ReadOnlyDictionary<string, IServerCallHandler>(callHandlers);
}
- internal ImmutableDictionary<string, IServerCallHandler> CallHandlers
+ internal IDictionary<string, IServerCallHandler> CallHandlers
{
get
{
@@ -115,7 +115,7 @@ namespace Grpc.Core
public ServerServiceDefinition Build()
{
- return new ServerServiceDefinition(callHandlers.ToImmutableDictionary());
+ return new ServerServiceDefinition(callHandlers);
}
}
}
diff --git a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
index 4180d98938..82653c3a1f 100644
--- a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
+++ b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
@@ -46,13 +46,15 @@ namespace Grpc.Core.Utils
/// </summary>
public static void RunBenchmark(int warmupIterations, int benchmarkIterations, Action action)
{
- Console.WriteLine("Warmup iterations: " + warmupIterations);
+ var logger = GrpcEnvironment.Logger;
+
+ logger.Info("Warmup iterations: {0}", warmupIterations);
for (int i = 0; i < warmupIterations; i++)
{
action();
}
- Console.WriteLine("Benchmark iterations: " + benchmarkIterations);
+ logger.Info("Benchmark iterations: {0}", benchmarkIterations);
var stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < benchmarkIterations; i++)
@@ -60,8 +62,8 @@ namespace Grpc.Core.Utils
action();
}
stopwatch.Stop();
- Console.WriteLine("Elapsed time: " + stopwatch.ElapsedMilliseconds + "ms");
- Console.WriteLine("Ops per second: " + (int)((double)benchmarkIterations * 1000 / stopwatch.ElapsedMilliseconds));
+ logger.Info("Elapsed time: {0}ms", stopwatch.ElapsedMilliseconds);
+ logger.Info("Ops per second: {0}", (int)((double)benchmarkIterations * 1000 / stopwatch.ElapsedMilliseconds));
}
}
}
diff --git a/src/csharp/Grpc.Core/packages.config b/src/csharp/Grpc.Core/packages.config
index 6cdcdf2656..9b12b9b096 100644
--- a/src/csharp/Grpc.Core/packages.config
+++ b/src/csharp/Grpc.Core/packages.config
@@ -3,5 +3,4 @@
<package id="grpc.dependencies.openssl.redist" version="1.0.2.2" targetFramework="net45" />
<package id="grpc.dependencies.zlib.redist" version="1.2.8.9" targetFramework="net45" />
<package id="Ix-Async" version="1.2.3" targetFramework="net45" />
- <package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
index 5d5401593d..b603e3af3c 100644
--- a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
@@ -2,7 +2,7 @@
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}</ProjectGuid>
@@ -11,7 +11,7 @@
<AssemblyName>MathClient</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@@ -19,17 +19,22 @@
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <Externalconsole>true</Externalconsole>
- <PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
- <DebugType>full</DebugType>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <Externalconsole>true</Externalconsole>
- <PlatformTarget>x86</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
index cfe2a06916..f9839d99f1 100644
--- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs
+++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
@@ -39,7 +39,7 @@ namespace math
{
public static void Main(string[] args)
{
- using (Channel channel = new Channel("127.0.0.1", 23456))
+ using (Channel channel = new Channel("127.0.0.1", 23456, Credentials.Insecure))
{
Math.IMathClient client = new Math.MathClient(channel);
MathExamples.DivExample(client);
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
index 677d87da20..5f74b58773 100644
--- a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
@@ -2,7 +2,7 @@
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{BF62FE08-373A-43D6-9D73-41CAA38B7011}</ProjectGuid>
@@ -11,7 +11,7 @@
<AssemblyName>MathServer</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@@ -19,17 +19,22 @@
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <Externalconsole>true</Externalconsole>
- <PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
- <DebugType>full</DebugType>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <Externalconsole>true</Externalconsole>
- <PlatformTarget>x86</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
index f440985112..5f7e717b0c 100644
--- a/src/csharp/Grpc.Examples.MathServer/MathServer.cs
+++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
@@ -38,16 +38,19 @@ namespace math
{
class MainClass
{
+ const string Host = "0.0.0.0";
+ const int Port = 23456;
+
public static void Main(string[] args)
{
- string host = "0.0.0.0";
-
- Server server = new Server();
- server.AddServiceDefinition(Math.BindService(new MathServiceImpl()));
- int port = server.AddListeningPort(host, 23456);
+ Server server = new Server
+ {
+ Services = { Math.BindService(new MathServiceImpl()) },
+ Ports = { { Host, Port, ServerCredentials.Insecure } }
+ };
server.Start();
- Console.WriteLine("MathServer listening on port " + port);
+ Console.WriteLine("MathServer listening on port " + Port);
Console.WriteLine("Press any key to stop the server...");
Console.ReadKey();
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index d59d7515d1..9a8f780b24 100644
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -19,15 +19,22 @@
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>full</DebugType>
+ <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="nunit.framework">
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index 7a957c5b6f..08aece7ef2 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -33,6 +33,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
@@ -46,7 +47,7 @@ namespace math.Tests
/// </summary>
public class MathClientServerTest
{
- string host = "localhost";
+ const string Host = "localhost";
Server server;
Channel channel;
Math.MathClient client;
@@ -54,19 +55,14 @@ namespace math.Tests
[TestFixtureSetUp]
public void Init()
{
- server = new Server();
- server.AddServiceDefinition(Math.BindService(new MathServiceImpl()));
- int port = server.AddListeningPort(host, Server.PickUnusedPort);
- server.Start();
- channel = new Channel(host, port);
- client = Math.NewClient(channel);
-
- // TODO(jtattermusch): get rid of the custom header here once we have dedicated tests
- // for header support.
- client.HeaderInterceptor = (metadata) =>
+ server = new Server
{
- metadata.Add(new Metadata.Entry("customHeader", "abcdef"));
+ Services = { Math.BindService(new MathServiceImpl()) },
+ Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
+ server.Start();
+ channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
+ client = Math.NewClient(channel);
}
[TestFixtureTearDown]
@@ -108,69 +104,105 @@ namespace math.Tests
}
[Test]
- public void DivAsync()
+ public async Task DivAsync()
+ {
+ DivReply response = await client.DivAsync(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
+ Assert.AreEqual(3, response.Quotient);
+ Assert.AreEqual(1, response.Remainder);
+ }
+
+ [Test]
+ public async Task Fib()
{
- Task.Run(async () =>
+ using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build()))
{
- DivReply response = await client.DivAsync(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
- Assert.AreEqual(3, response.Quotient);
- Assert.AreEqual(1, response.Remainder);
- }).Wait();
+ var responses = await call.ResponseStream.ToList();
+ CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 },
+ responses.ConvertAll((n) => n.Num_));
+ }
}
[Test]
- public void Fib()
+ public async Task FibWithCancel()
{
- Task.Run(async () =>
+ var cts = new CancellationTokenSource();
+
+ using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(),
+ cancellationToken: cts.Token))
{
- using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build()))
+ List<long> responses = new List<long>();
+
+ try
{
- var responses = await call.ResponseStream.ToList();
- CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 },
- responses.ConvertAll((n) => n.Num_));
+ while (await call.ResponseStream.MoveNext())
+ {
+ if (responses.Count == 0)
+ {
+ cts.CancelAfter(500); // make sure we cancel soon
+ }
+ responses.Add(call.ResponseStream.Current.Num_);
+ }
+ Assert.Fail();
}
- }).Wait();
+ catch (RpcException e)
+ {
+ Assert.IsTrue(responses.Count > 0);
+ Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
+ }
+ }
}
- // TODO: test Fib with limit=0 and cancellation
[Test]
- public void Sum()
+ public async Task FibWithDeadline()
{
- Task.Run(async () =>
+ using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(),
+ deadline: DateTime.UtcNow.AddMilliseconds(500)))
{
- using (var call = client.Sum())
+ try
{
- var numbers = new List<long> { 10, 20, 30 }.ConvertAll(
- n => Num.CreateBuilder().SetNum_(n).Build());
-
- await call.RequestStream.WriteAll(numbers);
- var result = await call.ResponseAsync;
- Assert.AreEqual(60, result.Num_);
+ await call.ResponseStream.ToList();
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode);
}
- }).Wait();
+ }
}
+ // TODO: test Fib with limit=0 and cancellation
[Test]
- public void DivMany()
+ public async Task Sum()
{
- Task.Run(async () =>
+ using (var call = client.Sum())
{
- var divArgsList = new List<DivArgs>
- {
- new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
- new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
- new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build()
- };
+ var numbers = new List<long> { 10, 20, 30 }.ConvertAll(
+ n => Num.CreateBuilder().SetNum_(n).Build());
- using (var call = client.DivMany())
- {
- await call.RequestStream.WriteAll(divArgsList);
- var result = await call.ResponseStream.ToList();
+ await call.RequestStream.WriteAll(numbers);
+ var result = await call.ResponseAsync;
+ Assert.AreEqual(60, result.Num_);
+ }
+ }
- CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient));
- CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder));
- }
- }).Wait();
+ [Test]
+ public async Task DivMany()
+ {
+ var divArgsList = new List<DivArgs>
+ {
+ new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
+ new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
+ new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build()
+ };
+
+ using (var call = client.DivMany())
+ {
+ await call.RequestStream.WriteAll(divArgsList);
+ var result = await call.ResponseStream.ToList();
+
+ 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/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
index eaf24a253c..c1aa40500e 100644
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -19,15 +19,22 @@
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>full</DebugType>
+ <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index ef787cf1d8..4941ff35f7 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -19,24 +19,28 @@ namespace math {
static readonly Method<global::math.DivArgs, global::math.DivReply> __Method_Div = new Method<global::math.DivArgs, global::math.DivReply>(
MethodType.Unary,
+ __ServiceName,
"Div",
__Marshaller_DivArgs,
__Marshaller_DivReply);
static readonly Method<global::math.DivArgs, global::math.DivReply> __Method_DivMany = new Method<global::math.DivArgs, global::math.DivReply>(
MethodType.DuplexStreaming,
+ __ServiceName,
"DivMany",
__Marshaller_DivArgs,
__Marshaller_DivReply);
static readonly Method<global::math.FibArgs, global::math.Num> __Method_Fib = new Method<global::math.FibArgs, global::math.Num>(
MethodType.ServerStreaming,
+ __ServiceName,
"Fib",
__Marshaller_FibArgs,
__Marshaller_Num);
static readonly Method<global::math.Num, global::math.Num> __Method_Sum = new Method<global::math.Num, global::math.Num>(
MethodType.ClientStreaming,
+ __ServiceName,
"Sum",
__Marshaller_Num,
__Marshaller_Num);
@@ -44,11 +48,16 @@ namespace math {
// client interface
public interface IMathClient
{
- global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::math.DivReply Div(global::math.DivArgs request, CallOptions options);
+ AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, CallOptions options);
+ AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(CallOptions options);
+ AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, CallOptions options);
+ AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(CallOptions options);
}
// server-side interface
@@ -66,30 +75,55 @@ namespace math {
public MathClient(Channel channel) : base(channel)
{
}
- public global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__ServiceName, __Method_Div, headers);
- return Calls.BlockingUnaryCall(call, request, cancellationToken);
+ var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.BlockingUnaryCall(call, request);
}
- public AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public global::math.DivReply Div(global::math.DivArgs request, CallOptions options)
{
- var call = CreateCall(__ServiceName, __Method_Div, headers);
- return Calls.AsyncUnaryCall(call, request, cancellationToken);
+ var call = CreateCall(__Method_Div, options);
+ return Calls.BlockingUnaryCall(call, request);
}
- public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__ServiceName, __Method_DivMany, headers);
- return Calls.AsyncDuplexStreamingCall(call, cancellationToken);
+ var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncUnaryCall(call, request);
}
- public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, CallOptions options)
{
- var call = CreateCall(__ServiceName, __Method_Fib, headers);
- return Calls.AsyncServerStreamingCall(call, request, cancellationToken);
+ var call = CreateCall(__Method_Div, options);
+ return Calls.AsyncUnaryCall(call, request);
}
- public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__ServiceName, __Method_Sum, headers);
- return Calls.AsyncClientStreamingCall(call, cancellationToken);
+ var call = CreateCall(__Method_DivMany, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncDuplexStreamingCall(call);
+ }
+ public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(CallOptions options)
+ {
+ var call = CreateCall(__Method_DivMany, options);
+ return Calls.AsyncDuplexStreamingCall(call);
+ }
+ public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_Fib, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncServerStreamingCall(call, request);
+ }
+ public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, CallOptions options)
+ {
+ var call = CreateCall(__Method_Fib, options);
+ return Calls.AsyncServerStreamingCall(call, request);
+ }
+ public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_Sum, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncClientStreamingCall(call);
+ }
+ public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(CallOptions options)
+ {
+ var call = CreateCall(__Method_Sum, options);
+ return Calls.AsyncClientStreamingCall(call);
}
}
diff --git a/src/csharp/Grpc.Examples/MathServiceImpl.cs b/src/csharp/Grpc.Examples/MathServiceImpl.cs
index 3dd0f53a0d..dd26b1d350 100644
--- a/src/csharp/Grpc.Examples/MathServiceImpl.cs
+++ b/src/csharp/Grpc.Examples/MathServiceImpl.cs
@@ -54,8 +54,13 @@ namespace math
{
if (request.Limit <= 0)
{
- // TODO(jtattermusch): support cancellation
- throw new NotImplementedException("Not implemented yet");
+ // keep streaming the sequence until cancelled.
+ IEnumerator<Num> fibEnumerator = FibInternal(long.MaxValue).GetEnumerator();
+ while (!context.CancellationToken.IsCancellationRequested && fibEnumerator.MoveNext())
+ {
+ await responseStream.WriteAsync(fibEnumerator.Current);
+ await Task.Delay(100);
+ }
}
if (request.Limit > 0)
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
index 72e110302b..c922ddfb9e 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
@@ -17,7 +17,6 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
@@ -25,10 +24,18 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
<ItemGroup>
<Reference Include="Google.ProtocolBuffers">
<HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath>
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
index bc14a0a62f..024377e216 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
@@ -57,11 +57,13 @@ namespace Grpc.HealthCheck.Tests
{
serviceImpl = new HealthServiceImpl();
- server = new Server();
- server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl));
- int port = server.AddListeningPort(Host, Server.PickUnusedPort);
+ server = new Server
+ {
+ Services = { Grpc.Health.V1Alpha.Health.BindService(serviceImpl) },
+ Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
+ };
server.Start();
- channel = new Channel(Host, port);
+ channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
client = Grpc.Health.V1Alpha.Health.NewClient(channel);
}
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
index 4ebb6446dd..0b7a7b91c6 100644
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -18,7 +18,6 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
@@ -26,10 +25,18 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
<ItemGroup>
<Reference Include="Google.ProtocolBuffers">
<HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath>
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
index ca35b36805..acdfba42c8 100644
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
@@ -20,9 +20,9 @@
</dependencies>
</metadata>
<files>
- <file src="bin/Release/Grpc.HealthCheck.dll" target="lib/net45" />
- <file src="bin/Release/Grpc.HealthCheck.pdb" target="lib/net45" />
- <file src="bin/Release/Grpc.HealthCheck.xml" target="lib/net45" />
+ <file src="bin/ReleaseSigned/Grpc.HealthCheck.dll" target="lib/net45" />
+ <file src="bin/ReleaseSigned/Grpc.HealthCheck.pdb" target="lib/net45" />
+ <file src="bin/ReleaseSigned/Grpc.HealthCheck.xml" target="lib/net45" />
<file src="**\*.cs" target="src" />
</files>
</package>
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
index 217127eca7..0dabc91f7c 100644
--- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -17,6 +17,7 @@ namespace Grpc.Health.V1Alpha {
static readonly Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse> __Method_Check = new Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse>(
MethodType.Unary,
+ __ServiceName,
"Check",
__Marshaller_HealthCheckRequest,
__Marshaller_HealthCheckResponse);
@@ -24,8 +25,10 @@ namespace Grpc.Health.V1Alpha {
// client interface
public interface IHealthClient
{
- global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options);
+ AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options);
}
// server-side interface
@@ -40,15 +43,25 @@ namespace Grpc.Health.V1Alpha {
public HealthClient(Channel channel) : base(channel)
{
}
- public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__ServiceName, __Method_Check, headers);
- return Calls.BlockingUnaryCall(call, request, cancellationToken);
+ var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.BlockingUnaryCall(call, request);
}
- public AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options)
{
- var call = CreateCall(__ServiceName, __Method_Check, headers);
- return Calls.AsyncUnaryCall(call, request, cancellationToken);
+ var call = CreateCall(__Method_Check, options);
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options)
+ {
+ var call = CreateCall(__Method_Check, options);
+ return Calls.AsyncUnaryCall(call, request);
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index dc1d0a44c0..2c38c9645c 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -2,7 +2,7 @@
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{3D166931-BA2D-416E-95A3-D36E8F6E90B9}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Grpc.IntegrationTesting.Client</RootNamespace>
@@ -10,7 +10,7 @@
<StartupObject>Grpc.IntegrationTesting.Client.Program</StartupObject>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@@ -18,17 +18,24 @@
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <Externalconsole>true</Externalconsole>
- <PlatformTarget>x86</PlatformTarget>
+ <PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
- <DebugType>full</DebugType>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <Externalconsole>true</Externalconsole>
- <PlatformTarget>x86</PlatformTarget>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/app.config b/src/csharp/Grpc.IntegrationTesting.Client/app.config
index 966b777192..0a82bb4f16 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/app.config
+++ b/src/csharp/Grpc.IntegrationTesting.Client/app.config
@@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index f03c8f3ce3..949ad61375 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -2,7 +2,7 @@
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A654F3B8-E859-4E6A-B30D-227527DBEF0D}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Grpc.IntegrationTesting.Server</RootNamespace>
@@ -10,7 +10,7 @@
<StartupObject>Grpc.IntegrationTesting.Server.Program</StartupObject>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@@ -18,17 +18,24 @@
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <Externalconsole>true</Externalconsole>
- <PlatformTarget>x86</PlatformTarget>
+ <PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
- <DebugType>full</DebugType>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <Externalconsole>true</Externalconsole>
- <PlatformTarget>x86</PlatformTarget>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/app.config b/src/csharp/Grpc.IntegrationTesting.Server/app.config
index 966b777192..0a82bb4f16 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/app.config
+++ b/src/csharp/Grpc.IntegrationTesting.Server/app.config
@@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index d3c69ab9eb..06a75a3351 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -2,16 +2,15 @@
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
- <ProductVersion>8.0.30703</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C61154BA-DD4A-4838-8420-0162A28925E0}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Grpc.IntegrationTesting</RootNamespace>
<AssemblyName>Grpc.IntegrationTesting</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <NuGetPackageImportStamp>041c163e</NuGetPackageImportStamp>
</PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@@ -19,46 +18,44 @@
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <Externalconsole>true</Externalconsole>
- <PlatformTarget>x86</PlatformTarget>
+ <PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
- <DebugType>full</DebugType>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <Externalconsole>true</Externalconsole>
- <PlatformTarget>x86</PlatformTarget>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
- <Reference Include="Google.Apis.Auth, Version=1.9.1.12395, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll</HintPath>
+ <Reference Include="BouncyCastle.Crypto">
+ <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.1.12399, Culture=neutral, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Auth, Version=1.9.2.27817, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll</HintPath>
</Reference>
- <Reference Include="Google.Apis.Core, Version=1.9.1.12394, Culture=neutral, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.2.27820, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <Reference Include="Google.Apis.Core, Version=1.9.2.27816, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+ <HintPath>..\packages\Google.Apis.Core.1.9.2\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, 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, 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=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
+ <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
@@ -67,24 +64,29 @@
<Reference Include="Google.ProtocolBuffers">
<HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
</Reference>
- <Reference Include="System.Collections.Immutable, Version=1.1.36.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
- </Reference>
<Reference Include="System.Interactive.Async">
<HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
- <Reference Include="System.Net.Http.Extensions, Version=2.2.28.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll</HintPath>
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
</Reference>
- <Reference Include="System.Net.Http.Primitives, Version=4.2.28.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll</HintPath>
+ <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">
@@ -99,6 +101,7 @@
<Compile Include="InteropClient.cs" />
<Compile Include="TestCredentials.cs" />
<Compile Include="TestGrpc.cs" />
+ <Compile Include="SslCredentialsTest.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@@ -133,9 +136,11 @@
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
- <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
- <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
- <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
- <Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
+ <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
</Target>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index ce255f9423..7411d91d5a 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -127,15 +127,15 @@ namespace Grpc.IntegrationTesting
{
credential = credential.CreateScoped(new[] { AuthScope });
}
- client.HeaderInterceptor = OAuth2InterceptorFactory.Create(credential);
+ client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
}
- RunTestCase(options.testCase, client);
+ RunTestCaseAsync(options.testCase, client).Wait();
}
GrpcEnvironment.Shutdown();
}
- private void RunTestCase(string testCase, TestService.TestServiceClient client)
+ private async Task RunTestCaseAsync(string testCase, TestService.TestServiceClient client)
{
switch (testCase)
{
@@ -146,16 +146,16 @@ namespace Grpc.IntegrationTesting
RunLargeUnary(client);
break;
case "client_streaming":
- RunClientStreaming(client);
+ await RunClientStreamingAsync(client);
break;
case "server_streaming":
- RunServerStreaming(client);
+ await RunServerStreamingAsync(client);
break;
case "ping_pong":
- RunPingPong(client);
+ await RunPingPongAsync(client);
break;
case "empty_stream":
- RunEmptyStream(client);
+ await RunEmptyStreamAsync(client);
break;
case "service_account_creds":
RunServiceAccountCreds(client);
@@ -170,10 +170,10 @@ namespace Grpc.IntegrationTesting
RunPerRpcCreds(client);
break;
case "cancel_after_begin":
- RunCancelAfterBegin(client);
+ await RunCancelAfterBeginAsync(client);
break;
case "cancel_after_first_response":
- RunCancelAfterFirstResponse(client);
+ await RunCancelAfterFirstResponseAsync(client);
break;
case "benchmark_empty_unary":
RunBenchmarkEmptyUnary(client);
@@ -207,118 +207,106 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static void RunClientStreaming(TestService.ITestServiceClient client)
+ public static async Task RunClientStreamingAsync(TestService.ITestServiceClient client)
{
- Task.Run(async () =>
- {
- Console.WriteLine("running client_streaming");
+ Console.WriteLine("running client_streaming");
- var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.ConvertAll((size) => StreamingInputCallRequest.CreateBuilder().SetPayload(CreateZerosPayload(size)).Build());
+ var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.ConvertAll((size) => StreamingInputCallRequest.CreateBuilder().SetPayload(CreateZerosPayload(size)).Build());
- using (var call = client.StreamingInputCall())
- {
- await call.RequestStream.WriteAll(bodySizes);
+ using (var call = client.StreamingInputCall())
+ {
+ await call.RequestStream.WriteAll(bodySizes);
- var response = await call.ResponseAsync;
- Assert.AreEqual(74922, response.AggregatedPayloadSize);
- }
- Console.WriteLine("Passed!");
- }).Wait();
+ var response = await call.ResponseAsync;
+ Assert.AreEqual(74922, response.AggregatedPayloadSize);
+ }
+ Console.WriteLine("Passed!");
}
- public static void RunServerStreaming(TestService.ITestServiceClient client)
+ public static async Task RunServerStreamingAsync(TestService.ITestServiceClient client)
{
- Task.Run(async () =>
- {
- Console.WriteLine("running server_streaming");
+ Console.WriteLine("running server_streaming");
- var bodySizes = new List<int> { 31415, 9, 2653, 58979 };
+ var bodySizes = new List<int> { 31415, 9, 2653, 58979 };
- var request = StreamingOutputCallRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .AddRangeResponseParameters(bodySizes.ConvertAll(
- (size) => ResponseParameters.CreateBuilder().SetSize(size).Build()))
- .Build();
+ var request = StreamingOutputCallRequest.CreateBuilder()
+ .SetResponseType(PayloadType.COMPRESSABLE)
+ .AddRangeResponseParameters(bodySizes.ConvertAll(
+ (size) => ResponseParameters.CreateBuilder().SetSize(size).Build()))
+ .Build();
- using (var call = client.StreamingOutputCall(request))
+ using (var call = client.StreamingOutputCall(request))
+ {
+ var responseList = await call.ResponseStream.ToList();
+ foreach (var res in responseList)
{
- var responseList = await call.ResponseStream.ToList();
- foreach (var res in responseList)
- {
- Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type);
- }
- CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length));
+ Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type);
}
- Console.WriteLine("Passed!");
- }).Wait();
+ CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length));
+ }
+ Console.WriteLine("Passed!");
}
- public static void RunPingPong(TestService.ITestServiceClient client)
+ public static async Task RunPingPongAsync(TestService.ITestServiceClient client)
{
- Task.Run(async () =>
- {
- Console.WriteLine("running ping_pong");
+ Console.WriteLine("running ping_pong");
- using (var call = client.FullDuplexCall())
- {
- await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415))
- .SetPayload(CreateZerosPayload(27182)).Build());
+ using (var call = client.FullDuplexCall())
+ {
+ await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
+ .SetResponseType(PayloadType.COMPRESSABLE)
+ .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415))
+ .SetPayload(CreateZerosPayload(27182)).Build());
- Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
- Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
+ Assert.IsTrue(await call.ResponseStream.MoveNext());
+ Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+ Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
- await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(9))
- .SetPayload(CreateZerosPayload(8)).Build());
+ await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
+ .SetResponseType(PayloadType.COMPRESSABLE)
+ .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(9))
+ .SetPayload(CreateZerosPayload(8)).Build());
- Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
- Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length);
+ Assert.IsTrue(await call.ResponseStream.MoveNext());
+ Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+ Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length);
- await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(2653))
- .SetPayload(CreateZerosPayload(1828)).Build());
+ await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
+ .SetResponseType(PayloadType.COMPRESSABLE)
+ .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(2653))
+ .SetPayload(CreateZerosPayload(1828)).Build());
- Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
- Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length);
+ Assert.IsTrue(await call.ResponseStream.MoveNext());
+ Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+ Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length);
- await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(58979))
- .SetPayload(CreateZerosPayload(45904)).Build());
+ await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
+ .SetResponseType(PayloadType.COMPRESSABLE)
+ .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(58979))
+ .SetPayload(CreateZerosPayload(45904)).Build());
- Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
- Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length);
+ Assert.IsTrue(await call.ResponseStream.MoveNext());
+ Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+ Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length);
- await call.RequestStream.CompleteAsync();
+ await call.RequestStream.CompleteAsync();
- Assert.IsFalse(await call.ResponseStream.MoveNext());
- }
- Console.WriteLine("Passed!");
- }).Wait();
+ Assert.IsFalse(await call.ResponseStream.MoveNext());
+ }
+ Console.WriteLine("Passed!");
}
- public static void RunEmptyStream(TestService.ITestServiceClient client)
+ public static async Task RunEmptyStreamAsync(TestService.ITestServiceClient client)
{
- Task.Run(async () =>
+ Console.WriteLine("running empty_stream");
+ using (var call = client.FullDuplexCall())
{
- Console.WriteLine("running empty_stream");
- using (var call = client.FullDuplexCall())
- {
- await call.RequestStream.CompleteAsync();
+ await call.RequestStream.CompleteAsync();
- var responseList = await call.ResponseStream.ToList();
- Assert.AreEqual(0, responseList.Count);
- }
- Console.WriteLine("Passed!");
- }).Wait();
+ var responseList = await call.ResponseStream.ToList();
+ Assert.AreEqual(0, responseList.Count);
+ }
+ Console.WriteLine("Passed!");
}
public static void RunServiceAccountCreds(TestService.ITestServiceClient client)
@@ -368,11 +356,7 @@ namespace Grpc.IntegrationTesting
Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result);
string oauth2Token = credential.Token.AccessToken;
- // Intercept calls with an OAuth2 token obtained out-of-band.
- client.HeaderInterceptor = new MetadataInterceptorDelegate((metadata) =>
- {
- metadata.Add(new Metadata.Entry("Authorization", "Bearer " + oauth2Token));
- });
+ client.HeaderInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
var request = SimpleRequest.CreateBuilder()
.SetFillUsername(true)
@@ -393,78 +377,75 @@ namespace Grpc.IntegrationTesting
var credential = GoogleCredential.GetApplicationDefault().CreateScoped(new[] { AuthScope });
Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result);
string oauth2Token = credential.Token.AccessToken;
+ var headerInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
var request = SimpleRequest.CreateBuilder()
.SetFillUsername(true)
.SetFillOauthScope(true)
.Build();
- var response = client.UnaryCall(request, headers: new Metadata { new Metadata.Entry("Authorization", "Bearer " + oauth2Token) });
+ var headers = new Metadata();
+ headerInterceptor(headers);
+ var response = client.UnaryCall(request, headers: headers);
Assert.AreEqual(AuthScopeResponse, response.OauthScope);
Assert.AreEqual(ServiceAccountUser, response.Username);
Console.WriteLine("Passed!");
}
- public static void RunCancelAfterBegin(TestService.ITestServiceClient client)
+ public static async Task RunCancelAfterBeginAsync(TestService.ITestServiceClient client)
{
- Task.Run(async () =>
+ Console.WriteLine("running cancel_after_begin");
+
+ var cts = new CancellationTokenSource();
+ using (var call = client.StreamingInputCall(cancellationToken: cts.Token))
{
- Console.WriteLine("running cancel_after_begin");
+ // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
+ await Task.Delay(1000);
+ cts.Cancel();
- var cts = new CancellationTokenSource();
- using (var call = client.StreamingInputCall(cancellationToken: cts.Token))
+ try
{
- // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
- await Task.Delay(1000);
- cts.Cancel();
-
- try
- {
- var response = await call.ResponseAsync;
- Assert.Fail();
- }
- catch (RpcException e)
- {
- Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
- }
+ var response = await call.ResponseAsync;
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
}
- Console.WriteLine("Passed!");
- }).Wait();
+ }
+ Console.WriteLine("Passed!");
}
- public static void RunCancelAfterFirstResponse(TestService.ITestServiceClient client)
+ public static async Task RunCancelAfterFirstResponseAsync(TestService.ITestServiceClient client)
{
- Task.Run(async () =>
- {
- Console.WriteLine("running cancel_after_first_response");
+ Console.WriteLine("running cancel_after_first_response");
- var cts = new CancellationTokenSource();
- using (var call = client.FullDuplexCall(cancellationToken: cts.Token))
- {
- await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415))
- .SetPayload(CreateZerosPayload(27182)).Build());
+ var cts = new CancellationTokenSource();
+ using (var call = client.FullDuplexCall(cancellationToken: cts.Token))
+ {
+ await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
+ .SetResponseType(PayloadType.COMPRESSABLE)
+ .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415))
+ .SetPayload(CreateZerosPayload(27182)).Build());
- Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
- Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
+ Assert.IsTrue(await call.ResponseStream.MoveNext());
+ Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+ Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
- cts.Cancel();
+ cts.Cancel();
- try
- {
- await call.ResponseStream.MoveNext();
- Assert.Fail();
- }
- catch (RpcException e)
- {
- Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
- }
+ try
+ {
+ await call.ResponseStream.MoveNext();
+ Assert.Fail();
}
- Console.WriteLine("Passed!");
- }).Wait();
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
+ }
+ }
+ Console.WriteLine("Passed!");
}
// This is not an official interop test, but it's useful.
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
index f306289cfb..6fa721bc1c 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
@@ -33,6 +33,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using grpc.testing;
@@ -47,7 +48,7 @@ namespace Grpc.IntegrationTesting
/// </summary>
public class InteropClientServerTest
{
- string host = "localhost";
+ const string Host = "localhost";
Server server;
Channel channel;
TestService.ITestServiceClient client;
@@ -55,16 +56,19 @@ namespace Grpc.IntegrationTesting
[TestFixtureSetUp]
public void Init()
{
- server = new Server();
- server.AddServiceDefinition(TestService.BindService(new TestServiceImpl()));
- int port = server.AddListeningPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials());
+ server = new Server
+ {
+ Services = { TestService.BindService(new TestServiceImpl()) },
+ Ports = { { Host, ServerPort.PickUnused, TestCredentials.CreateTestServerCredentials() } }
+ };
server.Start();
var options = new List<ChannelOption>
{
new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
};
- channel = new Channel(host, port, TestCredentials.CreateTestClientCredentials(true), options);
+ int port = server.Ports.Single().BoundPort;
+ channel = new Channel(Host, port, TestCredentials.CreateTestClientCredentials(true), options);
client = TestService.NewClient(channel);
}
@@ -89,39 +93,39 @@ namespace Grpc.IntegrationTesting
}
[Test]
- public void ClientStreaming()
+ public async Task ClientStreaming()
{
- InteropClient.RunClientStreaming(client);
+ await InteropClient.RunClientStreamingAsync(client);
}
[Test]
- public void ServerStreaming()
+ public async Task ServerStreaming()
{
- InteropClient.RunServerStreaming(client);
+ await InteropClient.RunServerStreamingAsync(client);
}
[Test]
- public void PingPong()
+ public async Task PingPong()
{
- InteropClient.RunPingPong(client);
+ await InteropClient.RunPingPongAsync(client);
}
[Test]
- public void EmptyStream()
+ public async Task EmptyStream()
{
- InteropClient.RunEmptyStream(client);
+ await InteropClient.RunEmptyStreamAsync(client);
}
[Test]
- public void CancelAfterBegin()
+ public async Task CancelAfterBegin()
{
- InteropClient.RunCancelAfterBegin(client);
+ await InteropClient.RunCancelAfterBeginAsync(client);
}
[Test]
- public void CancelAfterFirstResponse()
+ public async Task CancelAfterFirstResponse()
{
- InteropClient.RunCancelAfterFirstResponse(client);
+ await InteropClient.RunCancelAfterFirstResponseAsync(client);
}
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
index 9475e66c40..504fd11857 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
@@ -88,18 +88,20 @@ namespace Grpc.IntegrationTesting
private void Run()
{
- var server = new Server();
- server.AddServiceDefinition(TestService.BindService(new TestServiceImpl()));
+ var server = new Server
+ {
+ Services = { TestService.BindService(new TestServiceImpl()) }
+ };
string host = "0.0.0.0";
int port = options.port.Value;
if (options.useTls)
{
- server.AddListeningPort(host, port, TestCredentials.CreateTestServerCredentials());
+ server.Ports.Add(host, port, TestCredentials.CreateTestServerCredentials());
}
else
{
- server.AddListeningPort(host, options.port.Value);
+ server.Ports.Add(host, options.port.Value, ServerCredentials.Insecure);
}
Console.WriteLine("Running server on " + string.Format("{0}:{1}", host, port));
server.Start();
diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
new file mode 100644
index 0000000000..1c398eb84e
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
@@ -0,0 +1,100 @@
+#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.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using grpc.testing;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.IntegrationTesting
+{
+ /// <summary>
+ /// Test SSL credentials where server authenticates client
+ /// and client authenticates the server.
+ /// </summary>
+ public class SslCredentialsTest
+ {
+ const string Host = "localhost";
+ Server server;
+ Channel channel;
+ TestService.ITestServiceClient client;
+
+ [TestFixtureSetUp]
+ public void Init()
+ {
+ var rootCert = File.ReadAllText(TestCredentials.ClientCertAuthorityPath);
+ var keyCertPair = new KeyCertificatePair(
+ File.ReadAllText(TestCredentials.ServerCertChainPath),
+ File.ReadAllText(TestCredentials.ServerPrivateKeyPath));
+
+ var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert, true);
+ var clientCredentials = new SslCredentials(rootCert, keyCertPair);
+
+ server = new Server
+ {
+ Services = { TestService.BindService(new TestServiceImpl()) },
+ Ports = { { Host, ServerPort.PickUnused, serverCredentials } }
+ };
+ server.Start();
+
+ var options = new List<ChannelOption>
+ {
+ new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
+ };
+
+ channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options);
+ client = TestService.NewClient(channel);
+ }
+
+ [TestFixtureTearDown]
+ public void Cleanup()
+ {
+ channel.Dispose();
+ server.ShutdownAsync().Wait();
+ GrpcEnvironment.Shutdown();
+ }
+
+ [Test]
+ public void AuthenticatedClientAndServer()
+ {
+ var response = client.UnaryCall(SimpleRequest.CreateBuilder().SetResponseSize(10).Build());
+ Assert.AreEqual(10, response.Payload.Body.Length);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
index 401c50b1ae..da0b7fb910 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
@@ -33,7 +33,6 @@
using System;
using System.Collections.Generic;
-using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
@@ -78,7 +77,7 @@ namespace Grpc.IntegrationTesting
var keyCertPair = new KeyCertificatePair(
File.ReadAllText(ServerCertChainPath),
File.ReadAllText(ServerPrivateKeyPath));
- return new SslServerCredentials(ImmutableList.Create(keyCertPair));
+ return new SslServerCredentials(new[] { keyCertPair });
}
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index de2fa07441..697acb53d8 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -22,36 +22,42 @@ namespace grpc.testing {
static readonly Method<global::grpc.testing.Empty, global::grpc.testing.Empty> __Method_EmptyCall = new Method<global::grpc.testing.Empty, global::grpc.testing.Empty>(
MethodType.Unary,
+ __ServiceName,
"EmptyCall",
__Marshaller_Empty,
__Marshaller_Empty);
static readonly Method<global::grpc.testing.SimpleRequest, global::grpc.testing.SimpleResponse> __Method_UnaryCall = new Method<global::grpc.testing.SimpleRequest, global::grpc.testing.SimpleResponse>(
MethodType.Unary,
+ __ServiceName,
"UnaryCall",
__Marshaller_SimpleRequest,
__Marshaller_SimpleResponse);
static readonly Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> __Method_StreamingOutputCall = new Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse>(
MethodType.ServerStreaming,
+ __ServiceName,
"StreamingOutputCall",
__Marshaller_StreamingOutputCallRequest,
__Marshaller_StreamingOutputCallResponse);
static readonly Method<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> __Method_StreamingInputCall = new Method<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse>(
MethodType.ClientStreaming,
+ __ServiceName,
"StreamingInputCall",
__Marshaller_StreamingInputCallRequest,
__Marshaller_StreamingInputCallResponse);
static readonly Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> __Method_FullDuplexCall = new Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse>(
MethodType.DuplexStreaming,
+ __ServiceName,
"FullDuplexCall",
__Marshaller_StreamingOutputCallRequest,
__Marshaller_StreamingOutputCallResponse);
static readonly Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> __Method_HalfDuplexCall = new Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse>(
MethodType.DuplexStreaming,
+ __ServiceName,
"HalfDuplexCall",
__Marshaller_StreamingOutputCallRequest,
__Marshaller_StreamingOutputCallResponse);
@@ -59,14 +65,22 @@ namespace grpc.testing {
// client interface
public interface ITestServiceClient
{
- global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
- global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, CallOptions options);
+ AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, CallOptions options);
+ global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, CallOptions options);
+ AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, CallOptions options);
+ AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, CallOptions options);
+ AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options);
+ AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options);
+ AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options);
}
// server-side interface
@@ -86,45 +100,85 @@ namespace grpc.testing {
public TestServiceClient(Channel channel) : base(channel)
{
}
- public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__ServiceName, __Method_EmptyCall, headers);
- return Calls.BlockingUnaryCall(call, request, cancellationToken);
+ var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.BlockingUnaryCall(call, request);
}
- public AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, CallOptions options)
{
- var call = CreateCall(__ServiceName, __Method_EmptyCall, headers);
- return Calls.AsyncUnaryCall(call, request, cancellationToken);
+ var call = CreateCall(__Method_EmptyCall, options);
+ return Calls.BlockingUnaryCall(call, request);
}
- public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__ServiceName, __Method_UnaryCall, headers);
- return Calls.BlockingUnaryCall(call, request, cancellationToken);
+ var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncUnaryCall(call, request);
}
- public AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, CallOptions options)
{
- var call = CreateCall(__ServiceName, __Method_UnaryCall, headers);
- return Calls.AsyncUnaryCall(call, request, cancellationToken);
+ var call = CreateCall(__Method_EmptyCall, options);
+ return Calls.AsyncUnaryCall(call, request);
}
- public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__ServiceName, __Method_StreamingOutputCall, headers);
- return Calls.AsyncServerStreamingCall(call, request, cancellationToken);
+ var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.BlockingUnaryCall(call, request);
}
- public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, CallOptions options)
{
- var call = CreateCall(__ServiceName, __Method_StreamingInputCall, headers);
- return Calls.AsyncClientStreamingCall(call, cancellationToken);
+ var call = CreateCall(__Method_UnaryCall, options);
+ return Calls.BlockingUnaryCall(call, request);
}
- public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
- var call = CreateCall(__ServiceName, __Method_FullDuplexCall, headers);
- return Calls.AsyncDuplexStreamingCall(call, cancellationToken);
+ var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncUnaryCall(call, request);
}
- public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, CallOptions options)
{
- var call = CreateCall(__ServiceName, __Method_HalfDuplexCall, headers);
- return Calls.AsyncDuplexStreamingCall(call, cancellationToken);
+ var call = CreateCall(__Method_UnaryCall, options);
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_StreamingOutputCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncServerStreamingCall(call, request);
+ }
+ public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, CallOptions options)
+ {
+ var call = CreateCall(__Method_StreamingOutputCall, options);
+ return Calls.AsyncServerStreamingCall(call, request);
+ }
+ public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_StreamingInputCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncClientStreamingCall(call);
+ }
+ public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options)
+ {
+ var call = CreateCall(__Method_StreamingInputCall, options);
+ return Calls.AsyncClientStreamingCall(call);
+ }
+ public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_FullDuplexCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncDuplexStreamingCall(call);
+ }
+ public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options)
+ {
+ var call = CreateCall(__Method_FullDuplexCall, options);
+ return Calls.AsyncDuplexStreamingCall(call);
+ }
+ public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_HalfDuplexCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncDuplexStreamingCall(call);
+ }
+ public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options)
+ {
+ var call = CreateCall(__Method_HalfDuplexCall, options);
+ return Calls.AsyncDuplexStreamingCall(call);
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/app.config b/src/csharp/Grpc.IntegrationTesting/app.config
index 966b777192..0a82bb4f16 100644
--- a/src/csharp/Grpc.IntegrationTesting/app.config
+++ b/src/csharp/Grpc.IntegrationTesting/app.config
@@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
index c74ac75d79..7d1f84f303 100644
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting/packages.config
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Google.Apis.Auth" version="1.9.1" targetFramework="net45" />
- <package id="Google.Apis.Core" version="1.9.1" targetFramework="net45" />
+ <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.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.9" 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.14" targetFramework="net45" />
- <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" />
- <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
+ <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+ <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="net45" />
- <package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 705e4fb1c2..f19f29c6a2 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -34,60 +34,83 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck.Tests", "G
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|x86 = Debug|x86
- Release|x86 = Release|x86
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ ReleaseSigned|Any CPU = ReleaseSigned|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.ActiveCfg = Debug|Any CPU
- {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.Build.0 = Debug|Any CPU
- {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.ActiveCfg = Release|Any CPU
- {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.Build.0 = Release|Any CPU
- {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.ActiveCfg = Debug|x86
- {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.Build.0 = Debug|x86
- {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.ActiveCfg = Release|x86
- {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.Build.0 = Release|x86
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.ActiveCfg = Debug|x86
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.Build.0 = Debug|x86
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.ActiveCfg = Release|x86
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.Build.0 = Release|x86
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.ActiveCfg = Debug|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.Build.0 = Debug|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.ActiveCfg = Release|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.Build.0 = Release|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.ActiveCfg = Debug|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.Build.0 = Debug|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.ActiveCfg = Release|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.Build.0 = Release|Any CPU
- {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.ActiveCfg = Debug|x86
- {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.Build.0 = Debug|x86
- {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.ActiveCfg = Release|x86
- {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.Build.0 = Release|x86
- {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|x86.ActiveCfg = Debug|Any CPU
- {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|x86.Build.0 = Debug|Any CPU
- {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|x86.ActiveCfg = Release|Any CPU
- {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|x86.Build.0 = Release|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.ActiveCfg = Debug|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.Build.0 = Debug|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.ActiveCfg = Release|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.Build.0 = Release|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86
- {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86
- {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86
- {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86
- {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.Build.0 = Release|x86
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.ActiveCfg = Debug|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.Build.0 = Debug|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.ActiveCfg = Release|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.Build.0 = Release|Any CPU
- {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|x86.Build.0 = Debug|Any CPU
- {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|x86.ActiveCfg = Release|Any CPU
- {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|x86.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index c3e5fe8817..9e1253bf0b 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -12,7 +12,7 @@ cd ..\..\vsprojects\nuget_package
@call buildall.bat || goto :error
endlocal
-@call buildall.bat || goto :error
+@call buildall.bat BUILD_SIGNED || goto :error
%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec -Version %CORE_VERSION% || goto :error
%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
diff --git a/src/csharp/buildall.bat b/src/csharp/buildall.bat
index 16860aec3c..d85896c255 100644
--- a/src/csharp/buildall.bat
+++ b/src/csharp/buildall.bat
@@ -9,10 +9,15 @@ cd /d %~dp0
@call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
@rem Build the C# native extension
-msbuild ..\..\vsprojects\grpc.sln /t:grpc_csharp_ext /p:PlatformToolset=v120 || goto :error
+msbuild ..\..\vsprojects\grpc_csharp_ext.sln /p:PlatformToolset=v120 || goto :error
msbuild Grpc.sln /p:Configuration=Debug || goto :error
msbuild Grpc.sln /p:Configuration=Release || goto :error
+
+if "%1" == "BUILD_SIGNED" (
+msbuild Grpc.sln /p:Configuration=ReleaseSigned || goto :error
+)
+
endlocal
goto :EOF
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 682521446f..048887bc12 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -169,7 +169,7 @@ grpcsharp_metadata_array_add(grpc_metadata_array *array, const char *key,
GPR_EXPORT gpr_intptr GPR_CALLTYPE
grpcsharp_metadata_array_count(grpc_metadata_array *array) {
- return (gpr_intptr) array->count;
+ return (gpr_intptr)array->count;
}
GPR_EXPORT const char *GPR_CALLTYPE
@@ -184,10 +184,10 @@ grpcsharp_metadata_array_get_value(grpc_metadata_array *array, size_t index) {
return array->metadata[index].value;
}
-GPR_EXPORT gpr_intptr GPR_CALLTYPE
-grpcsharp_metadata_array_get_value_length(grpc_metadata_array *array, size_t index) {
+GPR_EXPORT gpr_intptr GPR_CALLTYPE grpcsharp_metadata_array_get_value_length(
+ grpc_metadata_array *array, size_t index) {
GPR_ASSERT(index < array->count);
- return (gpr_intptr) array->metadata[index].value_length;
+ return (gpr_intptr)array->metadata[index].value_length;
}
/* Move contents of metadata array */
@@ -306,8 +306,7 @@ grpcsharp_batch_context_server_rpc_new_method(
return ctx->server_rpc_new.call_details.method;
}
-GPR_EXPORT const char *GPR_CALLTYPE
-grpcsharp_batch_context_server_rpc_new_host(
+GPR_EXPORT const char *GPR_CALLTYPE grpcsharp_batch_context_server_rpc_new_host(
const grpcsharp_batch_context *ctx) {
return ctx->server_rpc_new.call_details.host;
}
@@ -367,8 +366,9 @@ grpcsharp_completion_queue_pluck(grpc_completion_queue *cq, void *tag) {
/* Channel */
GPR_EXPORT grpc_channel *GPR_CALLTYPE
-grpcsharp_channel_create(const char *target, const grpc_channel_args *args) {
- return grpc_channel_create(target, args);
+
+grpcsharp_insecure_channel_create(const char *target, const grpc_channel_args *args) {
+ return grpc_insecure_channel_create(target, args);
}
GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_destroy(grpc_channel *channel) {
@@ -379,7 +379,24 @@ GPR_EXPORT grpc_call *GPR_CALLTYPE
grpcsharp_channel_create_call(grpc_channel *channel, grpc_completion_queue *cq,
const char *method, const char *host,
gpr_timespec deadline) {
- return grpc_channel_create_call(channel, cq, method, host, deadline);
+ return grpc_channel_create_call(channel, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
+ method, host, deadline);
+}
+
+GPR_EXPORT grpc_connectivity_state GPR_CALLTYPE
+grpcsharp_channel_check_connectivity_state(grpc_channel *channel, gpr_int32 try_to_connect) {
+ return grpc_channel_check_connectivity_state(channel, try_to_connect);
+}
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_watch_connectivity_state(
+ grpc_channel *channel, grpc_connectivity_state last_observed_state,
+ gpr_timespec deadline, grpc_completion_queue *cq, grpcsharp_batch_context *ctx) {
+ grpc_channel_watch_connectivity_state(channel, last_observed_state,
+ deadline, cq, ctx);
+}
+
+GPR_EXPORT char *GPR_CALLTYPE grpcsharp_channel_get_target(grpc_channel *channel) {
+ return grpc_channel_get_target(channel);
}
/* Channel args */
@@ -433,10 +450,20 @@ grpcsharp_channel_args_destroy(grpc_channel_args *args) {
/* Timespec */
-GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_now(void) { return gpr_now(GPR_CLOCK_REALTIME); }
+GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_now(gpr_clock_type clock_type) {
+ return gpr_now(clock_type);
+}
-GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_inf_future(void) {
- return gpr_inf_future(GPR_CLOCK_REALTIME);
+GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_inf_future(gpr_clock_type clock_type) {
+ return gpr_inf_future(clock_type);
+}
+
+GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_inf_past(gpr_clock_type clock_type) {
+ return gpr_inf_past(clock_type);
+}
+
+GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_convert_clock_type(gpr_timespec t, gpr_clock_type target_clock) {
+ return gpr_convert_clock_type(t, target_clock);
}
GPR_EXPORT gpr_int32 GPR_CALLTYPE gprsharp_sizeof_timespec(void) {
@@ -455,6 +482,14 @@ grpcsharp_call_cancel_with_status(grpc_call *call, grpc_status_code status,
return grpc_call_cancel_with_status(call, status, description);
}
+GPR_EXPORT char *GPR_CALLTYPE grpcsharp_call_get_peer(grpc_call *call) {
+ return grpc_call_get_peer(call);
+}
+
+GPR_EXPORT void GPR_CALLTYPE gprsharp_free(void *p) {
+ gpr_free(p);
+}
+
GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call *call) {
grpc_call_destroy(call);
}
@@ -638,20 +673,17 @@ grpcsharp_call_send_close_from_client(grpc_call *call,
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
}
-GPR_EXPORT grpc_call_error GPR_CALLTYPE
-grpcsharp_call_send_status_from_server(grpc_call *call,
- grpcsharp_batch_context *ctx,
- grpc_status_code status_code,
- const char *status_details,
- grpc_metadata_array *trailing_metadata) {
+GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
+ grpc_call *call, grpcsharp_batch_context *ctx, grpc_status_code status_code,
+ const char *status_details, grpc_metadata_array *trailing_metadata) {
/* TODO: don't use magic number */
grpc_op ops[1];
ops[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
ops[0].data.send_status_from_server.status = status_code;
ops[0].data.send_status_from_server.status_details =
gpr_strdup(status_details);
- grpcsharp_metadata_array_move(&(ctx->send_status_from_server.trailing_metadata),
- trailing_metadata);
+ grpcsharp_metadata_array_move(
+ &(ctx->send_status_from_server.trailing_metadata), trailing_metadata);
ops[0].data.send_status_from_server.trailing_metadata_count =
ctx->send_status_from_server.trailing_metadata.count;
ops[0].data.send_status_from_server.trailing_metadata =
@@ -699,8 +731,8 @@ grpcsharp_server_create(grpc_completion_queue *cq,
}
GPR_EXPORT gpr_int32 GPR_CALLTYPE
-grpcsharp_server_add_http2_port(grpc_server *server, const char *addr) {
- return grpc_server_add_http2_port(server, addr);
+grpcsharp_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
+ return grpc_server_add_insecure_http2_port(server, addr);
}
GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_start(grpc_server *server) {
@@ -761,7 +793,8 @@ grpcsharp_secure_channel_create(grpc_credentials *creds, const char *target,
GPR_EXPORT grpc_server_credentials *GPR_CALLTYPE
grpcsharp_ssl_server_credentials_create(
const char *pem_root_certs, const char **key_cert_pair_cert_chain_array,
- const char **key_cert_pair_private_key_array, size_t num_key_cert_pairs) {
+ const char **key_cert_pair_private_key_array, size_t num_key_cert_pairs,
+ int force_client_auth) {
size_t i;
grpc_server_credentials *creds;
grpc_ssl_pem_key_cert_pair *key_cert_pairs =
@@ -777,7 +810,8 @@ grpcsharp_ssl_server_credentials_create(
}
}
creds = grpc_ssl_server_credentials_create(pem_root_certs, key_cert_pairs,
- num_key_cert_pairs);
+ num_key_cert_pairs,
+ force_client_auth);
gpr_free(key_cert_pairs);
return creds;
}
diff --git a/src/csharp/keys/Grpc.public.snk b/src/csharp/keys/Grpc.public.snk
new file mode 100644
index 0000000000..bac3046b36
--- /dev/null
+++ b/src/csharp/keys/Grpc.public.snk
Binary files differ
diff --git a/src/csharp/keys/README.md b/src/csharp/keys/README.md
new file mode 100644
index 0000000000..f3e9a3cb56
--- /dev/null
+++ b/src/csharp/keys/README.md
@@ -0,0 +1,5 @@
+Contents
+--------
+
+- Grpc.public.snk:
+ Public key to verify strong name of gRPC assemblies. \ No newline at end of file