Esempio n. 1
0
        /// <summary>
        /// Gets the variation name assigned for the user for the campaign
        /// </summary>
        /// <param name="campaignKey">Campaign key to uniquely identify a server-side campaign.</param>
        /// <param name="userId">User ID which uniquely identifies each user.</param>
        /// <param name="options">Dictionary for passing extra parameters to activate</param>
        /// <returns>
        /// If variation is assigned then variation name, or Null in case of user not becoming part
        /// </returns>
        public string GetVariation(string campaignKey, string userId, Dictionary <string, dynamic> options = null)
        {
            if (options == null)
            {
                options = new Dictionary <string, dynamic>();
            }
            Dictionary <string, dynamic> customVariables             = options.ContainsKey("customVariables") ? options["customVariables"] : null;
            Dictionary <string, dynamic> variationTargetingVariables = options.ContainsKey("variationTargetingVariables") ? options["variationTargetingVariables"] : null;

            if (this._validator.GetVariation(campaignKey, userId, options))
            {
                var campaign = this._campaignAllocator.GetCampaign(this._settings, campaignKey);
                if (campaign == null || campaign.Status != Constants.CampaignStatus.RUNNING)
                {
                    LogErrorMessage.CampaignNotRunning(typeof(IVWOClient).FullName, campaignKey, nameof(GetVariation));
                    return(null);
                }

                if (campaign.Type == Constants.CampaignTypes.FEATURE_ROLLOUT)
                {
                    LogErrorMessage.InvalidApi(typeof(IVWOClient).FullName, userId, campaignKey, campaign.Type, nameof(GetVariation));
                    return(null);
                }

                var assignedVariation = this.AllocateVariation(campaignKey, userId, campaign, customVariables, variationTargetingVariables, apiName: nameof(GetVariation));
                if (assignedVariation.Variation != null)
                {
                    return(assignedVariation.Variation.Name);
                }
                return(assignedVariation.Variation?.Name);
            }
            return(null);
        }
Esempio n. 2
0
        /// <summary>
        /// Activates a server-side A/B test for a specified user for a server-side running campaign.
        /// </summary>
        /// <param name="campaignKey">Campaign key to uniquely identify a server-side campaign.</param>
        /// <param name="userId">User ID which uniquely identifies each user.</param>
        /// <param name="options">Dictionary for passing extra parameters to activate</param>
        /// <returns>
        /// The name of the variation in which the user is bucketed, or null if the user doesn't qualify to become a part of the campaign.
        /// </returns>
        public string Activate(string campaignKey, string userId, Dictionary <string, dynamic> options = null)
        {
            if (options == null)
            {
                options = new Dictionary <string, dynamic>();
            }
            Dictionary <string, dynamic> customVariables             = options.ContainsKey("customVariables") ? options["customVariables"] : null;
            Dictionary <string, dynamic> variationTargetingVariables = options.ContainsKey("variationTargetingVariables") ? options["variationTargetingVariables"] : null;

            if (this._validator.Activate(campaignKey, userId, options))
            {
                var campaign = this._campaignAllocator.GetCampaign(this._settings, campaignKey);
                if (campaign == null || campaign.Status != Constants.CampaignStatus.RUNNING)
                {
                    LogErrorMessage.CampaignNotRunning(typeof(IVWOClient).FullName, campaignKey, nameof(Activate));
                    return(null);
                }
                if (campaign.Type != Constants.CampaignTypes.VISUAL_AB)
                {
                    LogErrorMessage.InvalidApi(typeof(IVWOClient).FullName, userId, campaignKey, campaign.Type, nameof(Activate));
                    return(null);
                }
                var assignedVariation = this.AllocateVariation(campaignKey, userId, campaign, customVariables, variationTargetingVariables, apiName: nameof(Activate));
                if (assignedVariation.Variation != null)
                {
                    var trackUserRequest = ServerSideVerb.TrackUser(this._settings.AccountId, assignedVariation.Campaign.Id, assignedVariation.Variation.Id, userId, this._isDevelopmentMode);
                    trackUserRequest.ExecuteAsync();
                    return(assignedVariation.Variation.Name);
                }
            }
            return(null);
        }
