Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public HttpCacheOptionsBuilder AddHeader(string name, string value)
{
throw new ArgumentException($"'{nameof(name)}' cannot be null or whitespace.", nameof(name));
}

ArgumentNullException.ThrowIfNull(value);

_options.DefaultHeaders[name] = value;
Expand All @@ -84,6 +85,7 @@ public HttpCacheOptionsBuilder AddHeaders(IDictionary<string, string> headers)
{
_options.DefaultHeaders[header.Key] = header.Value;
}

return this;
}

Expand Down
213 changes: 165 additions & 48 deletions src/Reliable.HttpClient.Caching/HttpClientWithCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,130 @@ public async Task<TResponse> PostAsync<TRequest, TResponse>(
return await PostAsync<TRequest, TResponse>(requestUri.ToString(), content, headers, cancellationToken).ConfigureAwait(false);
}

public async Task<HttpResponseMessage> PostAsync<TRequest>(
string requestUri,
TRequest content,
CancellationToken cancellationToken = default)
{
HttpResponseMessage response = await _httpClient.PostAsJsonAsync(requestUri, content, cancellationToken).ConfigureAwait(false);

// Invalidate cache only after successful HTTP request (before response handler to maintain adapter contract)
await InvalidateRelatedCacheAsync(requestUri).ConfigureAwait(false);

return response;
}

public async Task<HttpResponseMessage> PostAsync<TRequest>(
string requestUri,
TRequest content,
IDictionary<string, string> headers,
CancellationToken cancellationToken = default)
{
Dictionary<string, string> allHeaders = MergeHeaders(_cacheOptions.DefaultHeaders, headers);
using HttpRequestMessage request = CreateRequestWithHeaders(HttpMethod.Post, requestUri, allHeaders);
request.Content = JsonContent.Create(content);

HttpResponseMessage response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);

// Invalidate cache only after successful HTTP request (before response handler to maintain adapter contract)
await InvalidateRelatedCacheAsync(requestUri).ConfigureAwait(false);

return response;
}

/// <inheritdoc />
public async Task<TResponse> PatchAsync<TRequest, TResponse>(
string requestUri,
TRequest content,
CancellationToken cancellationToken = default) where TResponse : class
{
using HttpRequestMessage request = CreateRequestWithHeaders(HttpMethod.Patch, requestUri, _cacheOptions.DefaultHeaders);
request.Content = JsonContent.Create(content);

HttpResponseMessage response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
TResponse result = await _responseHandler.HandleAsync<TResponse>(response, cancellationToken).ConfigureAwait(false);

// Invalidate cache only after successful HTTP request (before response handler to maintain adapter contract)
await InvalidateRelatedCacheAsync(requestUri).ConfigureAwait(false);

return result;
}

/// <inheritdoc />
public async Task<TResponse> PatchAsync<TRequest, TResponse>(
Uri requestUri,
TRequest content,
CancellationToken cancellationToken = default) where TResponse : class
{
return await PatchAsync<TRequest, TResponse>(requestUri.ToString(), content, cancellationToken).ConfigureAwait(false);
}

/// <inheritdoc />
public async Task<TResponse> PatchAsync<TRequest, TResponse>(
string requestUri,
TRequest content,
IDictionary<string, string> headers,
CancellationToken cancellationToken = default) where TResponse : class
{
Dictionary<string, string> allHeaders = MergeHeaders(_cacheOptions.DefaultHeaders, headers);
using HttpRequestMessage request = CreateRequestWithHeaders(HttpMethod.Patch, requestUri, allHeaders);
request.Content = JsonContent.Create(content);

HttpResponseMessage response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
TResponse result = await _responseHandler.HandleAsync<TResponse>(response, cancellationToken).ConfigureAwait(false);

// Invalidate cache only after successful HTTP request (before response handler to maintain adapter contract)
await InvalidateRelatedCacheAsync(requestUri).ConfigureAwait(false);

return result;
}

/// <inheritdoc />
public async Task<TResponse> PatchAsync<TRequest, TResponse>(
Uri requestUri,
TRequest content,
IDictionary<string, string> headers,
CancellationToken cancellationToken = default) where TResponse : class
{
return await PatchAsync<TRequest, TResponse>(requestUri.ToString(), content, headers, cancellationToken).ConfigureAwait(false);
}

/// <inheritdoc />
public async Task<HttpResponseMessage> PatchAsync<TRequest>(
string requestUri,
TRequest content,
CancellationToken cancellationToken = default)
{
using HttpRequestMessage request = CreateRequestWithHeaders(HttpMethod.Patch, requestUri, _cacheOptions.DefaultHeaders);
request.Content = JsonContent.Create(content);

HttpResponseMessage response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);

// Invalidate cache only after successful HTTP request (before response handler to maintain adapter contract)
await InvalidateRelatedCacheAsync(requestUri).ConfigureAwait(false);

return response;
}

/// <inheritdoc />
public async Task<HttpResponseMessage> PatchAsync<TRequest>(
string requestUri,
TRequest content,
IDictionary<string, string> headers,
CancellationToken cancellationToken = default)
{
Dictionary<string, string> allHeaders = MergeHeaders(_cacheOptions.DefaultHeaders, headers);
using HttpRequestMessage request = CreateRequestWithHeaders(HttpMethod.Patch, requestUri, allHeaders);
request.Content = JsonContent.Create(content);

HttpResponseMessage response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);

// Invalidate cache only after successful HTTP request (before response handler to maintain adapter contract)
await InvalidateRelatedCacheAsync(requestUri).ConfigureAwait(false);

return response;
}

