aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp/Grpc.Core/ClientBase.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/csharp/Grpc.Core/ClientBase.cs')
-rw-r--r--src/csharp/Grpc.Core/ClientBase.cs161
1 files changed, 112 insertions, 49 deletions
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index e5b398062b..5517233e3c 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -1,6 +1,6 @@
#region Copyright notice and license
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -31,93 +31,156 @@
#endregion
-using System;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
- /// Interceptor for call headers.
+ /// Generic base class for client-side stubs.
/// </summary>
- /// <remarks>Header interceptor is no longer to recommented way to perform authentication.
- /// For header (initial metadata) based auth such as OAuth2 or JWT access token, use <see cref="MetadataCredentials"/>.
- /// </remarks>
- public delegate void HeaderInterceptor(IMethod method, Metadata metadata);
+ public abstract class ClientBase<T> : ClientBase
+ where T : ClientBase<T>
+ {
+ /// <summary>
+ /// Initializes a new instance of <c>ClientBase</c> class that
+ /// throws <c>NotImplementedException</c> upon invocation of any RPC.
+ /// This constructor is only provided to allow creation of test doubles
+ /// for client classes (e.g. mocking requires a parameterless constructor).
+ /// </summary>
+ protected ClientBase() : base()
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of <c>ClientBase</c> class.
+ /// </summary>
+ /// <param name="configuration">The configuration.</param>
+ protected ClientBase(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of <c>ClientBase</c> class.
+ /// </summary>
+ /// <param name="channel">The channel to use for remote call invocation.</param>
+ public ClientBase(Channel channel) : base(channel)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of <c>ClientBase</c> class.
+ /// </summary>
+ /// <param name="callInvoker">The <c>CallInvoker</c> for remote call invocation.</param>
+ public ClientBase(CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+
+ /// <summary>
+ /// Creates a new client that sets host field for calls explicitly.
+ /// gRPC supports multiple "hosts" being served by a single server.
+ /// By default (if a client was not created by calling this method),
+ /// host <c>null</c> with the meaning "use default host" is used.
+ /// </summary>
+ public T WithHost(string host)
+ {
+ var newConfiguration = this.Configuration.WithHost(host);
+ return NewInstance(newConfiguration);
+ }
+
+ /// <summary>
+ /// Creates a new instance of client from given <c>ClientBaseConfiguration</c>.
+ /// </summary>
+ protected abstract T NewInstance(ClientBaseConfiguration configuration);
+ }
/// <summary>
/// Base class for client-side stubs.
/// </summary>
public abstract class ClientBase
{
- readonly Channel channel;
+ readonly ClientBaseConfiguration configuration;
+ readonly CallInvoker callInvoker;
+
+ /// <summary>
+ /// Initializes a new instance of <c>ClientBase</c> class that
+ /// throws <c>NotImplementedException</c> upon invocation of any RPC.
+ /// This constructor is only provided to allow creation of test doubles
+ /// for client classes (e.g. mocking requires a parameterless constructor).
+ /// </summary>
+ protected ClientBase() : this(new UnimplementedCallInvoker())
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of <c>ClientBase</c> class.
+ /// </summary>
+ /// <param name="configuration">The configuration.</param>
+ protected ClientBase(ClientBaseConfiguration configuration)
+ {
+ this.configuration = GrpcPreconditions.CheckNotNull(configuration, "configuration");
+ this.callInvoker = configuration.CreateDecoratedCallInvoker();
+ }
/// <summary>
/// Initializes a new instance of <c>ClientBase</c> class.
/// </summary>
/// <param name="channel">The channel to use for remote call invocation.</param>
- public ClientBase(Channel channel)
+ public ClientBase(Channel channel) : this(new DefaultCallInvoker(channel))
{
- this.channel = channel;
}
/// <summary>
- /// Can be used to register a custom header interceptor.
- /// The interceptor is invoked each time a new call on this client is started.
- /// It is not recommented to use header interceptor to add auth headers to RPC calls.
+ /// Initializes a new instance of <c>ClientBase</c> class.
/// </summary>
- /// <seealso cref="HeaderInterceptor"/>
- public HeaderInterceptor HeaderInterceptor
+ /// <param name="callInvoker">The <c>CallInvoker</c> for remote call invocation.</param>
+ public ClientBase(CallInvoker callInvoker) : this(new ClientBaseConfiguration(callInvoker, null))
{
- get;
- set;
}
/// <summary>
- /// gRPC supports multiple "hosts" being served by a single server.
- /// This property can be used to set the target host explicitly.
- /// By default, this will be set to <c>null</c> with the meaning
- /// "use default host".
+ /// Gets the call invoker.
/// </summary>
- public string Host
+ protected CallInvoker CallInvoker
{
- get;
- set;
+ get { return this.callInvoker; }
}
/// <summary>
- /// Channel associated with this client.
+ /// Gets the configuration.
/// </summary>
- public Channel Channel
+ internal ClientBaseConfiguration Configuration
{
- get
- {
- return this.channel;
- }
+ get { return this.configuration; }
}
/// <summary>
- /// Creates a new call to given method.
+ /// Represents configuration of ClientBase. The class itself is visible to
+ /// subclasses, but contents are marked as internal to make the instances opaque.
+ /// The verbose name of this class was chosen to make name clash in generated code
+ /// less likely.
/// </summary>
- /// <param name="method">The method to invoke.</param>
- /// <param name="options">The call options.</param>
- /// <typeparam name="TRequest">Request message type.</typeparam>
- /// <typeparam name="TResponse">Response message type.</typeparam>
- /// <returns>The call invocation details.</returns>
- protected CallInvocationDetails<TRequest, TResponse> CreateCall<TRequest, TResponse>(Method<TRequest, TResponse> method, CallOptions options)
- where TRequest : class
- where TResponse : class
+ protected internal class ClientBaseConfiguration
{
- var interceptor = HeaderInterceptor;
- if (interceptor != null)
+ readonly CallInvoker undecoratedCallInvoker;
+ readonly string host;
+
+ internal ClientBaseConfiguration(CallInvoker undecoratedCallInvoker, string host)
+ {
+ this.undecoratedCallInvoker = GrpcPreconditions.CheckNotNull(undecoratedCallInvoker);
+ this.host = host;
+ }
+
+ internal CallInvoker CreateDecoratedCallInvoker()
+ {
+ return new InterceptingCallInvoker(undecoratedCallInvoker, hostInterceptor: (h) => host);
+ }
+
+ internal ClientBaseConfiguration WithHost(string host)
{
- if (options.Headers == null)
- {
- options = options.WithHeaders(new Metadata());
- }
- interceptor(method, options.Headers);
+ GrpcPreconditions.CheckNotNull(host, "host");
+ return new ClientBaseConfiguration(this.undecoratedCallInvoker, host);
}
- return new CallInvocationDetails<TRequest, TResponse>(channel, method, Host, options);
}
}
}