Esempio n. 3
0
        public async Task <byte[]> ExecuteAsync(ApiRequest apiRequest)
        {
            if (apiRequest == null)
            {
                return(null);
            }
            HttpRequestMessage  httpRequestMessage  = new HttpRequestMessage(apiRequest.Method.GetHttpMethod(), apiRequest.Uri.ToString());
            HttpResponseMessage httpResponseMessage = null;

            try
            {
                httpResponseMessage = await _httpClient.SendAsync(httpRequestMessage);

                if (httpResponseMessage.IsSuccessStatusCode)
                {
                    var response = await httpResponseMessage.Content.ReadAsByteArrayAsync();

                    LogInfoMessage.ImpressionSuccess(file, apiRequest.Uri.ToString());
                    return(response);
                }
                LogErrorMessage.ImpressionFailed(file, apiRequest.Uri?.ToString());
            }
            catch (Exception exception)
            {
                LogErrorMessage.ImpressionFailed(file, apiRequest.Uri?.ToString());
            }
            finally
            {
            }
            return(null);
        }
Esempio n. 4
0
 public dynamic getTypeCastedFeatureValue(dynamic value, string variableType)
 {
     try
     {
         if (value.GetType().Name == Constants.DotnetVariableTypes.VALUES[variableType])
         {
             return(value);
         }
         if (variableType == Constants.VariableTypes.STRING)
         {
             return(Convert.ToString(value));
         }
         if (variableType == Constants.VariableTypes.INTEGER)
         {
             return(Convert.ToInt32(value));
         }
         if (variableType == Constants.VariableTypes.DOUBLE)
         {
             return(Convert.ToDouble(value));
         }
         if (variableType == Constants.VariableTypes.BOOLEAN)
         {
             return(Convert.ToBoolean(value));
         }
         return(value);
     }
     catch
     {
         LogErrorMessage.UnableToTypeCast(typeof(IVWOClient).FullName, value, variableType, value.GetType().Name);
         return(null);
     }
 }
Esempio n. 5
0
        /// <summary>
        /// Tracks a conversion event for a particular user for a running server-side campaign.
        /// </summary>
        /// <param name="userId">User ID which uniquely identifies each user.</param>
        /// <param name="goalIdentifier">The Goal key to uniquely identify a goal of a server-side campaign.</param>
        /// <param name="options">Dictionary for passing extra parameters to activate</param>
        /// <returns>
        /// A boolean value based on whether the impression was made to the VWO server.
        /// True, if an impression event is successfully being made to the VWO server for report generation.
        /// False, If userId provided is not part of campaign or when unexpected error comes and no impression call is made to the VWO server.
        /// </returns>
        public Dictionary <string, bool> Track(string userId, string goalIdentifier, Dictionary <string, dynamic> options = null)
        {
            if (options == null)
            {
                options = new Dictionary <string, dynamic>();
            }
            string goalTypeToTrack          = options.ContainsKey("goalTypeToTrack") ? options["goalTypeToTrack"] : null;
            bool   shouldTrackReturningUser = options.ContainsKey("shouldTrackReturningUser") ? options["shouldTrackReturningUser"] : this._shouldTrackReturningUser;

            goalTypeToTrack = !string.IsNullOrEmpty(goalTypeToTrack) ? goalTypeToTrack : this._goalTypeToTrack != null ? this._goalTypeToTrack : Constants.GoalTypes.ALL;

            Dictionary <string, bool> result = new Dictionary <string, bool>();
            bool campaignFound = false;

            foreach (BucketedCampaign campaign in this._settings.Campaigns)
            {
                foreach (KeyValuePair <string, Goal> goal in campaign.Goals)
                {
                    if (goal.Key != null && goalIdentifier == goal.Value.Identifier && (goalTypeToTrack == Constants.GoalTypes.ALL || goalTypeToTrack == goal.Value.Type))
                    {
                        campaignFound        = true;
                        result[campaign.Key] = this.Track(campaign.Key, userId, goalIdentifier, options);
                    }
                }
            }
            if (!campaignFound)
            {
                LogErrorMessage.NoCampaignForGoalFound(file, goalIdentifier);
                return(null);
            }
            return(result);
        }
Esempio n. 6
0
        /// <summary>
        /// Returns the feature variable corresponding to the variableKey passed. It typecasts the value to the corresponding value type found in settings_file
        /// </summary>
        /// <param name="campaignKey">Campaign key to uniquely identify a server-side campaign.</param>
        /// <param name="variableKey">Campaign key to uniquely identify a server-side campaign.</param>
        /// <param name="userId">User ID which uniquely identifies each user.</param>
        /// <param name="options">Dictionary for passing extra parameters to activate</param>
        /// <returns>
        /// The name of the variation in which the user is bucketed, or null if the user doesn't qualify to become a part of the campaign.
        /// </returns>
        public dynamic GetFeatureVariableValue(string campaignKey, string variableKey, string userId, Dictionary <string, dynamic> options = null)
        {
            if (options == null)
            {
                options = new Dictionary <string, dynamic>();
            }
            Dictionary <string, dynamic> customVariables             = options.ContainsKey("customVariables") ? options["customVariables"] : null;
            Dictionary <string, dynamic> variationTargetingVariables = options.ContainsKey("variationTargetingVariables") ? options["variationTargetingVariables"] : null;
            var variables = new List <Dictionary <string, dynamic> >();
            var variable  = new Dictionary <string, dynamic>();

            if (this._validator.GetFeatureVariableValue(campaignKey, variableKey, userId, options))
            {
                var campaign = this._campaignAllocator.GetCampaign(this._settings, campaignKey);
                if (campaign == null || campaign.Status != Constants.CampaignStatus.RUNNING)
                {
                    LogErrorMessage.CampaignNotRunning(typeof(IVWOClient).FullName, campaignKey, nameof(GetFeatureVariableValue));
                    return(null);
                }

                if (campaign.Type == Constants.CampaignTypes.VISUAL_AB)
                {
                    LogErrorMessage.InvalidApi(typeof(IVWOClient).FullName, userId, campaignKey, campaign.Type, nameof(GetFeatureVariableValue));
                    return(null);
                }

                var assignedVariation = this.AllocateVariation(campaignKey, userId, campaign, customVariables, variationTargetingVariables, apiName: nameof(GetFeatureVariableValue));
                if (campaign.Type == Constants.CampaignTypes.FEATURE_ROLLOUT)
                {
                    variables = campaign.Variables;
                }
                else if (campaign.Type == Constants.CampaignTypes.FEATURE_TEST)
                {
                    if (!assignedVariation.Variation.IsFeatureEnabled)
                    {
                        LogInfoMessage.FeatureNotEnabledForUser(typeof(IVWOClient).FullName, campaignKey, userId, nameof(GetFeatureVariableValue));
                        assignedVariation = this.GetControlVariation(campaign, campaign.Variations.Find(1, (new VariationAllocator()).GetVariationId));
                    }
                    else
                    {
                        LogInfoMessage.FeatureEnabledForUser(typeof(IVWOClient).FullName, campaignKey, userId, nameof(GetFeatureVariableValue));
                    }
                    variables = assignedVariation.Variation.Variables;
                }

                variable = this.GetVariable(variables, variableKey);
                if (variable == null || variable.Count == 0)
                {
                    LogErrorMessage.VariableNotFound(typeof(IVWOClient).FullName, variableKey, campaignKey, campaign.Type, userId, nameof(GetFeatureVariableValue));
                    return(null);
                }
                else
                {
                    LogInfoMessage.VariableFound(typeof(IVWOClient).FullName, variableKey, campaignKey, campaign.Type, variable["value"].ToString(), userId, nameof(GetFeatureVariableValue));
                }
                return(this._segmentEvaluator.getTypeCastedFeatureValue(variable["value"], variable["type"]));
            }
            return(null);
        }
Esempio n. 7
0
        private static bool ValidateWithLog(Func <bool> validationFunc, string parameterName, string apiName)
        {
            bool validationResult = validationFunc.Invoke();

            if (validationResult == false)
            {
                LogErrorMessage.ApiMissingParams(file, apiName, parameterName);
            }
            return(validationResult);
        }
 public AccountSettings ProcessAndBucket(Settings settings)
 {
     try
     {
         var campaigns = Process(settings.Campaigns);
         return(new AccountSettings(settings.SdkKey, campaigns, settings.AccountId, settings.Version));
     }
     catch (Exception exception)
     {
     }
     LogErrorMessage.ProjectConfigCorrupted(file);
     return(null);
 }
Esempio n. 9
0
        /// <summary>
        /// Identifies whether the user becomes a part of feature rollout/test or not.
        /// </summary>
        /// <param name="campaignKey">Campaign key to uniquely identify a server-side campaign.</param>
        /// <param name="userId">User ID which uniquely identifies each user.</param>
        /// <param name="options">Dictionary for passing extra parameters to activate</param>
        /// <returns>
        /// /// A boolean value based on whether the impression was made to the VWO server.
        /// True, if an impression event is successfully being made to the VWO server for report generation.
        /// False, If userId provided is not part of campaign or when unexpected error comes and no impression call is made to the VWO server.
        /// </returns>
        public bool IsFeatureEnabled(string campaignKey, string userId, Dictionary <string, dynamic> options = null)
        {
            if (options == null)
            {
                options = new Dictionary <string, dynamic>();
            }
            Dictionary <string, dynamic> customVariables             = options.ContainsKey("customVariables") ? options["customVariables"] : null;
            Dictionary <string, dynamic> variationTargetingVariables = options.ContainsKey("variationTargetingVariables") ? options["variationTargetingVariables"] : null;

            if (this._validator.IsFeatureEnabled(campaignKey, userId, options))
            {
                var campaign = this._campaignAllocator.GetCampaign(this._settings, campaignKey);
                if (campaign == null || campaign.Status != Constants.CampaignStatus.RUNNING)
                {
                    LogErrorMessage.CampaignNotRunning(typeof(IVWOClient).FullName, campaignKey, nameof(IsFeatureEnabled));
                    return(false);
                }
                if (campaign.Type == Constants.CampaignTypes.VISUAL_AB)
                {
                    LogErrorMessage.InvalidApi(typeof(IVWOClient).FullName, userId, campaignKey, campaign.Type, nameof(IsFeatureEnabled));
                    return(false);
                }

                var assignedVariation = this.AllocateVariation(campaignKey, userId, campaign, customVariables, variationTargetingVariables, apiName: nameof(IsFeatureEnabled));
                if (campaign.Type == Constants.CampaignTypes.FEATURE_TEST)
                {
                    if (assignedVariation.Variation != null)
                    {
                        var trackUserRequest = ServerSideVerb.TrackUser(this._settings.AccountId, assignedVariation.Campaign.Id, assignedVariation.Variation.Id, userId, this._isDevelopmentMode);
                        trackUserRequest.ExecuteAsync();
                        var result = assignedVariation.Variation.IsFeatureEnabled;

                        if (result)
                        {
                            LogInfoMessage.FeatureEnabledForUser(typeof(IVWOClient).FullName, campaignKey, userId, nameof(IsFeatureEnabled));
                        }
                        else
                        {
                            LogInfoMessage.FeatureNotEnabledForUser(typeof(IVWOClient).FullName, campaignKey, userId, nameof(IsFeatureEnabled));
                        }
                        return(result);
                    }
                    return(false);
                }
                return(true);
            }
            else
            {
                return(false);
            }
        }
Esempio n. 10
0
        /// <summary>
        /// Calls Get within try to suppress any Exception from outside of SDK application.
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        private UserStorageMap TryGetUserMap(string userId, string campaignKey)
        {
            try
            {
                LogInfoMessage.LookingUpUserStorageService(file, userId, campaignKey);
                return(this._userStorageService.Get(userId, campaignKey));
            }
            catch (Exception ex)
            {
                LogErrorMessage.GetUserStorageServiceFailed(file, userId, campaignKey);
            }

            return(null);
        }
Esempio n. 11
0
        internal void SetUserMap(string userId, string campaignKey, string variationName, string goalIdentifier = null)
        {
            if (this._userStorageService == null)
            {
                LogDebugMessage.NoUserStorageServiceSet(file);
                return;
            }

            try
            {
                this._userStorageService.Set(new UserStorageMap(userId, campaignKey, variationName, goalIdentifier));
                LogInfoMessage.SavingDataUserStorageService(file, userId);
                return;
            }
            catch (Exception ex)
            {
                LogErrorMessage.SetUserStorageServiceFailed(file, userId);
            }
        }
        internal void SaveUserMap(string userId, string campaignTestKey, string variationName)
        {
            if (this._userProfileService == null)
            {
                LogDebugMessage.NoUserProfileServiceSave(file);
                return;
            }

            try
            {
                LogInfoMessage.SavingDataUserProfileService(file, userId);
                this._userProfileService.Save(new UserProfileMap(userId, campaignTestKey, variationName));
                return;
            }
            catch (Exception ex)
            {
                LogErrorMessage.SaveUserProfileServiceFailed(file, userId);
            }
        }
Esempio n. 13
0
        /// <summary>
        /// If variation is assigned, allocate the goal using goalIdentifier.
        /// </summary>
        /// <param name="campaignKey"></param>
        /// <param name="userId"></param>
        /// <param name="goalIdentifier"></param>
        /// <param name="campaign"></param>
        /// <param name="customVariables"></param>
        /// <param name="variationTargetingVariables"></param>
        /// <param name="apiName"></param>
        /// <returns>
        /// If Variation is allocated and goal with given identifier is found, return UserAssignedInfo with valid information, otherwise, Empty UserAssignedInfo object.
        /// </returns>
        private UserAllocationInfo AllocateVariation(string campaignKey, string userId, BucketedCampaign campaign, Dictionary <string, dynamic> customVariables, Dictionary <string, dynamic> variationTargetingVariables, string goalIdentifier, string apiName)
        {
            var userAllocationInfo = this.AllocateVariation(campaignKey, userId, campaign, customVariables, variationTargetingVariables, apiName);

            if (userAllocationInfo.Variation != null)
            {
                if (userAllocationInfo.Campaign.Goals.TryGetValue(goalIdentifier, out Goal goal))
                {
                    userAllocationInfo.Goal = goal;
                }
                else
                {
                    LogErrorMessage.TrackApiGoalNotFound(file, goalIdentifier, campaignKey, userId);
                }
            }
            else
            {
                LogErrorMessage.TrackApiVariationNotFound(file, campaignKey, userId);
            }
            return(userAllocationInfo);
        }
Esempio n. 14
0
        /// <summary>
        /// Makes a call to our server to store the tagValues
        /// </summary>
        /// <param name="tagKey">key name of the tag</param>
        /// <param name="tagValue">value of the tag</param>
        /// <param name="userId">User ID which uniquely identifies each user.</param>
        /// <returns>
        /// A boolean value based on whether the impression was made to the VWO server.
        /// True, if an impression event is successfully being made to the VWO server for report generation.
        /// False, If userId provided is not part of campaign or when unexpected error comes and no impression call is made to the VWO server.
        /// </returns>
        public bool Push(string tagKey, dynamic tagValue, string userId)
        {
            if (this._validator.Push(tagKey, tagValue, userId))
            {
                if ((int)tagKey.Length > (Constants.PushApi.TAG_KEY_LENGTH))
                {
                    LogErrorMessage.TagKeyLengthExceeded(typeof(IVWOClient).FullName, tagKey, userId, nameof(Push));
                    return(false);
                }

                if ((int)tagValue.Length > (Constants.PushApi.TAG_VALUE_LENGTH))
                {
                    LogErrorMessage.TagValueLengthExceeded(typeof(IVWOClient).FullName, tagValue, userId, nameof(Push));
                    return(false);
                }
                var pushRequest = ServerSideVerb.PushTags(this._settings, tagKey, tagValue, userId, this._isDevelopmentMode);
                pushRequest.ExecuteAsync();
                return(true);
            }
            return(false);
        }
