Suppose a scenario where:

  • you need to execute an expensive operation which can fail or succeed.

  • the result of the operation is modeled by using a result object Result<T>. The result object contains a boolean property which says if the operation succeeded and a property containing the operation result. Here you can find an example of such an implementation.

  • you want to use Hybrid Cache to cache the result of the expensive operation by having all the good things provided by Hybrid Cache (e.g.: cache stampede protection).

  • you want to cache the operation result only if the operation succeeded. If the operation failed, you want to skip caching the operation result, so that the next time you can retry the operation.

Is there a simple and elegant way to do so by using the GetOrCreateAsync method provided by Hybrid Cache ? It seems to me that these requirements are not simple to match with the semantic of GetOrCreateAsync

A possible solution is using an exception to signal Hybrid Cache not to cache the result of a failed operation, as it is done here. Is there any other solution to this problem ?

It seems there is an api proposal on GitHub which goes in a similar direction.

1 Reply 1

As is typical for Microsoft documentation, it doesn't say what happens in case of failure.

It seems fairly safe, however, to assume that GetOrCreateAsync does not cache the result if an exception is thrown. After all, how could it? It needs to cache an object of the type T, and an exception is typically not of type T.

In that case, then, what prevents you from throwing an exception as in the link? You don't have to do it on a case-by-case basis. You could add a general-purpose helper function to your code base, like

public static T EnsureSuccess(this Result<T> result)
{
    // Check if result is success, and then:
    if (success)
    {
        // Return the T value associated with the success case
    }
    else
        throw new InvalidOperationException("boo!"); // or some other exception type
}

I've been deliberately vague about the Result<T> API, since there are so many variations out there...

This should enable you to use GetOrCreateAsync like this:

public async Task<string> GetSomeInfoAsync(
    string name,
    int id,
    CancellationToken token = default)
{
    return await _cache.GetOrCreateAsync(
        $"{name}-{id}", // Unique key to the cache entry
        async cancel =>
        {
            var result = await GetDataFromTheSourceAsync(name, id, cancel);
            return result.EnsureSuccess();
        },
        cancellationToken: token)
    );
}

If you wish to be able to write this as a one-liner, you'll need to define a functor for task values, so that you can use EnsureSuccess to map the result, but that's an independent issue not related to HybridCache, but rather to how asynchronous code composes in C# (which is: Not that well). Even so, it could look like GetDataFromTheSourceAsync(name, id, cancel).Select(EnsureSuccess).

Your Reply

By clicking “Post Your Reply”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.