private EvaluateResult EvaluateLogic(ProjectConfig projectConfig, string key, string logDefaultValue, string logDefaultVariationId, User user = null) { if (!this.configDeserializer.TryDeserialize(projectConfig.JsonString, out var deserialized)) { this.log.Warning("Config deserialization failed, returning defaultValue"); return(null); } var settings = deserialized.Settings; if (!settings.TryGetValue(key, out var setting)) { var keys = string.Join(",", settings.Keys.Select(s => $"'{s}'").ToArray()); this.log.Error($"Evaluating '{key}' failed. Returning default value: '{logDefaultValue}'. Here are the available keys: {keys}."); return(null); } var evaluateLog = new EvaluateLogger <string> { ReturnValue = logDefaultValue, User = user, KeyName = key, VariationId = logDefaultVariationId }; try { EvaluateResult result = null; if (user != null) { // evaluate rules if (TryEvaluateRules(setting.RolloutRules, user, evaluateLog, out result)) { evaluateLog.ReturnValue = result.RawValue; evaluateLog.VariationId = result.VariationId; return(result); } // evaluate variations if (TryEvaluateVariations(setting.RolloutPercentageItems, key, user, out result)) { evaluateLog.Log("evaluate % option => user targeted"); evaluateLog.ReturnValue = result.RawValue; evaluateLog.VariationId = result.VariationId; return(result); } else { evaluateLog.Log("evaluate % option => user not targeted"); } } else if (user == null && (setting.RolloutRules.Any() || setting.RolloutPercentageItems.Any())) { this.log.Warning($"Evaluating '{key}'. UserObject missing! You should pass a UserObject to GetValue() or GetValueAsync(), in order to make targeting work properly. Read more: https://configcat.com/docs/advanced/user-object"); } // regular evaluate result = new EvaluateResult(setting.RawValue, setting.VariationId); evaluateLog.ReturnValue = result.RawValue; evaluateLog.VariationId = result.VariationId; return(result); } finally { this.log.Information(evaluateLog.ToString()); } }
private static bool TryEvaluateRules <T>(ICollection <RolloutRule> rules, User user, EvaluateLogger <T> logger, out EvaluateResult result) { result = new EvaluateResult(); if (rules != null && rules.Count > 0) { foreach (var rule in rules.OrderBy(o => o.Order)) { result.RawValue = rule.RawValue; result.VariationId = rule.VariationId; if (!user.AllAttributes.ContainsKey(rule.ComparisonAttribute)) { continue; } var comparisonAttributeValue = user.AllAttributes[rule.ComparisonAttribute]; if (string.IsNullOrEmpty(comparisonAttributeValue)) { continue; } string l = $"evaluate rule: '{comparisonAttributeValue}' {EvaluateLogger<T>.FormatComparator(rule.Comparator)} '{rule.ComparisonValue}' => "; switch (rule.Comparator) { case ComparatorEnum.In: if (rule.ComparisonValue .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(t => t.Trim()) .Contains(comparisonAttributeValue)) { logger.Log(l + "match"); return(true); } logger.Log(l + "no match"); break; case ComparatorEnum.NotIn: if (!rule.ComparisonValue .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(t => t.Trim()) .Contains(comparisonAttributeValue)) { logger.Log(l + "match"); return(true); } logger.Log(l + "no match"); break; case ComparatorEnum.Contains: if (comparisonAttributeValue.Contains(rule.ComparisonValue)) { logger.Log(l + "match"); return(true); } logger.Log(l + "no match"); break; case ComparatorEnum.NotContains: if (!comparisonAttributeValue.Contains(rule.ComparisonValue)) { logger.Log(l + "match"); return(true); } logger.Log(l + "no match"); break; case ComparatorEnum.SemVerIn: case ComparatorEnum.SemVerNotIn: case ComparatorEnum.SemVerLessThan: case ComparatorEnum.SemVerLessThanEqual: case ComparatorEnum.SemVerGreaterThan: case ComparatorEnum.SemVerGreaterThanEqual: if (EvaluateSemVer(comparisonAttributeValue, rule.ComparisonValue, rule.Comparator)) { logger.Log(l + "match"); return(true); } logger.Log(l + "no match"); break; case ComparatorEnum.NumberEqual: case ComparatorEnum.NumberNotEqual: case ComparatorEnum.NumberLessThan: case ComparatorEnum.NumberLessThanEqual: case ComparatorEnum.NumberGreaterThan: case ComparatorEnum.NumberGreaterThanEqual: if (EvaluateNumber(comparisonAttributeValue, rule.ComparisonValue, rule.Comparator)) { logger.Log(l + "match"); return(true); } logger.Log(l + "no match"); break; case ComparatorEnum.SensitiveOneOf: if (rule.ComparisonValue .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(t => t.Trim()) .Contains(HashUtils.HashString(comparisonAttributeValue))) { logger.Log(l + "match"); return(true); } logger.Log(l + "no match"); break; case ComparatorEnum.SensitiveNotOneOf: if (!rule.ComparisonValue .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(t => t.Trim()) .Contains(HashUtils.HashString(comparisonAttributeValue))) { logger.Log(l + "match"); return(true); } logger.Log(l + "no match"); break; default: break; } } } return(false); }