Esempio n. 15
0
        /// <summary>
        /// Calls Get within try to suppress any Exception from outside of SDK application.
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="campaignKey"></param>
        /// <param name="userStorageData"></param>
        /// <returns></returns>
        private UserStorageMap TryGetUserMap(string userId, string campaignKey, Dictionary <string, dynamic> userStorageData = null)
        {
            try
            {
                LogInfoMessage.LookingUpUserStorageService(file, userId, campaignKey);
                if (userStorageData != null)
                {
                    if (userStorageData.ContainsKey("userId") && userStorageData.ContainsKey("campaignKey") && userStorageData.ContainsKey("variationName"))
                    {
                        if (string.IsNullOrEmpty(userStorageData["userId"]) == false && string.IsNullOrEmpty(userStorageData["campaignKey"]) == false &&
                            string.IsNullOrEmpty(userStorageData["variationName"]) == false)
                        {
                            string jsonString = JsonConvert.SerializeObject(userStorageData);
                            var    allValue   = JsonConvert.DeserializeObject <UserStorageMap>(jsonString);
                            LogInfoMessage.ReturnUserStorageData(file, userStorageData["userId"], userStorageData["campaignKey"]);
                            return(allValue);
                        }
                        else
                        {
                            return(this._userStorageService.Get(userId, campaignKey));
                        }
                    }
                    else
                    {
                        return(this._userStorageService.Get(userId, campaignKey));
                    }
                }
                else
                {
                    return(this._userStorageService.Get(userId, campaignKey));
                }
            }
            catch (Exception ex)
            {
                LogErrorMessage.GetUserStorageServiceFailed(file, userId, campaignKey);
            }

            return(null);
        }
Esempio n. 16
0
        /// <summary>
        /// Send Post network call to VWO servers.
        /// </summary>
        /// <returns>Boolean value specifying flush was successful or not.</returns>
        private async Task <bool> sendPostCall()
        {
            string     PayLoad    = HttpRequestBuilder.GetJsonString(this.batchQueue);
            var        ApiRequest = ServerSideVerb.EventBatching(this.accountId, this.isDevelopmentMode, this.apikey);
            HttpClient httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders.Accept.Clear();
            httpClient.DefaultRequestHeaders.Add("Authorization", this.apikey);
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            var data = new StringContent(PayLoad, Encoding.UTF8, "application/json");

            try
            {
                HttpResponseMessage response = await httpClient.PostAsync(ApiRequest.Uri, data);

                response.EnsureSuccessStatusCode();
                if (response.StatusCode == System.Net.HttpStatusCode.OK && response.StatusCode < System.Net.HttpStatusCode.Ambiguous)
                {
                    if (flushCallback != null)
                    {
                        flushCallback.onFlush(null, PayLoad);
                    }
                    LogInfoMessage.ImpressionSuccess(file, ApiRequest.logUri?.ToString());
                    return(true);
                }
                else if (response.StatusCode == System.Net.HttpStatusCode.RequestEntityTooLarge)
                {
                    if (flushCallback != null)
                    {
                        flushCallback.onFlush("Payload size too large", PayLoad);
                    }
                    LogDebugMessage.BatchEventLimitExceeded(file, ApiRequest.logUri?.ToString(), this.accountId.ToString(), eventsPerRequest.ToString());
                    LogErrorMessage.ImpressionFailed(file, ApiRequest.logUri?.ToString());

                    return(false);
                }
                else if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
                {
                    if (flushCallback != null)
                    {
                        flushCallback.onFlush("Account id not found, no request app id found, or invalid API key", PayLoad);
                    }
                    LogErrorMessage.BulkNotProcessed(file);
                    LogErrorMessage.ImpressionFailed(file, ApiRequest.logUri?.ToString());
                    return(false);
                }
                else
                {
                    LogErrorMessage.BulkNotProcessed(file);
                    LogErrorMessage.ImpressionFailed(file, ApiRequest.logUri?.ToString());
                    if (flushCallback != null)
                    {
                        flushCallback.onFlush("Invalid call", PayLoad);
                    }

                    return(false);
                }
            }
            catch (HttpRequestException ex)
            {
                LogErrorMessage.BulkNotProcessed(file);
                LogErrorMessage.UnableToDisplayHttpRequest(file, ex.StackTrace);
                if (flushCallback != null)
                {
                    flushCallback.onFlush("HttpRequest Exception", PayLoad);
                }
                return(false);
            }
        }