/// <inheritdoc />
public async Task<TResponse> PutAsync<TRequest, TResponse>(
string requestUri,
Expand Down Expand Up @@ -231,6 +355,34 @@ public async Task<TResponse> DeleteAsync<TResponse>(
return result;
}

public async Task<HttpResponseMessage> DeleteAsync(
string requestUri,
CancellationToken cancellationToken = default)
{
HttpResponseMessage response = await _httpClient.DeleteAsync(requestUri, cancellationToken).ConfigureAwait(false);

// Invalidate cache only after successful HTTP request (before response handler to maintain adapter contract)
await InvalidateRelatedCacheAsync(requestUri).ConfigureAwait(false);

return response;
}

public async Task<HttpResponseMessage> DeleteAsync(
string requestUri,
IDictionary<string, string> headers,
CancellationToken cancellationToken = default)
{
Dictionary<string, string> allHeaders = MergeHeaders(_cacheOptions.DefaultHeaders, headers);
using HttpRequestMessage request = CreateRequestWithHeaders(HttpMethod.Delete, requestUri, allHeaders);

HttpResponseMessage response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);

// Invalidate cache only after successful HTTP request (before response handler to maintain adapter contract)
await InvalidateRelatedCacheAsync(requestUri).ConfigureAwait(false);

return response;
}

/// <inheritdoc />
public Task InvalidateCacheAsync(string pattern)
{
Expand Down Expand Up @@ -339,31 +491,13 @@ Task<TResponse> IHttpClientAdapter.GetAsync<TResponse>(
Uri requestUri, IDictionary<string, string> headers, CancellationToken cancellationToken) =>
GetAsync<TResponse>(requestUri, headers, cacheDuration: null, cancellationToken);

async Task<HttpResponseMessage> IHttpClientAdapter.PostAsync<TRequest>(
string requestUri, TRequest content, CancellationToken cancellationToken)
{
HttpResponseMessage response = await _httpClient.PostAsJsonAsync(requestUri, content, cancellationToken).ConfigureAwait(false);

// Invalidate cache only after successful HTTP request (before response handler to maintain adapter contract)
await InvalidateRelatedCacheAsync(requestUri).ConfigureAwait(false);

return response;
}

async Task<HttpResponseMessage> IHttpClientAdapter.PostAsync<TRequest>(
string requestUri, TRequest content, IDictionary<string, string> headers, CancellationToken cancellationToken)
{
Dictionary<string, string> allHeaders = MergeHeaders(_cacheOptions.DefaultHeaders, headers);
using HttpRequestMessage request = CreateRequestWithHeaders(HttpMethod.Post, requestUri, allHeaders);
request.Content = JsonContent.Create(content);

HttpResponseMessage response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);

// Invalidate cache only after successful HTTP request (before response handler to maintain adapter contract)
await InvalidateRelatedCacheAsync(requestUri).ConfigureAwait(false);
Task<HttpResponseMessage> IHttpClientAdapter.PostAsync<TRequest>(
string requestUri, TRequest content, CancellationToken cancellationToken) =>
PostAsync(requestUri, content, cancellationToken);

return response;
}
Task<HttpResponseMessage> IHttpClientAdapter.PostAsync<TRequest>(
string requestUri, TRequest content, IDictionary<string, string> headers, CancellationToken cancellationToken) =>
PostAsync(requestUri, content, headers, cancellationToken);

Task<TResponse> IHttpClientAdapter.PostAsync<TRequest, TResponse>(
string requestUri, TRequest content, CancellationToken cancellationToken) =>
Expand All @@ -381,35 +515,18 @@ Task<TResponse> IHttpClientAdapter.PutAsync<TRequest, TResponse>(
string requestUri, TRequest content, IDictionary<string, string> headers, CancellationToken cancellationToken) =>
PutAsync<TRequest, TResponse>(requestUri, content, headers, cancellationToken);

async Task<HttpResponseMessage> IHttpClientAdapter.DeleteAsync(string requestUri, CancellationToken cancellationToken)
{
HttpResponseMessage response = await _httpClient.DeleteAsync(requestUri, cancellationToken).ConfigureAwait(false);

// Invalidate cache only after successful HTTP request (before response handler to maintain adapter contract)
await InvalidateRelatedCacheAsync(requestUri).ConfigureAwait(false);

return response;
}

async Task<HttpResponseMessage> IHttpClientAdapter.DeleteAsync(
string requestUri, IDictionary<string, string> headers, CancellationToken cancellationToken)
{
Dictionary<string, string> allHeaders = MergeHeaders(_cacheOptions.DefaultHeaders, headers);
using HttpRequestMessage request = CreateRequestWithHeaders(HttpMethod.Delete, requestUri, allHeaders);

HttpResponseMessage response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);

// Invalidate cache only after successful HTTP request (before response handler to maintain adapter contract)
await InvalidateRelatedCacheAsync(requestUri).ConfigureAwait(false);

return response;
}

Task<TResponse> IHttpClientAdapter.DeleteAsync<TResponse>(
string requestUri, CancellationToken cancellationToken) =>
DeleteAsync<TResponse>(requestUri, cancellationToken);

Task<TResponse> IHttpClientAdapter.DeleteAsync<TResponse>(
string requestUri, IDictionary<string, string> headers, CancellationToken cancellationToken) =>
DeleteAsync<TResponse>(requestUri, headers, cancellationToken);

Task<HttpResponseMessage> IHttpClientAdapter.DeleteAsync(string requestUri, CancellationToken cancellationToken) =>
DeleteAsync(requestUri, cancellationToken);

Task<HttpResponseMessage> IHttpClientAdapter.DeleteAsync(
string requestUri, IDictionary<string, string> headers, CancellationToken cancellationToken) =>
DeleteAsync(requestUri, headers, cancellationToken);
}
Loading