Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add delegate for HttpClient override #64

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,20 +142,33 @@ VaultConfiguration config = new VaultConfiguration("http:127.0.0.1:8200");
VaultClient vaultClient = new VaultClient(config);
```

You can also add custom configuration including a custom `HttpClientHandler`.
This can be used to intercept requests and add custom logic before the base
`SendAsync` is called by the HttpClient. See [HttpClientHandler docs][http-client-handler-docs] for more details.
We also allow you to bring your own `HttpClient` through a delegate. This can work
with any current factory pattern that you're using to create an `HttpClient`
object, which is one of the recommended patterns for managing your `HttpClient`
lifecycle. More on the `IHttpClientFactory` can be found [here][[http-client-factory]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bad link?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh whooops


```csharp
// Create a custom HttpClientHandler
HttpClientHandler myClientHandler = new HttpClientHandler();
// Create a HttpClient Provider Function
public static HttpClient MyHttpClientProvider(HttpClientHandler handler)
{
// Configuring your own HttpClient
HttpClient httpClient = new HttpClient(handler);
httpClient.Timeout = TimeSpan.FromSeconds(60);
return httpClient;
}
```

```csharp
// Configuring Vault with your custom HttpClient Provider
VaultConfiguration config = new VaultConfiguration("http://127.0.0.1:8200",
myClientHandler);
httpClientProvider: MyHttpClientProvider);
```

The VaultClient also allows you to set a custom Timeout for all API calls.

_**Note**_: This timeout will override any timeout in a preconfigured `HttpClient`


```csharp
VaultConfiguration config = new VaultConfiguration(basePath: address,
httpClientHandler: httpClientHandler,
Expand Down
28 changes: 14 additions & 14 deletions generate/templates/Configuration.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace {{packageName}}.Client
{
{
/// <summary>
/// Represents the TLS Configuration
/// </summary>
Expand Down Expand Up @@ -168,17 +168,17 @@ namespace {{packageName}}.Client

#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="{{packageName}}Configuration" /> class
/// Initializes a new instance of the <see cref="VaultConfiguration" /> class
/// </summary>
public {{packageName}}Configuration(string basePath,
HttpClientHandler httpClientHandler = null,
public VaultConfiguration(string basePath,
Func<HttpClientHandler, HttpClient> httpClientProvider = null,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is Func here? shouldn't this be HttpClient?
(sorry if dumb question, looks weird from a non-c# perspective)

I saw IHttpClientFactory above, shouldn't it take that as the param type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this is kind of weird. But because the VaultClient needs to configure the HttpClientHandler (for TLS among other things), which the HttpClient is dependent on we have to allow users to pass a delegate (i.e. Func) to new up their own HttpClient with our pre-configured client handler.

Copy link
Contributor Author

@AnPucel AnPucel Dec 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was debating whether to allow just to pass their own HttpClient object, like you're suggesting, but if they wanted to utilize the TLS, then they'd have to preconfigure it, which may be annoying.

It could be that we offer both options.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the Go version, we allow you to provide HTTPClient directly but then override the TLS options (if configured). Not sure if this is something doable here.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this make sense in the context of IHttpClientFactory, as the factory manages the HttpClientHandler instances?

TimeSpan? timeout = null,
RetryConfiguration retryConfiguration = null,
RateLimitConfiguration rateLimitConfiguration = null,
TLSConfiguration tlsConfiguration = null)
{
if (string.IsNullOrEmpty(basePath)) throw new ArgumentException("Cannot be empty", "BasePath");
HttpClientHandler = httpClientHandler ?? new HttpClientHandler();
HttpClientHandler = new HttpClientHandler();

if (tlsConfiguration != null)
{
Expand All @@ -189,7 +189,7 @@ namespace {{packageName}}.Client
{
throw new ArgumentException("Certificate does not contain a private key");
}
httpClientHandler.ClientCertificates.Add(TLSConfiguration.ClientCertificate);
HttpClientHandler.ClientCertificates.Add(TLSConfiguration.ClientCertificate);
}
else if (TLSConfiguration.ClientCertificateCollection != null)
{
Expand All @@ -201,7 +201,7 @@ namespace {{packageName}}.Client
}
}

httpClientHandler.ClientCertificates.AddRange(TLSConfiguration.ClientCertificateCollection);
HttpClientHandler.ClientCertificates.AddRange(TLSConfiguration.ClientCertificateCollection);
}

Func<object, X509Certificate, X509Chain, SslPolicyErrors, bool> ValidateServiceCertficate =
Expand All @@ -225,17 +225,17 @@ namespace {{packageName}}.Client
return true;
};

httpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
httpClientHandler.ServerCertificateCustomValidationCallback = ValidateServiceCertficate;
HttpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
HttpClientHandler.ServerCertificateCustomValidationCallback = ValidateServiceCertficate;
}


timeout = timeout ?? TimeSpan.FromSeconds(100);
RetryConfiguration = retryConfiguration ?? new RetryConfiguration(5, TimeSpan.FromMilliseconds(500));
RateLimitConfiguration = rateLimitConfiguration ?? new RateLimitConfiguration(50, TimeSpan.FromSeconds(5));

BasePath = basePath.EndsWith("/") ? basePath : basePath + "/";
HttpClient = new HttpClient(HttpClientHandler);

HttpClient = httpClientProvider == null ? new HttpClient(HttpClientHandler) : httpClientProvider(HttpClientHandler);
timeout = timeout ?? TimeSpan.FromSeconds(100);
HttpClient.Timeout = (TimeSpan)timeout;
}

Expand All @@ -246,7 +246,7 @@ namespace {{packageName}}.Client
/// <summary>
/// Gets or sets the base path for API access.
/// </summary>
public virtual string BasePath
public virtual string BasePath
{
get { return _basePath; }
set { _basePath = value; }
Expand Down Expand Up @@ -344,7 +344,7 @@ namespace {{packageName}}.Client

return apiKeyValue;
}

/// <summary>
/// Gets or sets the access token for OAuth2 authentication.
///
Expand Down
25 changes: 19 additions & 6 deletions generate/templates/README.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -164,20 +164,33 @@ VaultConfiguration config = new VaultConfiguration("http:127.0.0.1:8200");
VaultClient vaultClient = new VaultClient(config);
```

You can also add custom configuration including a custom `HttpClientHandler`.
This can be used to intercept requests and add custom logic before the base
`SendAsync` is called by the HttpClient. See [HttpClientHandler docs][http-client-handler-docs] for more details.
We also allow you to bring your own `HttpClient` through a delegate. This can work
with any current factory pattern that you're using to create an `HttpClient`
object, which is one of the recommended patterns for managing your `HttpClient`
lifecycle. More on the `IHttpClientFactory` can be found [here][[http-client-factory]]

```csharp
// Create a custom HttpClientHandler
HttpClientHandler myClientHandler = new HttpClientHandler();
// Create a HttpClient Provider Function
public static HttpClient MyHttpClientProvider(HttpClientHandler handler)
{
// Configuring your own HttpClient
HttpClient httpClient = new HttpClient(handler);
httpClient.Timeout = TimeSpan.FromSeconds(60);
return httpClient;
}
```

```csharp
// Configuring Vault with your custom HttpClient Provider
VaultConfiguration config = new VaultConfiguration("http://127.0.0.1:8200",
myClientHandler);
httpClientProvider: MyHttpClientProvider);
```

The VaultClient also allows you to set a custom Timeout for all API calls.

_**Note**_: This timeout will override any timeout in a preconfigured `HttpClient`


```csharp
VaultConfiguration config = new VaultConfiguration(basePath: address,
httpClientHandler: httpClientHandler,
Expand Down
24 changes: 12 additions & 12 deletions src/Vault/Client/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
using System.Text;

namespace Vault.Client
{
{
/// <summary>
/// Represents the TLS Configuration
/// </summary>
Expand Down Expand Up @@ -161,14 +161,14 @@ public class VaultConfiguration
/// Initializes a new instance of the <see cref="VaultConfiguration" /> class
/// </summary>
public VaultConfiguration(string basePath,
HttpClientHandler httpClientHandler = null,
Func<HttpClientHandler, HttpClient> httpClientProvider = null,
TimeSpan? timeout = null,
RetryConfiguration retryConfiguration = null,
RateLimitConfiguration rateLimitConfiguration = null,
TLSConfiguration tlsConfiguration = null)
{
if (string.IsNullOrEmpty(basePath)) throw new ArgumentException("Cannot be empty", "BasePath");
HttpClientHandler = httpClientHandler ?? new HttpClientHandler();
HttpClientHandler = new HttpClientHandler();

if (tlsConfiguration != null)
{
Expand All @@ -179,7 +179,7 @@ public VaultConfiguration(string basePath,
{
throw new ArgumentException("Certificate does not contain a private key");
}
httpClientHandler.ClientCertificates.Add(TLSConfiguration.ClientCertificate);
HttpClientHandler.ClientCertificates.Add(TLSConfiguration.ClientCertificate);
}
else if (TLSConfiguration.ClientCertificateCollection != null)
{
Expand All @@ -191,7 +191,7 @@ public VaultConfiguration(string basePath,
}
}

httpClientHandler.ClientCertificates.AddRange(TLSConfiguration.ClientCertificateCollection);
HttpClientHandler.ClientCertificates.AddRange(TLSConfiguration.ClientCertificateCollection);
}

Func<object, X509Certificate, X509Chain, SslPolicyErrors, bool> ValidateServiceCertficate =
Expand All @@ -215,17 +215,17 @@ public VaultConfiguration(string basePath,
return true;
};

httpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
httpClientHandler.ServerCertificateCustomValidationCallback = ValidateServiceCertficate;
HttpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
HttpClientHandler.ServerCertificateCustomValidationCallback = ValidateServiceCertficate;
}


timeout = timeout ?? TimeSpan.FromSeconds(100);
RetryConfiguration = retryConfiguration ?? new RetryConfiguration(5, TimeSpan.FromMilliseconds(500));
RateLimitConfiguration = rateLimitConfiguration ?? new RateLimitConfiguration(50, TimeSpan.FromSeconds(5));

BasePath = basePath.EndsWith("/") ? basePath : basePath + "/";
HttpClient = new HttpClient(HttpClientHandler);

HttpClient = httpClientProvider == null ? new HttpClient(HttpClientHandler) : httpClientProvider(HttpClientHandler);
timeout = timeout ?? TimeSpan.FromSeconds(100);
HttpClient.Timeout = (TimeSpan)timeout;
}

Expand All @@ -236,7 +236,7 @@ public VaultConfiguration(string basePath,
/// <summary>
/// Gets or sets the base path for API access.
/// </summary>
public virtual string BasePath
public virtual string BasePath
{
get { return _basePath; }
set { _basePath = value; }
Expand Down Expand Up @@ -334,7 +334,7 @@ public string GetApiKeyWithPrefix(string apiKeyIdentifier)

return apiKeyValue;
}

/// <summary>
/// Gets or sets the access token for OAuth2 authentication.
///
Expand Down