/// <summary> /// Get a Variation of an Experiment for a user to be allocated into. /// </summary> /// <param name = "experiment" > The Experiment the user will be bucketed into.</param> /// <param name = "userId" > The userId of the user. /// <param name = "filteredAttributes" > The user's attributes. This should be filtered to just attributes in the Datafile.</param> /// <returns>The Variation the user is allocated into.</returns> public virtual Variation GetVariation(Experiment experiment, string userId, ProjectConfig config, UserAttributes filteredAttributes) { if (!ExperimentUtils.IsExperimentActive(experiment, Logger)) { return(null); } // check if a forced variation is set var forcedVariation = GetForcedVariation(experiment.Key, userId, config); if (forcedVariation != null) { return(forcedVariation); } var variation = GetWhitelistedVariation(experiment, userId); if (variation != null) { return(variation); } UserProfile userProfile = null; if (UserProfileService != null) { try { Dictionary <string, object> userProfileMap = UserProfileService.Lookup(userId); if (userProfileMap != null && UserProfileUtil.IsValidUserProfileMap(userProfileMap)) { userProfile = UserProfileUtil.ConvertMapToUserProfile(userProfileMap); variation = GetStoredVariation(experiment, userProfile, config); if (variation != null) { return(variation); } } else if (userProfileMap == null) { Logger.Log(LogLevel.INFO, "We were unable to get a user profile map from the UserProfileService."); } else { Logger.Log(LogLevel.ERROR, "The UserProfileService returned an invalid map."); } } catch (Exception exception) { Logger.Log(LogLevel.ERROR, exception.Message); ErrorHandler.HandleError(new Exceptions.OptimizelyRuntimeException(exception.Message)); } } if (ExperimentUtils.IsUserInExperiment(config, experiment, filteredAttributes, Logger)) { // Get Bucketing ID from user attributes. string bucketingId = GetBucketingId(userId, filteredAttributes); variation = Bucketer.Bucket(config, experiment, bucketingId, userId); if (variation != null && variation.Key != null) { if (UserProfileService != null) { var bucketerUserProfile = userProfile ?? new UserProfile(userId, new Dictionary <string, Decision>()); SaveVariation(experiment, variation, bucketerUserProfile); } else { Logger.Log(LogLevel.INFO, "This decision will not be saved since the UserProfileService is null."); } } return(variation); } Logger.Log(LogLevel.INFO, $"User \"{userId}\" does not meet conditions to be in experiment \"{experiment.Key}\"."); return(null); }
/// <summary> /// Get a Variation of an Experiment for a user to be allocated into. /// </summary> /// <param name = "experiment" > The Experiment the user will be bucketed into.</param> /// <param name = "user" > optimizely user context. /// <param name = "config" > Project Config.</param> /// <param name = "options" >An array of decision options.</param> /// <returns>The Variation the user is allocated into.</returns> public virtual Result <Variation> GetVariation(Experiment experiment, OptimizelyUserContext user, ProjectConfig config, OptimizelyDecideOption[] options) { var reasons = new DecisionReasons(); var userId = user.GetUserId(); if (!ExperimentUtils.IsExperimentActive(experiment, Logger)) { return(Result <Variation> .NullResult(reasons)); } // check if a forced variation is set var decisionVariationResult = GetForcedVariation(experiment.Key, userId, config); reasons += decisionVariationResult.DecisionReasons; var variation = decisionVariationResult.ResultObject; if (variation == null) { decisionVariationResult = GetWhitelistedVariation(experiment, user.GetUserId()); reasons += decisionVariationResult.DecisionReasons; variation = decisionVariationResult.ResultObject; } if (variation != null) { decisionVariationResult.SetReasons(reasons); return(decisionVariationResult); } // fetch the user profile map from the user profile service var ignoreUPS = Array.Exists(options, option => option == OptimizelyDecideOption.IGNORE_USER_PROFILE_SERVICE); UserProfile userProfile = null; if (!ignoreUPS && UserProfileService != null) { try { Dictionary <string, object> userProfileMap = UserProfileService.Lookup(user.GetUserId()); if (userProfileMap != null && UserProfileUtil.IsValidUserProfileMap(userProfileMap)) { userProfile = UserProfileUtil.ConvertMapToUserProfile(userProfileMap); decisionVariationResult = GetStoredVariation(experiment, userProfile, config); reasons += decisionVariationResult.DecisionReasons; if (decisionVariationResult.ResultObject != null) { return(decisionVariationResult.SetReasons(reasons)); } } else if (userProfileMap == null) { Logger.Log(LogLevel.INFO, reasons.AddInfo("We were unable to get a user profile map from the UserProfileService.")); } else { Logger.Log(LogLevel.ERROR, reasons.AddInfo("The UserProfileService returned an invalid map.")); } } catch (Exception exception) { Logger.Log(LogLevel.ERROR, reasons.AddInfo(exception.Message)); ErrorHandler.HandleError(new Exceptions.OptimizelyRuntimeException(exception.Message)); } } var filteredAttributes = user.GetAttributes(); var doesUserMeetAudienceConditionsResult = ExperimentUtils.DoesUserMeetAudienceConditions(config, experiment, filteredAttributes, LOGGING_KEY_TYPE_EXPERIMENT, experiment.Key, Logger); reasons += doesUserMeetAudienceConditionsResult.DecisionReasons; if (doesUserMeetAudienceConditionsResult.ResultObject) { // Get Bucketing ID from user attributes. var bucketingIdResult = GetBucketingId(userId, filteredAttributes); reasons += bucketingIdResult.DecisionReasons; decisionVariationResult = Bucketer.Bucket(config, experiment, bucketingIdResult.ResultObject, userId); reasons += decisionVariationResult.DecisionReasons; if (decisionVariationResult.ResultObject?.Key != null) { if (UserProfileService != null && !ignoreUPS) { var bucketerUserProfile = userProfile ?? new UserProfile(userId, new Dictionary <string, Decision>()); SaveVariation(experiment, decisionVariationResult.ResultObject, bucketerUserProfile); } else { Logger.Log(LogLevel.INFO, "This decision will not be saved since the UserProfileService is null."); } } return(decisionVariationResult.SetReasons(reasons)); } Logger.Log(LogLevel.INFO, reasons.AddInfo($"User \"{user.GetUserId()}\" does not meet conditions to be in experiment \"{experiment.Key}\".")); return(Result <Variation> .NullResult(reasons)); }