Esempio n. 17
0
        /// <summary>
        /// Tracks a conversion event for a particular user for a running server-side campaign.
        /// </summary>
        /// <param name="campaignKey">Campaign key to uniquely identify a server-side campaign.</param>
        /// <param name="userId">User ID which uniquely identifies each user.</param>
        /// <param name="goalIdentifier">The Goal key to uniquely identify a goal of a server-side campaign.</param>
        /// <param name="options">Dictionary for passing extra parameters to activate</param>
        /// <returns>
        /// A boolean value based on whether the impression was made to the VWO server.
        /// True, if an impression event is successfully being made to the VWO server for report generation.
        /// False, If userId provided is not part of campaign or when unexpected error comes and no impression call is made to the VWO server.
        /// </returns>
        public bool Track(string campaignKey, string userId, string goalIdentifier, Dictionary <string, dynamic> options = null)
        {
            if (options == null)
            {
                options = new Dictionary <string, dynamic>();
            }
            string revenueValue = options.ContainsKey("revenueValue") ? options["revenueValue"].ToString() : null;
            Dictionary <string, dynamic> customVariables             = options.ContainsKey("customVariables") ? options["customVariables"] : null;
            Dictionary <string, dynamic> variationTargetingVariables = options.ContainsKey("variationTargetingVariables") ? options["variationTargetingVariables"] : null;
            string goalTypeToTrack          = options.ContainsKey("goalTypeToTrack") ? options["goalTypeToTrack"] : null;
            bool   shouldTrackReturningUser = options.ContainsKey("shouldTrackReturningUser") ? options["shouldTrackReturningUser"] : this._shouldTrackReturningUser;

            if (this._validator.Track(campaignKey, userId, goalIdentifier, revenueValue, options))
            {
                goalTypeToTrack = !string.IsNullOrEmpty(goalTypeToTrack) ? goalTypeToTrack : this._goalTypeToTrack != null ? this._goalTypeToTrack : Constants.GoalTypes.ALL;
                var campaign = this._campaignAllocator.GetCampaign(this._settings, campaignKey);
                if (campaign == null || campaign.Status != Constants.CampaignStatus.RUNNING)
                {
                    LogErrorMessage.CampaignNotRunning(typeof(IVWOClient).FullName, campaignKey, nameof(Track));
                    return(false);
                }

                if (campaign.Type == Constants.CampaignTypes.FEATURE_ROLLOUT)
                {
                    LogErrorMessage.InvalidApi(typeof(IVWOClient).FullName, userId, campaignKey, campaign.Type, nameof(Track));
                    return(false);
                }
                var assignedVariation      = this.AllocateVariation(campaignKey, userId, campaign, customVariables, variationTargetingVariables, goalIdentifier: goalIdentifier, apiName: nameof(Track));
                var variationName          = assignedVariation.Variation?.Name;
                var selectedGoalIdentifier = assignedVariation.Goal?.Identifier;
                if (string.IsNullOrEmpty(variationName) == false)
                {
                    if (string.IsNullOrEmpty(selectedGoalIdentifier) == false)
                    {
                        if (goalTypeToTrack != assignedVariation.Goal.Type && goalTypeToTrack != Constants.GoalTypes.ALL)
                        {
                            return(false);
                        }
                        if (!this.isGoalTriggerRequired(campaignKey, userId, goalIdentifier, variationName, shouldTrackReturningUser))
                        {
                            return(false);
                        }
                        bool sendImpression = true;
                        if (assignedVariation.Goal.IsRevenueType() && string.IsNullOrEmpty(revenueValue))
                        {
                            sendImpression = false;
                            LogErrorMessage.TrackApiRevenueNotPassedForRevenueGoal(file, goalIdentifier, campaignKey, userId);
                        }
                        else if (assignedVariation.Goal.IsRevenueType() == false)
                        {
                            revenueValue = null;
                        }

                        if (sendImpression)
                        {
                            var trackGoalRequest = ServerSideVerb.TrackGoal(this._settings.AccountId, assignedVariation.Campaign.Id, assignedVariation.Variation.Id, userId, assignedVariation.Goal.Id, revenueValue, this._isDevelopmentMode);
                            trackGoalRequest.ExecuteAsync();
                            return(true);
                        }
                    }
                    else
                    {
                        LogErrorMessage.TrackApiGoalNotFound(file, goalIdentifier, campaignKey, userId);
                    }
                }
            }
            return(false);
        }