Sure.
The project is using net7.0 target framework
Couchbase.Extensions.Caching 3.3.5
Couchbase.Extensions.DependencyInjection 3.4.8
Couchbase Server Enterprise 7.1.0
Program.cs:
_ = builder.Services.AddSingleton<ICacheService, CacheService>();
_ = builder.Services.AddCouchbase(options =>
{
options.ConnectionString = servers;
options.UserName = username;
options.Password = password;
options.KvTimeout = TimeSpan.FromSeconds(10); // Set the KV (key-value) operation timeout to 10 seconds
options.ViewTimeout = TimeSpan.FromSeconds(20); // Set the view operation timeout to 20 seconds
options.QueryTimeout = TimeSpan.FromSeconds(30); // Set the N1QL query timeout to 30 seconds
});
_ = builder.Services.AddDistributedCouchbaseCache(cacheBucketName, opt => { });
CacheService:
private readonly IDistributedCache cache;
public CacheService(IDistributedCache cache)
{
this.cache = cache;
}
/// <inheritdoc />
public async Task<T?> GetCachedDataAsync<T>(string key)
{
try
{
var cachedData = await this.cache.GetStringAsync(key);
if (cachedData != null)
{
return JsonConvert.DeserializeObject<T>(cachedData) ?? default;
}
}
catch (Exception exception)
{
// Log exception
}
return default;
}
The stack is the following:
Controller calls ExternalApiService:
var cart = await this.cartService.GetCart(cartId);
ExternalApiService builds a request and calls an ApiHttpClient:
public async Task<Cart> GetCart(string cartId)
{
var request = new HttpRequest()
{
Url = this.httpClient.PrepareRequestUri(this.settings.BaseUrl, string.Format(this.settings.GetCartEndpoint, cartId)),
Method = HttpMethod.Get
};
var response = await this.httpClient.ExecuteAuthorizedRequest<CartObject>(request);
return response.cart;
}
ApiHttpClient needs to add an Authorization header, so it calls AuthorizationService to retrieve an access token:
public async Task<T> ExecuteAuthorizedRequest<T>(IHttpRequest request)
{
var accessToken = await this.authService.GetAccessTokenAsync(RefreshToken);
request.AddHeader("Authorization", accessToken);
var result = await SendRequestAsync<T>(request);
return result;
}
AuthorizationService tries to get access token from cache using CacheService, if not there, makes the actual request and saves the response to cache:
public async Task<string> GetAccessTokenAsync(string refreshToken)
{
var result = await this.cacheService.GetCachedDataAsync<string>(refreshToken);
if (result != null)
{
return result;
}
var authInfo = await RenewAccessTokenAsync(refreshToken);
await this.cacheService.SetCachedDataAsync(refreshToken, authInfo.AccessToken, 5);
return authInfo.AccessToken;
}
Exceptions thrown:
System.AggregateException: Cluster has not yet bootstrapped. Call WaitUntilReadyAsync(…) to wait for it to complete.\r\n at Couchbase.Extensions.DependencyInjection.Internal.BucketProvider.GetBucketFromClusterAsync(String bucketName, IClusterProvider clusterProvider)\r\n at Couchbase.Extensions.Caching.Internal.DefaultCouchbaseCacheCollectionProvider.GetCollectionAsync()\r\n at Couchbase.Extensions.Caching.CouchbaseCache.Microsoft.Extensions.Caching.Distributed.IDistributedCache.GetAsync(String key, CancellationToken token)\r\n at Microsoft.Extensions.Caching.Distributed.DistributedCacheExtensions.GetStringAsync(IDistributedCache cache, String key, CancellationToken token)
System.AggregateException: Cluster has not yet bootstrapped. Call WaitUntilReadyAsync(…) to wait for it to complete.\r\n at Couchbase.Extensions.DependencyInjection.Internal.BucketProvider.GetBucketFromClusterAsync(String bucketName, IClusterProvider clusterProvider)\r\n at Couchbase.Extensions.Caching.Internal.DefaultCouchbaseCacheCollectionProvider.GetCollectionAsync()\r\n at Couchbase.Extensions.Caching.CouchbaseCache.SetAsync(String key, Byte value, DistributedCacheEntryOptions options, CancellationToken token)