diff --git a/OptimizelySDK.Tests/EntityTests/FeatureVariableTest.cs b/OptimizelySDK.Tests/EntityTests/FeatureVariableTest.cs index e4324652..b44b3194 100644 --- a/OptimizelySDK.Tests/EntityTests/FeatureVariableTest.cs +++ b/OptimizelySDK.Tests/EntityTests/FeatureVariableTest.cs @@ -30,6 +30,7 @@ public void TestFeatureVariableTypeName() Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.DOUBLE_TYPE), "GetFeatureVariableDouble"); Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.INTEGER_TYPE), "GetFeatureVariableInteger"); Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.STRING_TYPE), "GetFeatureVariableString"); + Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.JSON_TYPE), "GetFeatureVariableJSON"); } [Test] @@ -39,6 +40,7 @@ public void TestConstantValues() Assert.AreEqual(FeatureVariable.DOUBLE_TYPE, "double"); Assert.AreEqual(FeatureVariable.INTEGER_TYPE, "integer"); Assert.AreEqual(FeatureVariable.STRING_TYPE, "string"); + Assert.AreEqual(FeatureVariable.JSON_TYPE, "json"); } } } diff --git a/OptimizelySDK.Tests/OptimizelyTest.cs b/OptimizelySDK.Tests/OptimizelyTest.cs index 84c77604..69dc28d6 100644 --- a/OptimizelySDK.Tests/OptimizelyTest.cs +++ b/OptimizelySDK.Tests/OptimizelyTest.cs @@ -62,6 +62,7 @@ public class OptimizelyTest const string FEATUREVARIABLE_INTEGERTYPE = "integer"; const string FEATUREVARIABLE_DOUBLETYPE = "double"; const string FEATUREVARIABLE_STRINGTYPE = "string"; + const string FEATUREVARIABLE_JSONTYPE = "json"; #region Test Life Cycle [SetUp] @@ -197,6 +198,7 @@ public void TestInvalidInstanceLogMessages() Assert.IsNull(optimizely.GetFeatureVariableString(string.Empty, string.Empty, string.Empty)); Assert.IsNull(optimizely.GetFeatureVariableDouble(string.Empty, string.Empty, string.Empty)); Assert.IsNull(optimizely.GetFeatureVariableInteger(string.Empty, string.Empty, string.Empty)); + Assert.IsNull(optimizely.GetFeatureVariableJSON(string.Empty, string.Empty, string.Empty)); LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Provided 'datafile' has invalid schema."), Times.Once); LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'GetVariation'."), Times.Once); @@ -208,6 +210,7 @@ public void TestInvalidInstanceLogMessages() LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'GetFeatureVariableString'."), Times.Once); LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'GetFeatureVariableDouble'."), Times.Once); LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'GetFeatureVariableInteger'."), Times.Once); + LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Datafile has invalid format. Failing 'GetFeatureVariableJSON'."), Times.Once); } [Test] @@ -1245,6 +1248,36 @@ public void TestGetFeatureVariableStringFRCulture() Assert.AreEqual(stringValueFR, "cta_1"); } + [Test] + public void TestGetFeatureVariableJSONFRCulture() + { + var fallbackConfigManager = new FallbackProjectConfigManager(Config); + + var expectedDict = new Dictionary() + { + { "int_var", 1 }, + { "boolean_key", false} + }; + + SetCulture("en-US"); + var optimizely = new Optimizely(fallbackConfigManager); + + var optimizelyJsonValue = optimizely.GetFeatureVariableJSON("string_single_variable_feature", "json_var", "testUser1"); + + Assert.IsTrue(TestData.CompareObjects(optimizelyJsonValue.ToDictionary(), expectedDict)); + Assert.AreEqual(optimizelyJsonValue.GetValue("int_var"), 1); + Assert.AreEqual(optimizelyJsonValue.GetValue("boolean_key"), false); + Assert.IsTrue(TestData.CompareObjects(optimizelyJsonValue.GetValue(""), expectedDict)); + + SetCulture("fr-FR"); + var optimizelyJsonValueFR = optimizely.GetFeatureVariableJSON("string_single_variable_feature", "json_var", "testUser1"); + + Assert.IsTrue(TestData.CompareObjects(optimizelyJsonValue.ToDictionary(), expectedDict)); + Assert.AreEqual(optimizelyJsonValueFR.GetValue("int_var"), 1); + Assert.AreEqual(optimizelyJsonValueFR.GetValue("boolean_key"), false); + Assert.IsTrue(TestData.CompareObjects(optimizelyJsonValue.GetValue(""), expectedDict)); + } + [Test] public void TestGetFeatureVariableDoubleReturnsCorrectValue() { @@ -1316,6 +1349,74 @@ public void TestGetFeatureVariableStringReturnsCorrectValue() Assert.Null(OptimizelyMock.Object.GetFeatureVariableString(featureKey, variableKeyNull, TestUserId, null)); } + [Test] + public void TestGetFeatureVariableJSONReturnsCorrectValue() + { + var featureKey = "featureKey"; + var variableKeyString = "varJSONString1"; + var variableKeyIntString = "varJSONString2"; + var variableKeyDouble = "varJSONDouble"; + var variableKeyNull = "varNull"; + var featureVariableType = "json"; + + OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType(It.IsAny(), variableKeyString, It.IsAny(), + It.IsAny(), featureVariableType)).Returns(new OptimizelyJson("{\"string\": \"Test String\"}", ErrorHandlerMock.Object, LoggerMock.Object)); + Assert.AreEqual("Test String", OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyString, TestUserId, null).GetValue("string")); + + OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType(It.IsAny(), variableKeyIntString, It.IsAny(), + It.IsAny(), featureVariableType)).Returns(new OptimizelyJson("{ \"integer\": 123 }", ErrorHandlerMock.Object, LoggerMock.Object)); + Assert.AreEqual(123, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyIntString, TestUserId, null).GetValue("integer")); + + OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType(It.IsAny(), variableKeyDouble, It.IsAny(), + It.IsAny(), featureVariableType)).Returns(new OptimizelyJson("{ \"double\": 123.28 }", ErrorHandlerMock.Object, LoggerMock.Object)); + Assert.AreEqual(123.28, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyDouble, TestUserId, null).GetValue("double")); + + OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType(It.IsAny(), variableKeyNull, It.IsAny(), + It.IsAny(), featureVariableType)).Returns(null); + Assert.Null(OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyNull, TestUserId, null)); + } + + [Test] + public void TestGetFeatureVariableJSONReturnsCorrectValueWhenInitializedUsingDictionary() + { + var featureKey = "featureKey"; + var variableKeyString = "varJSONString1"; + var variableKeyIntString = "varJSONString2"; + var variableKeyDouble = "varJSONDouble"; + var variableKeyBoolean = "varJSONBoolean"; + var variableKeyNull = "varNull"; + var featureVariableType = "json"; + + var expectedStringDict = new Dictionary() { { "string", "Test String" } }; + var expectedIntegerDict = new Dictionary() { { "integer", 123 } }; + var expectedDoubleDict = new Dictionary() { { "double", 123.28 } }; + var expectedBooleanDict = new Dictionary() { { "boolean", true } }; + + OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType(It.IsAny(), variableKeyString, It.IsAny(), + It.IsAny(), featureVariableType)).Returns(new OptimizelyJson(expectedStringDict, ErrorHandlerMock.Object, LoggerMock.Object)); + Assert.IsTrue(TestData.CompareObjects(expectedStringDict, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyString, TestUserId, null).ToDictionary())); + Assert.AreEqual("Test String", OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyString, TestUserId, null).GetValue("string")); + + OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType(It.IsAny(), variableKeyIntString, It.IsAny(), + It.IsAny(), featureVariableType)).Returns(new OptimizelyJson(expectedIntegerDict, ErrorHandlerMock.Object, LoggerMock.Object)); + Assert.IsTrue(TestData.CompareObjects(expectedIntegerDict, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyIntString, TestUserId, null).ToDictionary())); + Assert.AreEqual(123, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyIntString, TestUserId, null).GetValue("integer")); + + OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType(It.IsAny(), variableKeyDouble, It.IsAny(), + It.IsAny(), featureVariableType)).Returns(new OptimizelyJson(expectedDoubleDict, ErrorHandlerMock.Object, LoggerMock.Object)); + Assert.IsTrue(TestData.CompareObjects(expectedDoubleDict, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyDouble, TestUserId, null).ToDictionary())); + Assert.AreEqual(123.28, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyDouble, TestUserId, null).GetValue("double")); + + OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType(It.IsAny(), variableKeyBoolean, It.IsAny(), + It.IsAny(), featureVariableType)).Returns(new OptimizelyJson(expectedBooleanDict, ErrorHandlerMock.Object, LoggerMock.Object)); + Assert.IsTrue(TestData.CompareObjects(expectedBooleanDict, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyBoolean, TestUserId, null).ToDictionary())); + Assert.AreEqual(true, OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyBoolean, TestUserId, null).GetValue("boolean")); + + OptimizelyMock.Setup(om => om.GetFeatureVariableValueForType(It.IsAny(), variableKeyNull, It.IsAny(), + It.IsAny(), featureVariableType)).Returns(null); + Assert.Null(OptimizelyMock.Object.GetFeatureVariableJSON(featureKey, variableKeyNull, TestUserId, null)); + } + #region Feature Toggle Tests [Test] @@ -1444,6 +1545,70 @@ public void TestGetFeatureVariableBooleanReturnsRightValueWhenUserBuckedIntoRoll LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Returning variable value ""true"" for variation ""{variation.Key}"" of feature flag ""{featureKey}"".")); } + [Test] + public void TestGetFeatureVariableJSONReturnsRightValueWhenUserBucketIntoRolloutAndVariationIsToggleOn() + { + var featureKey = "string_single_variable_feature"; + var featureFlag = Config.GetFeatureFlagFromKey(featureKey); + var variableKey = "json_var"; + var expectedStringValue = "cta_4"; + var expectedIntValue = 4; + var experiment = Config.GetRolloutFromId("166661").Experiments[0]; + var variation = Config.GetVariationFromKey(experiment.Key, "177775"); + var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT); + var userAttributes = new UserAttributes + { + { "device_type", "iPhone" }, + { "company", "Optimizely" }, + { "location", "San Francisco" } + }; + + DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, Config, userAttributes)).Returns(decision); + + var optly = Helper.CreatePrivateOptimizely(); + + optly.SetFieldOrProperty("ProjectConfigManager", ConfigManager); + optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object); + + var variableValue = (OptimizelyJson)optly.Invoke("GetFeatureVariableJSON", featureKey, variableKey, TestUserId, userAttributes); + Assert.AreEqual(expectedIntValue, variableValue.GetValue("int_var")); + Assert.AreEqual(expectedStringValue, variableValue.GetValue("string_var")); + + LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Returning variable value ""{variableValue}"" for variation ""{variation.Key}"" of feature flag ""{featureKey}"".")); + } + + [Test] + public void TestGetFeatureVariableJSONReturnsRightValueWhenUserBucketIntoRolloutAndVariationIsToggleOnTypeIsJson() + { + var featureKey = "string_single_variable_feature"; + var featureFlag = Config.GetFeatureFlagFromKey(featureKey); + var variableKey = "true_json_var"; + var expectedStringValue = "cta_5"; + var expectedIntValue = 5; + var experiment = Config.GetRolloutFromId("166661").Experiments[0]; + var variation = Config.GetVariationFromKey(experiment.Key, "177775"); + var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT); + var userAttributes = new UserAttributes + { + { "device_type", "iPhone" }, + { "company", "Optimizely" }, + { "location", "San Francisco" } + }; + + DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, Config, userAttributes)).Returns(decision); + + var optly = Helper.CreatePrivateOptimizely(); + + optly.SetFieldOrProperty("ProjectConfigManager", ConfigManager); + optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object); + + var variableValue = (OptimizelyJson)optly.Invoke("GetFeatureVariableJSON", featureKey, variableKey, TestUserId, userAttributes); + Assert.AreEqual(expectedIntValue, variableValue.GetValue("int_var")); + Assert.AreEqual(expectedStringValue, variableValue.GetValue("string_var")); + + LoggerMock.Verify(l => l.Log(LogLevel.INFO, $@"Returning variable value ""{variableValue}"" for variation ""{variation.Key}"" of feature flag ""{featureKey}"".")); + } + [Test] public void TestGetFeatureVariableStringReturnsRightValueWhenUserBuckedIntoRolloutAndVariationIsToggleOn() { @@ -1606,6 +1771,7 @@ public void TestGetFeatureVariableValueForTypeGivenInvalidVariableType() Assert.IsNull(Optimizely.GetFeatureVariableValueForType("boolean_single_variable_feature", "boolean_variable", TestUserId, null, variableTypeDouble)); Assert.IsNull(Optimizely.GetFeatureVariableValueForType("integer_single_variable_feature", "integer_variable", TestUserId, null, variableTypeString)); Assert.IsNull(Optimizely.GetFeatureVariableValueForType("string_single_variable_feature", "string_variable", TestUserId, null, variableTypeInt)); + Assert.IsNull(Optimizely.GetFeatureVariableValueForType("string_single_variable_feature", "json_var", TestUserId, null, variableTypeInt)); LoggerMock.Verify(l => l.Log(LogLevel.ERROR, $@"Variable is of type ""double"", but you requested it as type ""{variableTypeBool}"".")); @@ -1623,8 +1789,9 @@ public void TestUnsupportedVariableType() var featureVariableStringRandomType = Optimizely.GetFeatureVariableString("", "any_key", TestUserId); Assert.IsNull(featureVariableStringRandomType); - var featureVariableStringJsonType = Optimizely.GetFeatureVariableString("unsupported_variabletype", "string_json_key", TestUserId); - Assert.AreEqual(featureVariableStringJsonType, "{\"myvalue\": \"jsonValue\"}"); + // This is to test that only json subtype is parsing and all other will subtype will be stringify + var featureVariableStringRegexSubType = Optimizely.GetFeatureVariableString("unsupported_variabletype", "string_regex_key", TestUserId); + Assert.AreEqual(featureVariableStringRegexSubType, "^\\d+(\\.\\d+)?"); } // Should return default value and log message when feature is not enabled for the user. @@ -2632,6 +2799,55 @@ public void TestGetFeatureVariableDoubleSendsNotificationWhenUserBuckedIntoFeatu NotificationCallbackMock.Verify(nc => nc.TestDecisionCallback(DecisionNotificationTypes.FEATURE_VARIABLE, TestUserId, new UserAttributes(), It.Is>(info => TestData.CompareObjects(info, decisionInfo))), Times.Once); } + [Test] + public void TestGetFeatureVariableJsonSendsNotificationWhenUserBuckedIntoFeatureExperimentAndVariationIsToggleOn() + { + var featureKey = "string_single_variable_feature"; + var featureFlag = Config.GetFeatureFlagFromKey(featureKey); + var variableKey = "json_var"; + var expectedDict = new Dictionary() + { + { "int_var", 4 }, + { "string_var", "cta_4"} + }; + var experiment = Config.GetRolloutFromId("166661").Experiments[0]; + var variation = Config.GetVariationFromKey(experiment.Key, "177775"); + var decision = new FeatureDecision(experiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT); + var userAttributes = new UserAttributes + { + { "device_type", "iPhone" }, + { "company", "Optimizely" }, + { "location", "San Francisco" } + }; + + DecisionServiceMock.Setup(ds => ds.GetVariationForFeature(featureFlag, TestUserId, Config, userAttributes)).Returns(decision); + NotificationCallbackMock.Setup(nc => nc.TestDecisionCallback(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny>())); + + var optly = Helper.CreatePrivateOptimizely(); + + optly.SetFieldOrProperty("ProjectConfigManager", ConfigManager); + var optStronglyTyped = optly.GetObject() as Optimizely; + + optly.SetFieldOrProperty("DecisionService", DecisionServiceMock.Object); + optStronglyTyped.NotificationCenter.AddNotification(NotificationCenter.NotificationType.Decision, NotificationCallbackMock.Object.TestDecisionCallback); + + var variableValue = (OptimizelyJson)optly.Invoke("GetFeatureVariableJSON", featureKey, variableKey, TestUserId, userAttributes); + Assert.IsTrue(TestData.CompareObjects(expectedDict, variableValue.ToDictionary())); + var decisionInfo = new Dictionary + { + { "featureKey", featureKey }, + { "featureEnabled", true }, + { "variableKey", variableKey }, + { "variableValue", expectedDict }, + { "variableType", FEATUREVARIABLE_JSONTYPE }, + { "source", FeatureDecision.DECISION_SOURCE_ROLLOUT }, + { "sourceInfo", new Dictionary() }, + }; + + NotificationCallbackMock.Verify(nc => nc.TestDecisionCallback(DecisionNotificationTypes.FEATURE_VARIABLE, TestUserId, userAttributes, It.Is>(info => TestData.CompareObjects(info, decisionInfo))), Times.Once); + } + [Test] public void TestGetFeatureVariableIntegerSendsNotificationWhenUserBuckedIntoFeatureExperimentAndVariationIsToggleOn() { diff --git a/OptimizelySDK.Tests/TestData.json b/OptimizelySDK.Tests/TestData.json index 0e44dc56..11f3decb 100644 --- a/OptimizelySDK.Tests/TestData.json +++ b/OptimizelySDK.Tests/TestData.json @@ -171,6 +171,10 @@ { "id": "155558", "value": "cta_1" + }, + { + "id": "17014990011", + "value": "{\"int_var\": 1, \"boolean_key\": false}" } ], "featureEnabled": true @@ -589,6 +593,19 @@ "key": "string_variable", "type": "string", "defaultValue": "wingardium leviosa" + }, + { + "defaultValue": "{\"int_var\": 5212, \"boolean_key\": true}", + "type": "string", + "subType": "json", + "id": "17014990011", + "key": "json_var" + }, + { + "defaultValue": "{\"int_var\": 123, \"boolean_key\": true}", + "type": "json", + "id": "170149900112", + "key": "true_json_var" } ] }, @@ -654,10 +671,10 @@ }, { "id": "255555", - "key": "string_json_key", + "key": "string_regex_key", "type": "string", - "defaultValue": "{\"myvalue\": \"jsonValue\"}", - "subType": "json" + "defaultValue": "^\\d+(\\.\\d+)?", + "subType": "regex" } ] @@ -816,6 +833,14 @@ { "id": "155558", "value": "cta_4" + }, + { + "id": "17014990011", + "value": "{\"int_var\": 4 , \"string_var\": \"cta_4\"}" + }, + { + "id": "170149900112", + "value": "{\"int_var\": 5 , \"string_var\": \"cta_5\"}" } ], "featureEnabled": true diff --git a/OptimizelySDK/Entity/FeatureVariable.cs b/OptimizelySDK/Entity/FeatureVariable.cs index c0634b9e..33f69a72 100644 --- a/OptimizelySDK/Entity/FeatureVariable.cs +++ b/OptimizelySDK/Entity/FeatureVariable.cs @@ -22,6 +22,7 @@ public class FeatureVariable : IdKeyEntity public const string INTEGER_TYPE = "integer"; public const string DOUBLE_TYPE = "double"; public const string BOOLEAN_TYPE = "boolean"; + public const string JSON_TYPE = "json"; public enum VariableStatus { @@ -31,7 +32,38 @@ public enum VariableStatus public string DefaultValue { get; set; } - public string Type { get; set; } + + private string _subType; + + public string SubType + { + get + { + return _subType; + } + set + { + _subType = value; + } + } + + private string _type; + public string Type + { + get + { + if (_type == STRING_TYPE && _subType == JSON_TYPE) + { + return JSON_TYPE; + } + return _type; + } + set + { + _type = value; + } + } + public VariableStatus Status { get; set; } /// @@ -50,6 +82,8 @@ public static string GetFeatureVariableTypeName(string variableType) return "GetFeatureVariableInteger"; case STRING_TYPE: return "GetFeatureVariableString"; + case JSON_TYPE: + return "GetFeatureVariableJSON"; default: return null; } diff --git a/OptimizelySDK/Optimizely.cs b/OptimizelySDK/Optimizely.cs index d227597d..297a4f7f 100644 --- a/OptimizelySDK/Optimizely.cs +++ b/OptimizelySDK/Optimizely.cs @@ -28,6 +28,7 @@ using OptimizelySDK.Config; using OptimizelySDK.Event; using OptimizelySDK.OptlyConfig; +using System.Net; namespace OptimizelySDK { @@ -547,7 +548,7 @@ public virtual T GetFeatureVariableValueForType(string featureKey, string var return default(T); } else if (featureVariable.Type != variableType) - { + { Logger.Log(LogLevel.ERROR, $@"Variable is of type ""{featureVariable.Type}"", but you requested it as type ""{variableType}""."); return default(T); @@ -599,7 +600,7 @@ public virtual T GetFeatureVariableValueForType(string featureKey, string var { "featureKey", featureKey }, { "featureEnabled", featureEnabled }, { "variableKey", variableKey }, - { "variableValue", typeCastedValue }, + { "variableValue", typeCastedValue is OptimizelyJson? ((OptimizelyJson)typeCastedValue).ToDictionary() : typeCastedValue }, { "variableType", variableType.ToString().ToLower() }, { "source", decision?.Source }, { "sourceInfo", sourceInfo }, @@ -662,6 +663,19 @@ public string GetFeatureVariableString(string featureKey, string variableKey, st return GetFeatureVariableValueForType(featureKey, variableKey, userId, userAttributes, FeatureVariable.STRING_TYPE); } + /// + /// Gets json sub type feature variable value. + /// + /// The feature flag key + /// The variable key + /// The user ID + /// The user's attributes + /// OptimizelyJson | Feature variable value or null + public OptimizelyJson GetFeatureVariableJSON(string featureKey, string variableKey, string userId, UserAttributes userAttributes = null) + { + return GetFeatureVariableValueForType(featureKey, variableKey, userId, userAttributes, FeatureVariable.JSON_TYPE); + } + /// /// Sends impression event. /// @@ -806,6 +820,9 @@ private object GetTypeCastedVariableValue(string value, string type) case FeatureVariable.STRING_TYPE: result = value; break; + case FeatureVariable.JSON_TYPE: + result = new OptimizelyJson(value, ErrorHandler, Logger); + break; } if (result == null)