Skip to content

Instantly share code, notes, and snippets.

@bbilginn
Created July 23, 2020 06:06
Show Gist options
  • Save bbilginn/e41708d17998f69d204847e59f546a19 to your computer and use it in GitHub Desktop.
Save bbilginn/e41708d17998f69d204847e59f546a19 to your computer and use it in GitHub Desktop.
HttpClient ETag based client cache handler.
class HttpETagCacheHandler : HttpClientHandler
{
private static readonly ConcurrentDictionary<string, string> ETags = new ConcurrentDictionary<string, string>();
private static readonly ConcurrentDictionary<string, byte[]> MemoryCache = new ConcurrentDictionary<string, byte[]>();
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var pathAndQuery = request.RequestUri.PathAndQuery;
if (ETags.TryGetValue(pathAndQuery, out var ifNonMatch))
{
request.Headers.Add("If-None-Match", ifNonMatch);
}
var response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(ifNonMatch))
{
MemoryCache.TryRemove(ifNonMatch, out _);
ETags.TryRemove(pathAndQuery, out _);
}
var responseETag = response.Headers?.ETag?.Tag;
if (response.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(responseETag) && !ETags.ContainsKey(responseETag) && response.Content != null)
{
ETags.TryAdd(pathAndQuery, responseETag);
var bytes = await response.Content.ReadAsByteArrayAsync();
MemoryCache.TryAdd(responseETag, bytes);
}
if (response.StatusCode == HttpStatusCode.NotModified && !string.IsNullOrEmpty(responseETag) && MemoryCache.TryGetValue(responseETag, out var data))
{
response.Content = new ByteArrayContent(data);
response.StatusCode = HttpStatusCode.OK;
}
return response;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment