public override void Intercept(IInvocation invocation) { if (invocation.IsAction()) { invocation.Proceed(); return; } var(expectation, addOrUpdateCache, getFromCache) = Expectations.FirstOrDefault(x => x.expectation.IsHit(invocation)); var cacheKey = JsonConvert.SerializeObject(invocation.Arguments); if (expectation != null) { if (CachedInvocations.TryGetValue(expectation.Identifier, out var cachedInvocation)) { if (cachedInvocation.TryGetValue(cacheKey, out var cachedValue)) { if (expectation.IsExpired(cachedValue.invocationResult, cachedValue.invocationDateTime)) { invocation.Proceed(); addOrUpdateCache .Invoke ( invocation.ReturnValue, cachedInvocation, cacheKey ); } else { invocation.ReturnValue = getFromCache.Invoke(cachedValue.invocationResult); } } else { invocation.Proceed(); addOrUpdateCache .Invoke ( invocation.ReturnValue, cachedInvocation, cacheKey ); } } else { invocation.Proceed(); var cache = new ConcurrentDictionary <string, (object invocationResult, DateTime invocationDateTime)>(); addOrUpdateCache .Invoke ( invocation.ReturnValue, cache, cacheKey ); CachedInvocations .TryAdd ( expectation.Identifier, cache ); } } else { var returnType = invocation.Method.ReturnType; expectation = Expectation.FromInvocation(invocation, _expirationDelegate); addOrUpdateCache = BuildAddOrUpdateDelegateForType(returnType); getFromCache = BuildGetFromCacheDelegateForType(returnType); Expectations .Add ( ( expectation, addOrUpdateCache, getFromCache ) ); var cache = new ConcurrentDictionary <string, (object invocationResult, DateTime invocationDateTime)>(); CachedInvocations.TryAdd(expectation.Identifier, cache); invocation.Proceed(); addOrUpdateCache .Invoke ( invocation.ReturnValue, cache, cacheKey ); } }