From 74c58b65f290a3edbbfe1c3953c523bf5838af8d Mon Sep 17 00:00:00 2001 From: esrakartalOpt Date: Tue, 12 Aug 2025 10:40:52 -0500 Subject: [PATCH 1/8] [FSSDK-11463] C# - Add SDK Multi-Region Support for Data Hosting --- .../EventTests/EventBuilderTest.cs | 42 +- .../EventTests/EventFactoryTest.cs | 410 +++++++++++++++++- .../TestForwardingEventDispatcher.cs | 2 +- OptimizelySDK.Tests/OptimizelyTest.cs | 2 +- OptimizelySDK/Config/DatafileProjectConfig.cs | 6 + OptimizelySDK/Event/Builder/EventBuilder.cs | 11 +- OptimizelySDK/Event/Entity/EventContext.cs | 11 + OptimizelySDK/Event/EventFactory.cs | 30 +- OptimizelySDK/Event/UserEventFactory.cs | 2 + OptimizelySDK/ProjectConfig.cs | 5 + 10 files changed, 467 insertions(+), 54 deletions(-) diff --git a/OptimizelySDK.Tests/EventTests/EventBuilderTest.cs b/OptimizelySDK.Tests/EventTests/EventBuilderTest.cs index c869d831..8b4c3ad5 100644 --- a/OptimizelySDK.Tests/EventTests/EventBuilderTest.cs +++ b/OptimizelySDK.Tests/EventTests/EventBuilderTest.cs @@ -115,7 +115,7 @@ public void TestCreateImpressionEventNoAttributes() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -207,7 +207,7 @@ public void TestCreateImpressionEventWithAttributes() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -327,7 +327,7 @@ public void TestCreateImpressionEventWithTypedAttributes() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -441,7 +441,7 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayload() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -531,7 +531,7 @@ public void TestCreateConversionEventNoAttributesNoValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -617,7 +617,7 @@ public void TestCreateConversionEventWithAttributesNoValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -709,7 +709,7 @@ public void TestCreateConversionEventNoAttributesWithValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -809,7 +809,7 @@ public void TestCreateConversionEventWithAttributesWithValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -909,7 +909,7 @@ public void TestCreateConversionEventNoAttributesWithInvalidValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1003,7 +1003,7 @@ public void TestConversionEventWithNumericTag() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1096,7 +1096,7 @@ public void TestConversionEventWithFalsyNumericAndRevenueValues() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1189,7 +1189,7 @@ public void TestConversionEventWithNumericValue1() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1282,7 +1282,7 @@ public void TestConversionEventWithRevenueValue1() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1381,7 +1381,7 @@ public void TestCreateConversionEventWithBucketingIDAttribute() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1487,7 +1487,7 @@ public void TestCreateImpressionEventWithBucketingIDAttribute() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1587,7 +1587,7 @@ public void TestCreateImpressionEventWhenBotFilteringIsProvidedInDatafile() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1680,7 +1680,7 @@ public void TestCreateImpressionEventWhenBotFilteringIsNotProvidedInDatafile() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1770,7 +1770,7 @@ public void TestCreateConversionEventWhenBotFilteringIsProvidedInDatafile() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1856,7 +1856,7 @@ public void TestCreateConversionEventWhenBotFilteringIsNotProvidedInDatafile() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1989,7 +1989,7 @@ public void TestCreateConversionEventWhenEventUsedInMultipleExp() var expectedLogEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -2082,7 +2082,7 @@ public void TestCreateConversionEventRemovesInvalidAttributesFromPayload() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary diff --git a/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs b/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs index 3199a8ae..0fd2dfdd 100644 --- a/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs +++ b/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs @@ -66,6 +66,208 @@ public void Assert.IsNull(impressionEvent); } + [Test] + public void TestCreateImpressionEventNoAttributesEU() + { + var guid = Guid.NewGuid(); + var timeStamp = TestData.SecondsSince1970(); + + var payloadParams = new Dictionary + { + { + "visitors", new object[] + { + new Dictionary() + { + { + "snapshots", new object[] + { + new Dictionary + { + { + "decisions", new object[] + { + new Dictionary + { + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + { + "metadata", + new Dictionary + { + { "rule_type", "experiment" }, + { "rule_key", "test_experiment" }, + { "flag_key", "test_experiment" }, + { "variation_key", "control" }, + { "enabled", false }, + } + }, + }, + } + }, + { + "events", new object[] + { + new Dictionary + { + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, + } + }, + }, + } + }, + { + "attributes", new object[] + { + new Dictionary + { + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, + } + }, + { "visitor_id", TestUserId }, + }, + } + }, + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, + }; + + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["EU"], + payloadParams, + "POST", + new Dictionary + { + { "Content-Type", "application/json" }, + }); + + Config.Region = "EU"; + var impressionEvent = UserEventFactory.CreateImpressionEvent( + Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, + null, "test_experiment", "experiment"); + + var logEvent = EventFactory.CreateLogEvent(impressionEvent, Logger); + + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, + Guid.Parse(impressionEvent.UUID)); + + Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); + } + + [Test] + public void TestCreateImpressionEventNoAttributesInvalid() + { + var guid = Guid.NewGuid(); + var timeStamp = TestData.SecondsSince1970(); + + var payloadParams = new Dictionary + { + { + "visitors", new object[] + { + new Dictionary() + { + { + "snapshots", new object[] + { + new Dictionary + { + { + "decisions", new object[] + { + new Dictionary + { + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + { + "metadata", + new Dictionary + { + { "rule_type", "experiment" }, + { "rule_key", "test_experiment" }, + { "flag_key", "test_experiment" }, + { "variation_key", "control" }, + { "enabled", false }, + } + }, + }, + } + }, + { + "events", new object[] + { + new Dictionary + { + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, + } + }, + }, + } + }, + { + "attributes", new object[] + { + new Dictionary + { + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, + } + }, + { "visitor_id", TestUserId }, + }, + } + }, + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, + }; + + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], + payloadParams, + "POST", + new Dictionary + { + { "Content-Type", "application/json" }, + }); + + Config.Region = "ZZ"; + var impressionEvent = UserEventFactory.CreateImpressionEvent( + Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, + null, "test_experiment", "experiment"); + + var logEvent = EventFactory.CreateLogEvent(impressionEvent, Logger); + + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, + Guid.Parse(impressionEvent.UUID)); + + Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); + } + [Test] public void TestCreateImpressionEventNoAttributes() { @@ -146,7 +348,7 @@ public void TestCreateImpressionEventNoAttributes() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -251,7 +453,7 @@ public void TestCreateImpressionEventWithAttributes() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -383,7 +585,7 @@ public void TestCreateImpressionEventWithTypedAttributes() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -509,7 +711,7 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayload() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -642,7 +844,7 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayloadRollout( { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -735,7 +937,170 @@ public void TestCreateConversionEventNoAttributesNoValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], + payloadParams, + "POST", + new Dictionary + { + { "Content-Type", "application/json" }, + }); + var experimentToVariationMap = new Dictionary + { + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, + }; + + var conversionEvent = + UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, null); + var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); + + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); + + Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); + } + + [Test] + public void TestCreateConversionEventNoAttributesNoValueEU() + { + var guid = Guid.NewGuid(); + var timeStamp = TestData.SecondsSince1970(); + + var payloadParams = new Dictionary + { + { + "visitors", new object[] + { + new Dictionary + { + { + "snapshots", new object[] + { + new Dictionary + { + { + "events", new object[] + { + new Dictionary + { + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, + } + }, + }, + } + }, + { "visitor_id", TestUserId }, + { + "attributes", new object[] + { + new Dictionary + { + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, + } + }, + }, + } + }, + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, + }; + + var expectedEvent = new LogEvent( + EventFactory.EventEndpoints["EU"], + payloadParams, + "POST", + new Dictionary + { + { "Content-Type", "application/json" }, + }); + var experimentToVariationMap = new Dictionary + { + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, + }; + + Config.Region = "EU"; + var conversionEvent = + UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, null); + var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); + + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); + + Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); + } + + [Test] + public void TestCreateConversionEventNoAttributesNoValueInvalid() + { + var guid = Guid.NewGuid(); + var timeStamp = TestData.SecondsSince1970(); + + var payloadParams = new Dictionary + { + { + "visitors", new object[] + { + new Dictionary + { + { + "snapshots", new object[] + { + new Dictionary + { + { + "events", new object[] + { + new Dictionary + { + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, + } + }, + }, + } + }, + { "visitor_id", TestUserId }, + { + "attributes", new object[] + { + new Dictionary + { + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, + } + }, + }, + } + }, + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, + }; + + var expectedEvent = new LogEvent( + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -747,6 +1112,7 @@ public void TestCreateConversionEventNoAttributesNoValue() { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; + Config.Region = "ZZ"; var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, null); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); @@ -823,7 +1189,7 @@ public void TestCreateConversionEventWithAttributesNoValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -918,7 +1284,7 @@ public void TestCreateConversionEventNoAttributesWithValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1020,7 +1386,7 @@ public void TestCreateConversionEventWithAttributesWithValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1122,7 +1488,7 @@ public void TestCreateConversionEventNoAttributesWithInvalidValue() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1218,7 +1584,7 @@ public void TestConversionEventWithNumericTag() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1316,7 +1682,7 @@ public void TestConversionEventWithFalsyNumericAndRevenueValues() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1412,7 +1778,7 @@ public void TestConversionEventWithNumericValue1() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1507,7 +1873,7 @@ public void TestConversionEventWithRevenueValue1() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1609,7 +1975,7 @@ public void TestCreateConversionEventWithBucketingIDAttribute() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1727,7 +2093,7 @@ public void TestCreateImpressionEventWithBucketingIDAttribute() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1838,7 +2204,7 @@ public void TestCreateImpressionEventWhenBotFilteringIsProvidedInDatafile() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -1945,7 +2311,7 @@ public void TestCreateImpressionEventWhenBotFilteringIsNotProvidedInDatafile() { "anonymize_ip", false }, }; - var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var expectedLogEvent = new LogEvent(EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -2039,7 +2405,7 @@ public void TestCreateConversionEventWhenBotFilteringIsProvidedInDatafile() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -2128,7 +2494,7 @@ public void TestCreateConversionEventWhenBotFilteringIsNotProvidedInDatafile() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -2250,7 +2616,7 @@ public void TestCreateConversionEventWhenEventUsedInMultipleExp() var expectedLogEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary @@ -2358,7 +2724,7 @@ public void TestCreateConversionEventRemovesInvalidAttributesFromPayload() }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", + EventFactory.EventEndpoints["US"], payloadParams, "POST", new Dictionary diff --git a/OptimizelySDK.Tests/EventTests/TestForwardingEventDispatcher.cs b/OptimizelySDK.Tests/EventTests/TestForwardingEventDispatcher.cs index 01eca1ee..9b7cf533 100644 --- a/OptimizelySDK.Tests/EventTests/TestForwardingEventDispatcher.cs +++ b/OptimizelySDK.Tests/EventTests/TestForwardingEventDispatcher.cs @@ -18,7 +18,7 @@ public class TestForwardingEventDispatcher : IEventDispatcher public void DispatchEvent(LogEvent logEvent) { Assert.AreEqual(logEvent.HttpVerb, "POST"); - Assert.AreEqual(logEvent.Url, EventFactory.EVENT_ENDPOINT); + Assert.AreEqual(logEvent.Url, EventFactory.EventEndpoints["US"]); IsUpdated = true; } } diff --git a/OptimizelySDK.Tests/OptimizelyTest.cs b/OptimizelySDK.Tests/OptimizelyTest.cs index 0adb57ec..034b4bc0 100644 --- a/OptimizelySDK.Tests/OptimizelyTest.cs +++ b/OptimizelySDK.Tests/OptimizelyTest.cs @@ -3490,7 +3490,7 @@ public void TestTrackListener(UserAttributes userAttributes, EventTags eventTags var variation = Result.NewResult(Config.GetVariationFromKey(experimentKey, variationKey), DecisionReasons); - var logEvent = new LogEvent("https://logx.optimizely.com/v1/events", + var logEvent = new LogEvent(EventFactory.EventEndpoints["US"], OptimizelyHelper.SingleParameter, "POST", new Dictionary()); diff --git a/OptimizelySDK/Config/DatafileProjectConfig.cs b/OptimizelySDK/Config/DatafileProjectConfig.cs index cb248f8c..cf3701c8 100644 --- a/OptimizelySDK/Config/DatafileProjectConfig.cs +++ b/OptimizelySDK/Config/DatafileProjectConfig.cs @@ -832,5 +832,11 @@ public string ToDatafile() { return _datafile; } + + /// + /// Returns the datafile corresponding to ProjectConfig + /// + /// the datafile string corresponding to ProjectConfig + public string Region { get; set; } } } diff --git a/OptimizelySDK/Event/Builder/EventBuilder.cs b/OptimizelySDK/Event/Builder/EventBuilder.cs index 1d73ff94..0dfe4aa5 100644 --- a/OptimizelySDK/Event/Builder/EventBuilder.cs +++ b/OptimizelySDK/Event/Builder/EventBuilder.cs @@ -27,9 +27,6 @@ namespace OptimizelySDK.Event.Builder [Obsolete("This class is deprecated. Use 'OptimizelySDK.Event.EventFactory'.")] public class EventBuilder { - private const string IMPRESSION_ENDPOINT = "https://logx.optimizely.com/v1/events"; - - private const string CONVERSION_ENDPOINT = "https://logx.optimizely.com/v1/events"; private const string HTTP_VERB = "POST"; @@ -245,7 +242,9 @@ public virtual LogEvent CreateImpressionEvent(ProjectConfig config, Experiment e GetImpressionOrConversionParamsWithCommonParams(commonParams, new object[] { impressionOnlyParams }); - return new LogEvent(IMPRESSION_ENDPOINT, impressionParams, HTTP_VERB, HTTP_HEADERS); + var region = !string.IsNullOrEmpty(config.Region) ? config.Region: "US"; + + return new LogEvent(EventFactory.EventEndpoints[region], impressionParams, HTTP_VERB, HTTP_HEADERS); } @@ -270,8 +269,10 @@ public virtual LogEvent CreateConversionEvent(ProjectConfig config, string event var conversionParams = GetImpressionOrConversionParamsWithCommonParams(commonParams, conversionOnlyParams); + + var region = !string.IsNullOrEmpty(config.Region) ? config.Region: "US"; - return new LogEvent(CONVERSION_ENDPOINT, conversionParams, HTTP_VERB, HTTP_HEADERS); + return new LogEvent(EventFactory.EventEndpoints[region], conversionParams, HTTP_VERB, HTTP_HEADERS); } } } diff --git a/OptimizelySDK/Event/Entity/EventContext.cs b/OptimizelySDK/Event/Entity/EventContext.cs index 44b77644..ff2d5f58 100644 --- a/OptimizelySDK/Event/Entity/EventContext.cs +++ b/OptimizelySDK/Event/Entity/EventContext.cs @@ -40,6 +40,9 @@ public class EventContext [JsonProperty("anonymize_ip")] public bool AnonymizeIP { get; protected set; } + + [JsonProperty("region")] + public string Region { get; protected set; } /// /// EventContext builder @@ -50,6 +53,7 @@ public class Builder private string ProjectId; private string Revision; private bool AnonymizeIP; + private string Region; public Builder WithAccountId(string accountId) { @@ -74,6 +78,12 @@ public Builder WithAnonymizeIP(bool anonymizeIP) AnonymizeIP = anonymizeIP; return this; } + + public Builder WithRegion(string region) + { + Region = region; + return this; + } /// /// Build EventContext instance @@ -89,6 +99,7 @@ public EventContext Build() eventContext.ClientName = Optimizely.SDK_TYPE; eventContext.ClientVersion = Optimizely.SDK_VERSION; eventContext.AnonymizeIP = AnonymizeIP; + eventContext.Region = Region; return eventContext; } diff --git a/OptimizelySDK/Event/EventFactory.cs b/OptimizelySDK/Event/EventFactory.cs index 841b650f..2376a701 100644 --- a/OptimizelySDK/Event/EventFactory.cs +++ b/OptimizelySDK/Event/EventFactory.cs @@ -34,9 +34,15 @@ public class EventFactory { private const string CUSTOM_ATTRIBUTE_FEATURE_TYPE = "custom"; - public const string - EVENT_ENDPOINT = - "https://logx.optimizely.com/v1/events"; // Should be part of the datafile + // Supported regions for event endpoints + public static readonly string[] SupportedRegions = { "US", "EU" }; + + // Dictionary of event endpoints for different regions + public static readonly Dictionary EventEndpoints = new Dictionary + { + {"US", "https://logx.optimizely.com/v1/events"}, + {"EU", "https://eu.logx.optimizely.com/v1/events"} + }; private const string ACTIVATE_EVENT_KEY = "campaign_activated"; @@ -63,6 +69,10 @@ public static LogEvent CreateLogEvent(UserEvent[] userEvents, ILogger logger) var visitors = new List(userEvents.Count()); + + // Default to US region + string region = "US"; + foreach (var userEvent in userEvents) { if (userEvent is ImpressionEvent) @@ -80,6 +90,9 @@ public static LogEvent CreateLogEvent(UserEvent[] userEvents, ILogger logger) } var userContext = userEvent.Context; + + // Get region from the event's context, default to US if not specified + region = !string.IsNullOrEmpty(userContext.Region) ? userContext.Region : "US"; builder.WithClientName(userContext.ClientName). WithClientVersion(userContext.ClientVersion). @@ -102,7 +115,16 @@ public static LogEvent CreateLogEvent(UserEvent[] userEvents, ILogger logger) var eventBatchDictionary = JObject.FromObject(eventBatch).ToObject>(); - return new LogEvent(EVENT_ENDPOINT, eventBatchDictionary, "POST", + // Use the region to determine the endpoint URL, falling back to US if the region is not found or not supported + string endpointUrl = EventEndpoints["US"]; // Default to US endpoint + + // Only try to use the region-specific endpoint if it's a supported region + if (SupportedRegions.Contains(region) && EventEndpoints.ContainsKey(region)) + { + endpointUrl = EventEndpoints[region]; + } + + return new LogEvent(endpointUrl, eventBatchDictionary, "POST", new Dictionary { { "Content-Type", "application/json" }, diff --git a/OptimizelySDK/Event/UserEventFactory.cs b/OptimizelySDK/Event/UserEventFactory.cs index f073237a..28d6fb87 100644 --- a/OptimizelySDK/Event/UserEventFactory.cs +++ b/OptimizelySDK/Event/UserEventFactory.cs @@ -80,6 +80,7 @@ public static ImpressionEvent CreateImpressionEvent(ProjectConfig projectConfig, WithAccountId(projectConfig.AccountId). WithAnonymizeIP(projectConfig.AnonymizeIP). WithRevision(projectConfig.Revision). + WithRegion(projectConfig.Region). Build(); var variationKey = ""; @@ -123,6 +124,7 @@ EventTags eventTags WithAccountId(projectConfig.AccountId). WithAnonymizeIP(projectConfig.AnonymizeIP). WithRevision(projectConfig.Revision). + WithRegion(projectConfig.Region). Build(); return new ConversionEvent.Builder(). diff --git a/OptimizelySDK/ProjectConfig.cs b/OptimizelySDK/ProjectConfig.cs index 58272aa7..c8d29941 100644 --- a/OptimizelySDK/ProjectConfig.cs +++ b/OptimizelySDK/ProjectConfig.cs @@ -312,5 +312,10 @@ public interface ProjectConfig /// Returns the datafile corresponding to ProjectConfig /// string ToDatafile(); + + /// + /// Returns the datafile region to ProjectConfig + /// + string Region { get; set; } } } From 6d2e9bf22c456b622da5bdb88268681868cb4ee5 Mon Sep 17 00:00:00 2001 From: esrakartalOpt Date: Tue, 12 Aug 2025 10:52:37 -0500 Subject: [PATCH 2/8] Fix lint whitespace errors --- OptimizelySDK.Tests/EventTests/EventFactoryTest.cs | 14 +++++++------- OptimizelySDK/Event/Builder/EventBuilder.cs | 2 +- OptimizelySDK/Event/Entity/EventContext.cs | 4 ++-- OptimizelySDK/Event/EventFactory.cs | 5 ++--- OptimizelySDK/ProjectConfig.cs | 2 +- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs b/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs index 0fd2dfdd..8c839d67 100644 --- a/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs +++ b/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs @@ -153,7 +153,7 @@ public void TestCreateImpressionEventNoAttributesEU() { { "Content-Type", "application/json" }, }); - + Config.Region = "EU"; var impressionEvent = UserEventFactory.CreateImpressionEvent( Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, @@ -166,7 +166,7 @@ public void TestCreateImpressionEventNoAttributesEU() Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); } - + [Test] public void TestCreateImpressionEventNoAttributesInvalid() { @@ -254,7 +254,7 @@ public void TestCreateImpressionEventNoAttributesInvalid() { { "Content-Type", "application/json" }, }); - + Config.Region = "ZZ"; var impressionEvent = UserEventFactory.CreateImpressionEvent( Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, @@ -264,10 +264,10 @@ public void TestCreateImpressionEventNoAttributesInvalid() TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, Guid.Parse(impressionEvent.UUID)); - + Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); } - + [Test] public void TestCreateImpressionEventNoAttributes() { @@ -958,7 +958,7 @@ public void TestCreateConversionEventNoAttributesNoValue() Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } - + [Test] public void TestCreateConversionEventNoAttributesNoValueEU() { @@ -1040,7 +1040,7 @@ public void TestCreateConversionEventNoAttributesNoValueEU() Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } - + [Test] public void TestCreateConversionEventNoAttributesNoValueInvalid() { diff --git a/OptimizelySDK/Event/Builder/EventBuilder.cs b/OptimizelySDK/Event/Builder/EventBuilder.cs index 0dfe4aa5..9d631738 100644 --- a/OptimizelySDK/Event/Builder/EventBuilder.cs +++ b/OptimizelySDK/Event/Builder/EventBuilder.cs @@ -269,7 +269,7 @@ public virtual LogEvent CreateConversionEvent(ProjectConfig config, string event var conversionParams = GetImpressionOrConversionParamsWithCommonParams(commonParams, conversionOnlyParams); - + var region = !string.IsNullOrEmpty(config.Region) ? config.Region: "US"; return new LogEvent(EventFactory.EventEndpoints[region], conversionParams, HTTP_VERB, HTTP_HEADERS); diff --git a/OptimizelySDK/Event/Entity/EventContext.cs b/OptimizelySDK/Event/Entity/EventContext.cs index ff2d5f58..718deba6 100644 --- a/OptimizelySDK/Event/Entity/EventContext.cs +++ b/OptimizelySDK/Event/Entity/EventContext.cs @@ -40,7 +40,7 @@ public class EventContext [JsonProperty("anonymize_ip")] public bool AnonymizeIP { get; protected set; } - + [JsonProperty("region")] public string Region { get; protected set; } @@ -78,7 +78,7 @@ public Builder WithAnonymizeIP(bool anonymizeIP) AnonymizeIP = anonymizeIP; return this; } - + public Builder WithRegion(string region) { Region = region; diff --git a/OptimizelySDK/Event/EventFactory.cs b/OptimizelySDK/Event/EventFactory.cs index 2376a701..952494d2 100644 --- a/OptimizelySDK/Event/EventFactory.cs +++ b/OptimizelySDK/Event/EventFactory.cs @@ -69,7 +69,6 @@ public static LogEvent CreateLogEvent(UserEvent[] userEvents, ILogger logger) var visitors = new List(userEvents.Count()); - // Default to US region string region = "US"; @@ -90,7 +89,7 @@ public static LogEvent CreateLogEvent(UserEvent[] userEvents, ILogger logger) } var userContext = userEvent.Context; - + // Get region from the event's context, default to US if not specified region = !string.IsNullOrEmpty(userContext.Region) ? userContext.Region : "US"; @@ -117,7 +116,7 @@ public static LogEvent CreateLogEvent(UserEvent[] userEvents, ILogger logger) // Use the region to determine the endpoint URL, falling back to US if the region is not found or not supported string endpointUrl = EventEndpoints["US"]; // Default to US endpoint - + // Only try to use the region-specific endpoint if it's a supported region if (SupportedRegions.Contains(region) && EventEndpoints.ContainsKey(region)) { diff --git a/OptimizelySDK/ProjectConfig.cs b/OptimizelySDK/ProjectConfig.cs index c8d29941..8aab34f7 100644 --- a/OptimizelySDK/ProjectConfig.cs +++ b/OptimizelySDK/ProjectConfig.cs @@ -312,7 +312,7 @@ public interface ProjectConfig /// Returns the datafile corresponding to ProjectConfig /// string ToDatafile(); - + /// /// Returns the datafile region to ProjectConfig /// From 80d3455ffedd3158b8c1639885b88f5ec434eb08 Mon Sep 17 00:00:00 2001 From: esrakartalOpt Date: Tue, 12 Aug 2025 11:08:50 -0500 Subject: [PATCH 3/8] Fix lint errors --- OptimizelySDK/Config/DatafileProjectConfig.cs | 21 +++++++------------ OptimizelySDK/Event/Builder/EventBuilder.cs | 4 ++-- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/OptimizelySDK/Config/DatafileProjectConfig.cs b/OptimizelySDK/Config/DatafileProjectConfig.cs index cf3701c8..48f6cacb 100644 --- a/OptimizelySDK/Config/DatafileProjectConfig.cs +++ b/OptimizelySDK/Config/DatafileProjectConfig.cs @@ -103,7 +103,7 @@ public enum OPTLYSDKVersion public string Datafile { get; set; } /// - /// Configured host name for the Optimizely Data Platform. + /// Configured host name for the Optimizely Data Platform. /// public string HostForOdp { get; private set; } @@ -492,8 +492,7 @@ private static DatafileProjectConfig GetConfig(string configData) !(((int)supportedVersion).ToString() == config.Version))) { throw new ConfigParseException( - $@"This version of the C# SDK does not support the given datafile version: { - config.Version}"); + $@"This version of the C# SDK does not support the given datafile version: {config.Version}"); } return config; @@ -632,8 +631,7 @@ public Variation GetVariationFromKey(string experimentKey, string variationKey) return _VariationKeyMap[experimentKey][variationKey]; } - var message = $@"No variation key ""{variationKey - }"" defined in datafile for experiment ""{experimentKey}""."; + var message = $@"No variation key ""{variationKey}"" defined in datafile for experiment ""{experimentKey}""."; Logger.Log(LogLevel.ERROR, message); ErrorHandler.HandleError( new InvalidVariationException("Provided variation is not in datafile.")); @@ -655,8 +653,7 @@ public Variation GetVariationFromKeyByExperimentId(string experimentId, string v return _VariationKeyMapByExperimentId[experimentId][variationKey]; } - var message = $@"No variation key ""{variationKey - }"" defined in datafile for experiment ""{experimentId}""."; + var message = $@"No variation key ""{variationKey}"" defined in datafile for experiment ""{experimentId}""."; Logger.Log(LogLevel.ERROR, message); ErrorHandler.HandleError( new InvalidVariationException("Provided variation is not in datafile.")); @@ -678,8 +675,7 @@ public Variation GetVariationFromId(string experimentKey, string variationId) return _VariationIdMap[experimentKey][variationId]; } - var message = $@"No variation ID ""{variationId - }"" defined in datafile for experiment ""{experimentKey}""."; + var message = $@"No variation ID ""{variationId}"" defined in datafile for experiment ""{experimentKey}""."; Logger.Log(LogLevel.ERROR, message); ErrorHandler.HandleError( new InvalidVariationException("Provided variation is not in datafile.")); @@ -704,8 +700,7 @@ public Variation GetVariationFromIdByExperimentId(string experimentId, string va var message = $@"No variation ID ""{variationId }"" defined in datafile for experiment ""{experimentId}""."; Logger.Log(LogLevel.ERROR, message); - ErrorHandler.HandleError( - new InvalidVariationException("Provided variation is not in datafile.")); + ErrorHandler.HandleError(new InvalidVariationException("Provided variation is not in datafile.")); return new Variation(); } @@ -788,9 +783,7 @@ public string GetAttributeId(string attributeKey) if (hasReservedPrefix) { Logger.Log(LogLevel.WARN, - $@"Attribute {attributeKey} unexpectedly has reserved prefix { - RESERVED_ATTRIBUTE_PREFIX - }; using attribute ID instead of reserved attribute name."); + $@"Attribute {attributeKey} unexpectedly has reserved prefix {RESERVED_ATTRIBUTE_PREFIX}; using attribute ID instead of reserved attribute name."); } return attribute.Id; diff --git a/OptimizelySDK/Event/Builder/EventBuilder.cs b/OptimizelySDK/Event/Builder/EventBuilder.cs index 9d631738..0ac90e94 100644 --- a/OptimizelySDK/Event/Builder/EventBuilder.cs +++ b/OptimizelySDK/Event/Builder/EventBuilder.cs @@ -242,7 +242,7 @@ public virtual LogEvent CreateImpressionEvent(ProjectConfig config, Experiment e GetImpressionOrConversionParamsWithCommonParams(commonParams, new object[] { impressionOnlyParams }); - var region = !string.IsNullOrEmpty(config.Region) ? config.Region: "US"; + var region = !string.IsNullOrEmpty(config.Region) ? config.Region : "US"; return new LogEvent(EventFactory.EventEndpoints[region], impressionParams, HTTP_VERB, HTTP_HEADERS); } @@ -270,7 +270,7 @@ public virtual LogEvent CreateConversionEvent(ProjectConfig config, string event var conversionParams = GetImpressionOrConversionParamsWithCommonParams(commonParams, conversionOnlyParams); - var region = !string.IsNullOrEmpty(config.Region) ? config.Region: "US"; + var region = !string.IsNullOrEmpty(config.Region) ? config.Region : "US"; return new LogEvent(EventFactory.EventEndpoints[region], conversionParams, HTTP_VERB, HTTP_HEADERS); } From 29f76db90ba6a3aa38bc509685175073fb4dd53b Mon Sep 17 00:00:00 2001 From: esrakartalOpt Date: Tue, 12 Aug 2025 11:16:08 -0500 Subject: [PATCH 4/8] Fix last lint error --- OptimizelySDK/Config/DatafileProjectConfig.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OptimizelySDK/Config/DatafileProjectConfig.cs b/OptimizelySDK/Config/DatafileProjectConfig.cs index 48f6cacb..f97adb06 100644 --- a/OptimizelySDK/Config/DatafileProjectConfig.cs +++ b/OptimizelySDK/Config/DatafileProjectConfig.cs @@ -697,8 +697,7 @@ public Variation GetVariationFromIdByExperimentId(string experimentId, string va return _VariationIdMapByExperimentId[experimentId][variationId]; } - var message = $@"No variation ID ""{variationId - }"" defined in datafile for experiment ""{experimentId}""."; + var message = $@"No variation ID ""{variationId}"" defined in datafile for experiment ""{experimentId}""."; Logger.Log(LogLevel.ERROR, message); ErrorHandler.HandleError(new InvalidVariationException("Provided variation is not in datafile.")); return new Variation(); From 602d00d7236b674338dbb788a651cbb0a8486ebf Mon Sep 17 00:00:00 2001 From: esrakartalOpt Date: Tue, 12 Aug 2025 15:16:58 -0500 Subject: [PATCH 5/8] Implement copilot review comments --- OptimizelySDK/Config/DatafileProjectConfig.cs | 4 +++- OptimizelySDK/Event/Builder/EventBuilder.cs | 12 ++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/OptimizelySDK/Config/DatafileProjectConfig.cs b/OptimizelySDK/Config/DatafileProjectConfig.cs index f97adb06..465b384a 100644 --- a/OptimizelySDK/Config/DatafileProjectConfig.cs +++ b/OptimizelySDK/Config/DatafileProjectConfig.cs @@ -817,7 +817,9 @@ public bool IsFeatureExperiment(string experimentId) } /// - ///Returns the datafile corresponding to ProjectConfig + /// Gets or sets the region associated with the project configuration. + /// This typically indicates the data residency or deployment region (e.g., "us", "eu"). + /// Valid values depend on the Optimizely environment and configuration. /// /// the datafile string corresponding to ProjectConfig public string ToDatafile() diff --git a/OptimizelySDK/Event/Builder/EventBuilder.cs b/OptimizelySDK/Event/Builder/EventBuilder.cs index 0ac90e94..696bba43 100644 --- a/OptimizelySDK/Event/Builder/EventBuilder.cs +++ b/OptimizelySDK/Event/Builder/EventBuilder.cs @@ -242,9 +242,11 @@ public virtual LogEvent CreateImpressionEvent(ProjectConfig config, Experiment e GetImpressionOrConversionParamsWithCommonParams(commonParams, new object[] { impressionOnlyParams }); - var region = !string.IsNullOrEmpty(config.Region) ? config.Region : "US"; + var endpoint = EventFactory.EventEndpoints.ContainsKey(region) + ? EventFactory.EventEndpoints[region] + : EventFactory.EventEndpoints["US"]; - return new LogEvent(EventFactory.EventEndpoints[region], impressionParams, HTTP_VERB, HTTP_HEADERS); + return new LogEvent(endpoint, impressionParams, HTTP_VERB, HTTP_HEADERS); } @@ -270,9 +272,11 @@ public virtual LogEvent CreateConversionEvent(ProjectConfig config, string event var conversionParams = GetImpressionOrConversionParamsWithCommonParams(commonParams, conversionOnlyParams); - var region = !string.IsNullOrEmpty(config.Region) ? config.Region : "US"; + var endpoint = EventFactory.EventEndpoints.ContainsKey(region) + ? EventFactory.EventEndpoints[region] + : EventFactory.EventEndpoints["US"]; - return new LogEvent(EventFactory.EventEndpoints[region], conversionParams, HTTP_VERB, HTTP_HEADERS); + return new LogEvent(endpoint, conversionParams, HTTP_VERB, HTTP_HEADERS); } } } From c3da1206e8c912019dd3074714f2e45e6551cdb0 Mon Sep 17 00:00:00 2001 From: esrakartalOpt Date: Tue, 12 Aug 2025 15:25:03 -0500 Subject: [PATCH 6/8] Fix test error --- OptimizelySDK/Event/Builder/EventBuilder.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OptimizelySDK/Event/Builder/EventBuilder.cs b/OptimizelySDK/Event/Builder/EventBuilder.cs index 696bba43..752e38e3 100644 --- a/OptimizelySDK/Event/Builder/EventBuilder.cs +++ b/OptimizelySDK/Event/Builder/EventBuilder.cs @@ -242,6 +242,8 @@ public virtual LogEvent CreateImpressionEvent(ProjectConfig config, Experiment e GetImpressionOrConversionParamsWithCommonParams(commonParams, new object[] { impressionOnlyParams }); + var region = !string.IsNullOrEmpty(config.Region) ? config.Region : "US"; + var endpoint = EventFactory.EventEndpoints.ContainsKey(region) ? EventFactory.EventEndpoints[region] : EventFactory.EventEndpoints["US"]; @@ -272,6 +274,8 @@ public virtual LogEvent CreateConversionEvent(ProjectConfig config, string event var conversionParams = GetImpressionOrConversionParamsWithCommonParams(commonParams, conversionOnlyParams); + var region = !string.IsNullOrEmpty(config.Region) ? config.Region : "US"; + var endpoint = EventFactory.EventEndpoints.ContainsKey(region) ? EventFactory.EventEndpoints[region] : EventFactory.EventEndpoints["US"]; From 8841e89ff82f9138ba512f8a1503fac98f0c4674 Mon Sep 17 00:00:00 2001 From: esrakartalOpt Date: Thu, 14 Aug 2025 10:55:26 -0500 Subject: [PATCH 7/8] Implement comments --- OptimizelySDK/Event/Builder/EventBuilder.cs | 12 ++++-------- OptimizelySDK/Event/EventFactory.cs | 7 +++++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/OptimizelySDK/Event/Builder/EventBuilder.cs b/OptimizelySDK/Event/Builder/EventBuilder.cs index 752e38e3..1180b7ad 100644 --- a/OptimizelySDK/Event/Builder/EventBuilder.cs +++ b/OptimizelySDK/Event/Builder/EventBuilder.cs @@ -242,11 +242,9 @@ public virtual LogEvent CreateImpressionEvent(ProjectConfig config, Experiment e GetImpressionOrConversionParamsWithCommonParams(commonParams, new object[] { impressionOnlyParams }); - var region = !string.IsNullOrEmpty(config.Region) ? config.Region : "US"; + var region = !string.IsNullOrEmpty(config.Region) && EventFactory.EventEndpoints.ContainsKey(config.Region) ? config.Region : "US"; - var endpoint = EventFactory.EventEndpoints.ContainsKey(region) - ? EventFactory.EventEndpoints[region] - : EventFactory.EventEndpoints["US"]; + var endpoint = EventFactory.EventEndpoints[region] return new LogEvent(endpoint, impressionParams, HTTP_VERB, HTTP_HEADERS); } @@ -274,11 +272,9 @@ public virtual LogEvent CreateConversionEvent(ProjectConfig config, string event var conversionParams = GetImpressionOrConversionParamsWithCommonParams(commonParams, conversionOnlyParams); - var region = !string.IsNullOrEmpty(config.Region) ? config.Region : "US"; + var region = !string.IsNullOrEmpty(config.Region) && EventFactory.EventEndpoints.ContainsKey(config.Region) ? config.Region : "US"; - var endpoint = EventFactory.EventEndpoints.ContainsKey(region) - ? EventFactory.EventEndpoints[region] - : EventFactory.EventEndpoints["US"]; + var endpoint = EventFactory.EventEndpoints[region] return new LogEvent(endpoint, conversionParams, HTTP_VERB, HTTP_HEADERS); } diff --git a/OptimizelySDK/Event/EventFactory.cs b/OptimizelySDK/Event/EventFactory.cs index 952494d2..771e0f39 100644 --- a/OptimizelySDK/Event/EventFactory.cs +++ b/OptimizelySDK/Event/EventFactory.cs @@ -35,7 +35,7 @@ public class EventFactory private const string CUSTOM_ATTRIBUTE_FEATURE_TYPE = "custom"; // Supported regions for event endpoints - public static readonly string[] SupportedRegions = { "US", "EU" }; + public static string[] SupportedRegions => EventEndpoints.Keys.ToArray(); // Dictionary of event endpoints for different regions public static readonly Dictionary EventEndpoints = new Dictionary @@ -91,7 +91,10 @@ public static LogEvent CreateLogEvent(UserEvent[] userEvents, ILogger logger) var userContext = userEvent.Context; // Get region from the event's context, default to US if not specified - region = !string.IsNullOrEmpty(userContext.Region) ? userContext.Region : "US"; + if (!string.IsNullOrEmpty(userContext.Region)) + { + region = userContext.Region; + } builder.WithClientName(userContext.ClientName). WithClientVersion(userContext.ClientVersion). From 62127e2769787474e21cb6880c74ec329910c469 Mon Sep 17 00:00:00 2001 From: esrakartalOpt Date: Thu, 14 Aug 2025 10:59:22 -0500 Subject: [PATCH 8/8] Fix lint --- OptimizelySDK/Event/Builder/EventBuilder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OptimizelySDK/Event/Builder/EventBuilder.cs b/OptimizelySDK/Event/Builder/EventBuilder.cs index 1180b7ad..0dd4562a 100644 --- a/OptimizelySDK/Event/Builder/EventBuilder.cs +++ b/OptimizelySDK/Event/Builder/EventBuilder.cs @@ -244,7 +244,7 @@ public virtual LogEvent CreateImpressionEvent(ProjectConfig config, Experiment e var region = !string.IsNullOrEmpty(config.Region) && EventFactory.EventEndpoints.ContainsKey(config.Region) ? config.Region : "US"; - var endpoint = EventFactory.EventEndpoints[region] + var endpoint = EventFactory.EventEndpoints[region]; return new LogEvent(endpoint, impressionParams, HTTP_VERB, HTTP_HEADERS); } @@ -274,7 +274,7 @@ public virtual LogEvent CreateConversionEvent(ProjectConfig config, string event var region = !string.IsNullOrEmpty(config.Region) && EventFactory.EventEndpoints.ContainsKey(config.Region) ? config.Region : "US"; - var endpoint = EventFactory.EventEndpoints[region] + var endpoint = EventFactory.EventEndpoints[region]; return new LogEvent(endpoint, conversionParams, HTTP_VERB, HTTP_HEADERS); }