Exemplo n.º 1
0
    /// <summary>
    ///   Execute statement with MemoryCache
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="uid">The uid.</param>
    /// <param name="userId">The user identifier.</param>
    /// <param name="cacheLifeKey">The cache life key.</param>
    /// <param name="customHeaders">The custom headers.</param>
    /// <param name="action">The action.</param>
    /// <returns></returns>
    /// <exception cref="InvalidOperationException">
    ///   This method requires a cache; use the correct constructor
    ///   or
    ///   Incorrect expiration time parameter
    /// </exception>
    protected async Task<T> WithMemoryCacheExecute<T>(string uid, string userId, object cacheLifeKey, IHeaderDictionary customHeaders, Func<Task<T>> action, string uniqueIdCacheKey = null) where T : class, IMasterDataModel
    {
      if (_dataCache == null)
        throw new InvalidOperationException("This method requires a cache; use the correct constructor");

      if (string.IsNullOrEmpty(uid) && string.IsNullOrEmpty(userId))
      {
        log.LogWarning("Attempting to execute method with cache, but cannot generate a cache key - not caching the result.");
        var noCacheResult = await action.Invoke();
        if (noCacheResult != null)
          return noCacheResult;
      }
      else
      {
        var opts = new MemoryCacheEntryOptions();

        switch (cacheLifeKey)
        {
          case string s:
            opts.GetCacheOptions(s, configurationStore, log);
            break;
          case TimeSpan t:
            opts.SlidingExpiration = t;
            break;
          default:
            throw new InvalidOperationException("Incorrect expiration time parameter");
        }

        var keyPrefix = typeof(T).Name;
        var cacheKey = string.IsNullOrEmpty(userId) ? $"{keyPrefix} {uid}" : $"{keyPrefix} {uid} {userId}";
        // Allow for extra cache keys, eg page 1 or 2 would need a separate key 
        if (!string.IsNullOrEmpty(uniqueIdCacheKey))
          cacheKey = $"{cacheKey} {uniqueIdCacheKey}";

        T result = default;

        using (await _memCacheLock.LockAsync(cacheKey))
        {
          if (!IfCacheNeedsToBeInvalidated(customHeaders))
          {
            return await _dataCache.GetOrCreate(cacheKey, async entry =>
            {
              log.LogDebug($"{nameof(WithMemoryCacheExecute)}: Item for key {cacheKey} not found in cache, getting from web api");
              result = await action.Invoke();
              if (result != null)
              {
                entry.SetOptions(opts);
                // We need to support clearing cache by the user - the model doesn't know about the user info
                var identifiers = result.GetIdentifiers() ?? new List<string>();
                if (!string.IsNullOrEmpty(uid))
                  identifiers.Add(uid);
                if (!string.IsNullOrEmpty(userId))
                  identifiers.Add(userId);
                return new CacheItem<T>(result, identifiers);
              }

              throw new ServiceException(HttpStatusCode.BadRequest,
                new ContractExecutionResult(ContractExecutionStatesEnum.FailedToGetResults,
                  "Unable to request data from a webapi"));
            });
          }

          log.LogDebug($"{nameof(WithMemoryCacheExecute)}: Item for key {cacheKey} is requested to be invalidated, getting from web api");
          result = await action.Invoke();
          if (result != null)
          {
            // We need to support clearing cache by the user - the model doesn't know about the user info
            var identifiers = result.GetIdentifiers() ?? new List<string>();
            if (!string.IsNullOrEmpty(uid))
              identifiers.Add(uid);
            if (!string.IsNullOrEmpty(userId))
              identifiers.Add(userId);
            return _dataCache.Set(cacheKey, result, identifiers, opts);
          }
        }
      }

      throw new ServiceException(HttpStatusCode.BadRequest,
          new ContractExecutionResult(ContractExecutionStatesEnum.FailedToGetResults,
            "Unable to request data from a webapi"));
    }