-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHttpClientWithCacheExtensions.cs
More file actions
185 lines (167 loc) · 8.98 KB
/
HttpClientWithCacheExtensions.cs
File metadata and controls
185 lines (167 loc) · 8.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Reliable.HttpClient.Caching.Abstractions;
namespace Reliable.HttpClient.Caching.Extensions;
/// <summary>
/// Extension methods for registering universal HTTP client with caching
/// </summary>
public static class HttpClientWithCacheExtensions
{
/// <summary>
/// Adds universal HTTP client with caching to the service collection
/// </summary>
/// <param name="services">Service collection</param>
/// <param name="httpClientName">HTTP client name (optional)</param>
/// <param name="cacheOptions">Cache options including default headers and settings (optional)</param>
/// <returns>Service collection for method chaining</returns>
public static IServiceCollection AddHttpClientWithCache(
this IServiceCollection services,
string? httpClientName = null,
HttpCacheOptions? cacheOptions = null)
{
// Register dependencies
services.AddMemoryCache();
services.AddSingleton<ISimpleCacheKeyGenerator, DefaultSimpleCacheKeyGenerator>();
// Register the universal HTTP client with cache as scoped to avoid captive dependency
services.AddScoped<IHttpClientWithCache>(sp => CreateHttpClientWithCache(sp, httpClientName, cacheOptions));
services.AddScoped(sp => (HttpClientWithCache)sp.GetRequiredService<IHttpClientWithCache>());
return services;
}
/// <summary>
/// Adds universal HTTP client with caching to the service collection
/// </summary>
/// <param name="services">Service collection</param>
/// <param name="httpClientName">HTTP client name (optional)</param>
/// <param name="configureCacheOptions">Action to configure cache options
/// which then will be registered as <see cref="IOptions{TOptions}"/> named after <paramref name="httpClientName"/></param>
/// <returns>Service collection for method chaining</returns>
public static IServiceCollection AddHttpClientWithCache(
this IServiceCollection services,
string? httpClientName,
Action<HttpCacheOptions> configureCacheOptions)
{
var options = new HttpCacheOptions();
configureCacheOptions(options);
services.Configure(httpClientName, configureCacheOptions);
return services.AddHttpClientWithCache(httpClientName, options);
}
/// <summary>
/// Adds universal HTTP client with caching and resilience to the service collection
/// </summary>
/// <param name="services">Service collection</param>
/// <param name="httpClientName">HTTP client name</param>
/// <param name="configureResilience">Action to configure resilience options</param>
/// <param name="cacheOptions">Cache options including default headers and settings (optional)</param>
/// <returns>Service collection for method chaining</returns>
public static IServiceCollection AddResilientHttpClientWithCache(
this IServiceCollection services,
string httpClientName,
Action<HttpClientOptions>? configureResilience = null,
HttpCacheOptions? cacheOptions = null)
{
// Add HTTP client with resilience
services.AddHttpClient(httpClientName)
.AddResilience(configureResilience);
// Add universal HTTP client with cache
return services.AddHttpClientWithCache(httpClientName, cacheOptions);
}
/// <summary>
/// Adds universal HTTP client with caching using preset resilience configuration
/// </summary>
/// <param name="services">Service collection</param>
/// <param name="httpClientName">HTTP client name</param>
/// <param name="preset">Predefined resilience preset</param>
/// <param name="customizeOptions">Optional action to customize preset options</param>
/// <param name="cacheOptions">Cache options including default headers and settings (optional)</param>
/// <returns>Service collection for method chaining</returns>
public static IServiceCollection AddResilientHttpClientWithCache(
this IServiceCollection services,
string httpClientName,
HttpClientOptions preset,
Action<HttpClientOptions>? customizeOptions = null,
HttpCacheOptions? cacheOptions = null)
{
// Add HTTP client with resilience preset
services.AddHttpClient(httpClientName)
.AddResilience(preset, customizeOptions);
// Add universal HTTP client with cache
return services.AddHttpClientWithCache(httpClientName, cacheOptions);
}
/// <summary>
/// Adds universal HTTP client with caching and resilience to the service collection
/// </summary>
/// <param name="services">Service collection</param>
/// <param name="httpClientName">HTTP client name</param>
/// <param name="configureResilience">Action to configure resilience options</param>
/// <param name="configureCacheOptions">Action to configure cache options</param>
/// <returns>Service collection for method chaining</returns>
public static IServiceCollection AddResilientHttpClientWithCache(
this IServiceCollection services,
string httpClientName,
Action<HttpCacheOptions> configureCacheOptions,
Action<HttpClientOptions>? configureResilience = null)
{
var cacheOptions = new HttpCacheOptions();
configureCacheOptions(cacheOptions);
services.Configure(httpClientName, configureCacheOptions);
return services.AddResilientHttpClientWithCache(httpClientName, configureResilience, cacheOptions);
}
/// <summary>
/// Adds universal HTTP client with caching using preset resilience configuration
/// </summary>
/// <param name="services">Service collection</param>
/// <param name="httpClientName">HTTP client name</param>
/// <param name="preset">Predefined resilience preset</param>
/// <param name="customizeOptions">Optional action to customize preset options</param>
/// <param name="configureCacheOptions">Action to configure cache options</param>
/// <returns>Service collection for method chaining</returns>
public static IServiceCollection AddResilientHttpClientWithCache(
this IServiceCollection services,
string httpClientName,
HttpClientOptions preset,
Action<HttpCacheOptions> configureCacheOptions,
Action<HttpClientOptions>? customizeOptions = null)
{
var cacheOptions = new HttpCacheOptions();
configureCacheOptions(cacheOptions);
services.Configure(httpClientName, configureCacheOptions);
return services.AddResilientHttpClientWithCache(httpClientName, preset, customizeOptions, cacheOptions);
}
/// <summary>
/// Creates an instance of <see cref="HttpClientWithCache"/> using the provided service provider and configuration.
/// </summary>
/// <param name="serviceProvider">The service provider used to resolve required dependencies.</param>
/// <param name="httpClientName">The name of the HTTP client to retrieve from the <see cref="IHttpClientFactory"/>.
/// <param name="cacheOptions">Cache options including default headers and settings (optional)</param>
/// If null or empty, a default client is created.</param>
/// <returns>A configured instance of <see cref="HttpClientWithCache"/>.</returns>
/// <exception cref="InvalidOperationException">Thrown if a required service (e.g., <see cref="IHttpClientFactory"/>, <see cref="IMemoryCache"/>,
/// <see cref="IHttpResponseHandler"/>, or <see cref="ISimpleCacheKeyGenerator"/>) is not registered in the service provider.</exception>
private static HttpClientWithCache CreateHttpClientWithCache(
IServiceProvider serviceProvider,
string? httpClientName,
HttpCacheOptions? cacheOptions)
{
IHttpClientFactory httpClientFactory = serviceProvider.GetRequiredService<IHttpClientFactory>();
System.Net.Http.HttpClient httpClient = httpClientName is null or ""
? httpClientFactory.CreateClient()
: httpClientFactory.CreateClient(httpClientName);
IMemoryCache cache = serviceProvider.GetRequiredService<IMemoryCache>();
IHttpResponseHandler responseHandler = serviceProvider.GetRequiredService<IHttpResponseHandler>();
HttpCacheOptions? cacheOptionsToInject = cacheOptions is null
? serviceProvider.GetService<IOptionsSnapshot<HttpCacheOptions>>()?.Get(httpClientName)
: cacheOptions;
IOptionsSnapshot<HttpCacheOptions>? cacheOptionsSnapshot = serviceProvider.GetService<IOptionsSnapshot<HttpCacheOptions>>();
ISimpleCacheKeyGenerator cacheKeyGenerator = serviceProvider.GetRequiredService<ISimpleCacheKeyGenerator>();
ILogger<HttpClientWithCache>? logger = serviceProvider.GetService<ILogger<HttpClientWithCache>>();
return new HttpClientWithCache(
httpClient,
cache,
responseHandler,
cacheOptionsToInject,
cacheKeyGenerator,
logger);
}
}