public async Task <InProductTrainingViewResponse> CreateInProductTrainingViewAsync(InProductTrainingViewRequest inProductTrainingViewRequest, Guid userId)
        {
            var validationResult = _validatorLocator.Validate <InProductTrainingViewRequestValidator>(inProductTrainingViewRequest);

            if (!validationResult.IsValid)
            {
                _logger.Error("Validation failed while attempting to create an InProductTrainingView resource.");
                throw new ValidationFailedException(validationResult.Errors);
            }

            var returnPayload    = new InProductTrainingViewResponse();
            var returnMessage    = "";
            var returnResultCode = ResultCode.Failed;

            var userApiResult = await _userApi.GetUserAsync(userId);

            string createdByUserName;

            if (userApiResult != null)
            {
                createdByUserName = !userApiResult.Payload.Username.IsNullOrEmpty() ? userApiResult.Payload.Username : userApiResult.Payload.Email;
            }
            else
            {
                createdByUserName = "******";
            }

            try
            {
                var key         = KeyResolver.InProductTrainingViews(userId, inProductTrainingViewRequest.ClientApplicationId);
                var dtoForTrace = _serializer.SerializeToString(inProductTrainingViewRequest);

                var cachedData = await _cache.SetMembersAsync <InProductTrainingViewResponse>(key);

                // ReSharper disable once UseNullPropagation
                if (cachedData != null)
                {
                    var trainingOfType = cachedData?.Where(t =>
                                                           t.InProductTrainingSubjectId == inProductTrainingViewRequest.InProductTrainingSubjectId &&
                                                           t.Title == inProductTrainingViewRequest.Title &&
                                                           t.UserId == userId)
                                         .FirstOrDefault();

                    if (trainingOfType != null)
                    {
                        returnPayload    = trainingOfType;
                        returnMessage    = CreateInProductTrainingViewReturnCode.RecordAlreadyExists.BuildResponseMessage(inProductTrainingViewRequest, userId);
                        returnResultCode = ResultCode.RecordAlreadyExists;

                        _logger.Info($"Record not created because it already exists in cache. {dtoForTrace}");
                    }
                }

                var populateCache = false;
                InProductTrainingViewResponse queryResult = null;
                if (returnResultCode != ResultCode.RecordAlreadyExists)
                {
                    var returnCode = CreateInProductTrainingViewReturnCode.CreateFailed;
                    queryResult = _dbService.CreateInProductTrainingView(
                        inProductTrainingViewRequest.InProductTrainingSubjectId, userId,
                        inProductTrainingViewRequest.Title, inProductTrainingViewRequest.UserTypeId, createdByUserName, ref returnCode);

                    returnPayload    = queryResult;
                    returnMessage    = returnCode.BuildResponseMessage(inProductTrainingViewRequest, userId);
                    returnResultCode = returnCode.ToResultCode();

                    if (returnCode == CreateInProductTrainingViewReturnCode.CreateSucceeded)
                    {
                        populateCache = true;
                        _logger.Info($"Created InProductTrainingView record. {dtoForTrace}");
                    }
                    else
                    {
                        if (returnCode == CreateInProductTrainingViewReturnCode.RecordAlreadyExists)
                        {
                            populateCache = true;
                            _logger.Info($"Record not created because it already exists in dB. {dtoForTrace}");
                        }
                        else if (returnCode == CreateInProductTrainingViewReturnCode.CreateFailed)
                        {
                            _logger.Error($"{returnMessage} {dtoForTrace}");
                        }
                        else
                        {
                            _logger.Warning($"{returnMessage} {dtoForTrace}");
                        }
                    }
                }

                if (populateCache && queryResult != null)
                {
                    var queryResultAsList = new List <InProductTrainingViewResponse> {
                        queryResult
                    };
                    if (await _cache.SetAddAsync(key, queryResultAsList) > 0 || await _cache.KeyExistsAsync(key))
                    {
                        _logger.Info($"Succesfully cached an item in the set for key '{key}' {dtoForTrace}");
                        if (!await _cache.KeyExpireAsync(key, _expirationTime, CacheCommandOptions.None))
                        {
                            _logger.Error($"Could not set cache expiration for the key '{key}' or the key does not exist. {dtoForTrace}");
                        }
                    }
                    else
                    {
                        _logger.Error($"Could not cache an item in the set for '{key}'. {dtoForTrace}");
                    }
                }
            }
            catch (Exception ex)
            {
                returnPayload.ResultCode    = ResultCode.Failed;
                returnPayload.ReturnMessage = ex.ToString();

                _logger.Error("Create InProductTrainingView failed due to an unknown exception", ex);
            }

            returnPayload.ReturnMessage = returnMessage;
            returnPayload.ResultCode    = returnResultCode;
            return(returnPayload);
        }
        public async Task <IEnumerable <InProductTrainingViewResponse> > GetViewedInProductTrainingAsync(int clientApplicationId, Guid userId)
        {
            var validationResult = _validatorLocator.Validate <ClientApplicationIdValidator>(clientApplicationId);

            if (!validationResult.IsValid)
            {
                _logger.Error("Validation failed while attempting to create an InProductTrainingView resource.");
                throw new ValidationFailedException(validationResult.Errors);
            }

            try
            {
                var key = KeyResolver.InProductTrainingViews(userId, clientApplicationId);

                if (await _cache.KeyExistsAsync(key))
                {
                    var cachedData = await _cache.SetMembersAsync <InProductTrainingViewResponse>(key);

                    if (cachedData != null)
                    {
                        _logger.Info($"{nameof(GetViewedInProductTrainingAsync)} - Item retrieved from cache for key {key}.");
                        return(cachedData.ToList());
                    }
                }

                var dbData = await _dbService.GetInProductTrainingViewsAsync(clientApplicationId, userId);

                if (dbData != null)
                {
                    if (dbData.Any())
                    {
                        _logger.Info($"{nameof(GetViewedInProductTrainingAsync)} - Records retrieved from dB for key {key}.");

                        if (await _cache.SetAddAsync(key, dbData) > 0 || await _cache.KeyExistsAsync(key))
                        {
                            _logger.Info($"{nameof(GetViewedInProductTrainingAsync)} - Succesfully cached an item in the set for key '{key}'.");

                            if (!await _cache.KeyExpireAsync(key, _expirationTime, CacheCommandOptions.None))
                            {
                                _logger.Info($"{nameof(GetViewedInProductTrainingAsync)} - Could not set cache expiration for the key '{key}' or the key does not exist.");
                            }
                        }
                        else
                        {
                            _logger.Error($"{nameof(GetViewedInProductTrainingAsync)} - Could not cache an item in the set for '{key}'.");
                        }
                    }
                }
                else
                {
                    var errorMessage =
                        $"{nameof(GetViewedInProductTrainingAsync)} - Unable to retrieve in-product training views from database. Args " +
                        $"[{nameof(userId)}: {userId}, {nameof(clientApplicationId)}: {clientApplicationId}]";

                    throw new Exception(errorMessage);
                }

                return(dbData);
            }
            catch (Exception ex)
            {
                var errorMessage =
                    $"{nameof(GetViewedInProductTrainingAsync)} - Unable to retrieve in-product training views from database. Args " +
                    $"[{nameof(userId)}: {userId}, {nameof(clientApplicationId)}: {clientApplicationId}]";

                throw new Exception(errorMessage, ex);
            }
        }