public async Task <CommandResult <TResult> > DispatchAsync <TResult>(ICommand <TResult> command, CancellationToken cancellationToken) { CacheOptions options = _cacheOptionsProvider.Get(command); if (options == null) { return(await _commandDispatcher.DispatchAsync(command, cancellationToken)); } var cacheKey = CacheKey(command); TResult result = await _cacheAdapter.Get <TResult>(cacheKey); if (result != null) { return(new CommandResult <TResult>(result, false)); } CommandResult <TResult> executedResult; if (options.Semaphore != null) { await options.Semaphore.WaitAsync(cancellationToken); try { result = await _cacheAdapter.Get <TResult>(cacheKey); if (result != null) { return(new CommandResult <TResult>(result, false)); } else { executedResult = await _commandDispatcher.DispatchAsync(command, cancellationToken); } } finally { options.Semaphore.Release(); } } else { executedResult = await _commandDispatcher.DispatchAsync(command, cancellationToken); } if (options.LifeTime != null) { await _cacheAdapter.Set(cacheKey, executedResult.Result, options.LifeTime()); } else if (options.ExpiresAtUtc != null) { await _cacheAdapter.Set(cacheKey, executedResult.Result, options.ExpiresAtUtc()); } else { // shouldn't happen but lets make sure we spit out a sensible error if it does throw new CacheConfigurationException("Either a lifetime or expiry date must be set for a cached command"); } return(executedResult); }