diff --git a/src/csharp/Grpc.Auth/AuthInterceptors.cs b/src/csharp/Grpc.Auth/AuthInterceptors.cs
new file mode 100644
index 00000000000..61338f7f0e2
--- /dev/null
+++ b/src/csharp/Grpc.Auth/AuthInterceptors.cs
@@ -0,0 +1,84 @@
+#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 Google.Apis.Auth.OAuth2;
+using Grpc.Core;
+using Grpc.Core.Utils;
+
+namespace Grpc.Auth
+{
+ ///
+ /// Factory methods to create authorization interceptors.
+ ///
+ public static class AuthInterceptors
+ {
+ private const string AuthorizationHeader = "Authorization";
+ private const string Schema = "Bearer";
+
+ ///
+ /// Creates interceptor that will obtain access token from any credential type that implements
+ /// ITokenAccess. (e.g. GoogleCredential).
+ ///
+ public static HeaderInterceptor FromCredential(ITokenAccess credential)
+ {
+ return new HeaderInterceptor((method, authUri, metadata) =>
+ {
+ // TODO(jtattermusch): Rethink synchronous wait to obtain the result.
+ var accessToken = credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None)
+ .ConfigureAwait(false).GetAwaiter().GetResult();
+ metadata.Add(CreateBearerTokenHeader(accessToken));
+ });
+ }
+
+ ///
+ /// Creates OAuth2 interceptor that will use given access token as authorization.
+ ///
+ /// OAuth2 access token.
+ public static HeaderInterceptor FromAccessToken(string accessToken)
+ {
+ Preconditions.CheckNotNull(accessToken);
+ return new HeaderInterceptor((method, authUri, metadata) =>
+ {
+ metadata.Add(CreateBearerTokenHeader(accessToken));
+ });
+ }
+
+ private static Metadata.Entry CreateBearerTokenHeader(string accessToken)
+ {
+ return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index 930a34b0c33..4fb087d4a34 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -3,8 +3,6 @@
DebugAnyCPU
- 10.0.0
- 2.0{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}LibraryGrpc.Auth
@@ -41,57 +39,47 @@
C:\keys\Grpc.snk
-
- False
+
+
+
+
+ ..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll
-
- False
+ ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll
-
- False
+ ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll
-
- False
+ ..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll
-
- False
+ ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll
-
- False
+ ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll
-
- False
+ ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll
-
- False
+ ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
-
-
-
-
- False
+ ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll
-
- False
+ ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll
-
Version.cs
-
+
diff --git a/src/csharp/Grpc.Auth/OAuth2Interceptors.cs b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
deleted file mode 100644
index d628a83246d..00000000000
--- a/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-#region Copyright notice and license
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Security.Cryptography.X509Certificates;
-using System.Text.RegularExpressions;
-using System.Threading;
-using System.Threading.Tasks;
-
-using Google.Apis.Auth.OAuth2;
-using Google.Apis.Util;
-using Grpc.Core;
-using Grpc.Core.Utils;
-
-namespace Grpc.Auth
-{
- public static class OAuth2Interceptors
- {
- ///
- /// Creates OAuth2 interceptor that will obtain access token from GoogleCredentials.
- ///
- public static MetadataInterceptorDelegate FromCredential(GoogleCredential googleCredential)
- {
- var interceptor = new OAuth2Interceptor(googleCredential, SystemClock.Default);
- return new MetadataInterceptorDelegate(interceptor.InterceptHeaders);
- }
-
- ///
- /// Creates OAuth2 interceptor that will use given OAuth2 token.
- ///
- ///
- ///
- public static MetadataInterceptorDelegate FromAccessToken(string oauth2Token)
- {
- Preconditions.CheckNotNull(oauth2Token);
- return new MetadataInterceptorDelegate((authUri, metadata) =>
- {
- metadata.Add(OAuth2Interceptor.CreateBearerTokenHeader(oauth2Token));
- });
- }
-
- ///
- /// Injects OAuth2 authorization header into initial metadata (= request headers).
- ///
- private class OAuth2Interceptor
- {
- private const string AuthorizationHeader = "Authorization";
- private const string Schema = "Bearer";
-
- private ITokenAccess credential;
- private IClock clock;
-
- public OAuth2Interceptor(ITokenAccess credential, IClock clock)
- {
- this.credential = credential;
- this.clock = clock;
- }
-
- ///
- /// Gets access token and requests refreshing it if is going to expire soon.
- ///
- ///
- ///
- public string GetAccessToken(string authUri, CancellationToken cancellationToken)
- {
- // TODO(jtattermusch): Rethink synchronous wait to obtain the result.
- return credential.GetAccessTokenForRequestAsync(authUri, cancellationToken: cancellationToken).GetAwaiter().GetResult();
- }
-
- public void InterceptHeaders(string authUri, Metadata metadata)
- {
- var accessToken = GetAccessToken(authUri, CancellationToken.None);
- metadata.Add(CreateBearerTokenHeader(accessToken));
- }
-
- public static Metadata.Entry CreateBearerTokenHeader(string accessToken)
- {
- return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken);
- }
- }
- }
-}
diff --git a/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs b/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
index bf020cd6274..fb9b562c77b 100644
--- a/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
+++ b/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
@@ -88,6 +88,24 @@ namespace Grpc.Core
return responseAsync.GetAwaiter();
}
+ ///
+ /// Gets the call status if the call has already finished.
+ /// Throws InvalidOperationException otherwise.
+ ///
+ public Status GetStatus()
+ {
+ return getStatusFunc();
+ }
+
+ ///
+ /// Gets the call trailing metadata if the call has already finished.
+ /// Throws InvalidOperationException otherwise.
+ ///
+ public Metadata GetTrailers()
+ {
+ return getTrailersFunc();
+ }
+
///
/// Provides means to cleanup after the call.
/// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything.
diff --git a/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs b/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
index 0979de606f7..183c84216a0 100644
--- a/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
+++ b/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
@@ -32,8 +32,6 @@
#endregion
using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
namespace Grpc.Core
{
diff --git a/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs b/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
index 380efcdb0e2..ab2049f2695 100644
--- a/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
+++ b/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
@@ -32,8 +32,6 @@
#endregion
using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
namespace Grpc.Core
{
diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs
index 0cb2953f2c2..ad54b46ad59 100644
--- a/src/csharp/Grpc.Core/ChannelOptions.cs
+++ b/src/csharp/Grpc.Core/ChannelOptions.cs
@@ -71,7 +71,7 @@ namespace Grpc.Core
/// Creates a channel option with an integer value.
///
/// Name.
- /// String value.
+ /// Integer value.
public ChannelOption(string name, int intValue)
{
this.type = OptionType.Integer;
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index f240d777b9c..7bc100ca603 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -32,15 +32,15 @@
#endregion
using System;
-using System.Collections.Generic;
using System.Text.RegularExpressions;
-
-using Grpc.Core.Internal;
-using Grpc.Core.Utils;
+using System.Threading.Tasks;
namespace Grpc.Core
{
- public delegate void MetadataInterceptorDelegate(string authUri, Metadata metadata);
+ ///
+ /// Interceptor for call headers.
+ ///
+ public delegate void HeaderInterceptor(IMethod method, string authUri, Metadata metadata);
///
/// Base class for client-side stubs.
@@ -60,10 +60,10 @@ namespace Grpc.Core
}
///
- /// Can be used to register a custom header (initial metadata) interceptor.
- /// The delegate each time before a new call on this client is started.
+ /// Can be used to register a custom header (request metadata) interceptor.
+ /// The interceptor is invoked each time a new call on this client is started.
///
- public MetadataInterceptorDelegate HeaderInterceptor
+ public HeaderInterceptor HeaderInterceptor
{
get;
set;
@@ -107,7 +107,7 @@ namespace Grpc.Core
options = options.WithHeaders(new Metadata());
}
var authUri = authUriBase != null ? authUriBase + method.ServiceName : null;
- interceptor(authUri, options.Headers);
+ interceptor(method, authUri, options.Headers);
}
return new CallInvocationDetails(channel, method, Host, options);
}
diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs
index 4c208b4a263..4c53285893e 100644
--- a/src/csharp/Grpc.Core/Method.cs
+++ b/src/csharp/Grpc.Core/Method.cs
@@ -54,10 +54,37 @@ namespace Grpc.Core
DuplexStreaming
}
+ ///
+ /// A non-generic representation of a remote method.
+ ///
+ public interface IMethod
+ {
+ ///
+ /// Gets the type of the method.
+ ///
+ MethodType Type { get; }
+
+ ///
+ /// Gets the name of the service to which this method belongs.
+ ///
+ string ServiceName { get; }
+
+ ///
+ /// Gets the unqualified name of the method.
+ ///
+ string Name { get; }
+
+ ///
+ /// Gets the fully qualified name of the method. On the server side, methods are dispatched
+ /// based on this name.
+ ///
+ string FullName { get; }
+ }
+
///
/// A description of a remote method.
///
- public class Method
+ public class Method : IMethod
{
readonly MethodType type;
readonly string serviceName;
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 385ca920862..f4b0a1028f9 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -308,7 +308,7 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("running service_account_creds");
var credential = await GoogleCredential.GetApplicationDefaultAsync();
credential = credential.CreateScoped(new[] { AuthScope });
- client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
+ client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
var request = SimpleRequest.CreateBuilder()
.SetResponseType(PayloadType.COMPRESSABLE)
@@ -332,7 +332,7 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("running compute_engine_creds");
var credential = await GoogleCredential.GetApplicationDefaultAsync();
Assert.IsFalse(credential.IsCreateScopedRequired);
- client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
+ client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
var request = SimpleRequest.CreateBuilder()
.SetResponseType(PayloadType.COMPRESSABLE)
@@ -357,7 +357,7 @@ namespace Grpc.IntegrationTesting
var credential = await GoogleCredential.GetApplicationDefaultAsync();
// check this a credential with scope support, but don't add the scope.
Assert.IsTrue(credential.IsCreateScopedRequired);
- client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
+ client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
var request = SimpleRequest.CreateBuilder()
.SetResponseType(PayloadType.COMPRESSABLE)
@@ -381,7 +381,7 @@ namespace Grpc.IntegrationTesting
ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope });
string oauth2Token = await credential.GetAccessTokenForRequestAsync();
- client.HeaderInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
+ client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token);
var request = SimpleRequest.CreateBuilder()
.SetFillUsername(true)
@@ -401,7 +401,7 @@ namespace Grpc.IntegrationTesting
ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope });
string oauth2Token = await credential.GetAccessTokenForRequestAsync();
- var headerInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
+ var headerInterceptor = AuthInterceptors.FromAccessToken(oauth2Token);
var request = SimpleRequest.CreateBuilder()
.SetFillUsername(true)
@@ -409,7 +409,7 @@ namespace Grpc.IntegrationTesting
.Build();
var headers = new Metadata();
- headerInterceptor("", headers);
+ headerInterceptor(null, "", headers);
var response = client.UnaryCall(request, headers: headers);
Assert.AreEqual(AuthScopeResponse, response.OauthScope);