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

[API Proposal]: Add GetAsync to HybridCache #5688

Open
CoryCharlton opened this issue Nov 22, 2024 · 3 comments
Open

[API Proposal]: Add GetAsync to HybridCache #5688

CoryCharlton opened this issue Nov 22, 2024 · 3 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation untriaged

Comments

@CoryCharlton
Copy link

CoryCharlton commented Nov 22, 2024

Background and motivation

There are instances, such as session validation, where a consumer only wants to confirm that an item exists in the cache and not create it. This is not currently (directly) possible with the HybridCache implementation.

API Proposal

namespace Microsoft.Extensions.Caching.Hybrid;

public abstract class HybridCache
{
    public abstract ValueTask<T?> GetAsync<T>(string key, HybridCacheEntryOptions? options = null, CancellationToken cancellationToken = default);
}

API Usage

public async ValueTask<bool> ValidateSession(string sessionId, HybridCache cache) 
{
    var session = cache.GetAsync<Session>(sessionId);
    return (session is not null);
}

Alternative Designs

I can make this work using the existing API but I'm not a fan of my solution so if anyone has a better workaround let me know.

public async ValueTask<T?> GetAsync<T>(string key, HybridCacheEntryOptions? options = null, CancellationToken cancellationToken = default) where T : notnull
{
    try
    {
        return await GetOrCreateAsync<T>(key, _ => throw new CacheMissException(), options, null, cancellationToken);
    }
    catch (CacheMissException)
    {
        return default;
    }
}

More efficient option suggested by @nibdev

public static async Task<(bool Found, T? Result)> TryGetAsync<T>(this HybridCache cache, string key) where T : class
{
    var factoryCalled = false;
    var result = await cache.GetOrCreateAsync(
        key,
        _ =>
        {
            factoryCalled = true;
            return ValueTask.FromResult(default(T));
        },
        new HybridCacheEntryOptions
        {
            Expiration = TimeSpan.Zero,
            LocalCacheExpiration = TimeSpan.Zero,
            Flags = HybridCacheEntryFlags.DisableLocalCacheWrite | HybridCacheEntryFlags.DisableDistributedCacheWrite
        });

    return (!factoryCalled, result);
}

Risks

No response

@CoryCharlton CoryCharlton added api-suggestion Early API idea and discussion, it is NOT ready for implementation untriaged labels Nov 22, 2024
@ondrej-zoo
Copy link

I have another type of issue with not having a simple Get method. I would like to cache the access token so I don't need to obtain it every time I call some API. The problem is that I want to configure the absolute expiration of the cache entry based on the expiration of the token provided by the factory method.
The solution to my problem would be either

  • having Get method, or
  • having an overload of the GetOrCreate method accepting the delegate to create HybridCacheEntryOptions, something like this Func<CancellationToken, T, HybridCacheEntryOptions>

@nibdev
Copy link

nibdev commented Dec 11, 2024

I can make this work using the existing API but I'm not a fan of my solution so if anyone has a better workaround let me know.

I don't know if this is better for you but it probably is a bit less expensive as it does not use exceptions. And it could cache null and still would tell you if not found or null was cached

public static async Task<(bool Found, T? Result)> TryGetAsync<T>(this HybridCache cache, string key)
    where T : class
{
    var factoryCalled = false;
    var result = await cache.GetOrCreateAsync(
       key,
       _ =>
       {
           factoryCalled = true;
           return ValueTask.FromResult(default(T));
       },
       new HybridCacheEntryOptions
       {
           Expiration = TimeSpan.Zero,
           LocalCacheExpiration = TimeSpan.Zero,
           Flags = HybridCacheEntryFlags.DisableLocalCacheWrite | HybridCacheEntryFlags.DisableDistributedCacheWrite
       });

    return (!factoryCalled, result);
}

@CoryCharlton
Copy link
Author

CoryCharlton commented Dec 11, 2024

I don't know if this is better for you but it probably is a bit less expensive as it does not use exceptions. And it could cache null and still would tell you if not found or null was cached

Thanks for the suggestion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation untriaged
Projects
None yet
Development

No branches or pull requests

3 participants