diff --git a/OptimizelySDK.Net40/OptimizelySDK.Net40.csproj b/OptimizelySDK.Net40/OptimizelySDK.Net40.csproj
index 8f9b63b5..376c3828 100644
--- a/OptimizelySDK.Net40/OptimizelySDK.Net40.csproj
+++ b/OptimizelySDK.Net40/OptimizelySDK.Net40.csproj
@@ -39,6 +39,7 @@
+
@@ -230,6 +231,9 @@
Config\PollingProjectConfigManager
+
+
+ ClientConfigHandler
Config\HttpProjectConfigManager
diff --git a/OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj b/OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj
index 35e8e8b6..b4ca1a8a 100644
--- a/OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj
+++ b/OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj
@@ -1,4 +1,4 @@
-
+
netstandard2.0
@@ -72,6 +72,9 @@
Config\ProjectConfigManager.cs
+
+
+ Config\ClientConfigHandler.cs
Entity\Attribute.cs
@@ -257,6 +260,7 @@
+
diff --git a/OptimizelySDK.Tests/App.config b/OptimizelySDK.Tests/App.config
index e629f34e..efdfcc4f 100644
--- a/OptimizelySDK.Tests/App.config
+++ b/OptimizelySDK.Tests/App.config
@@ -4,10 +4,31 @@
that apply only to the Test project.
-->
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OptimizelySDK.Tests/ClientConfigHandlerTest.cs b/OptimizelySDK.Tests/ClientConfigHandlerTest.cs
new file mode 100644
index 00000000..be8adda6
--- /dev/null
+++ b/OptimizelySDK.Tests/ClientConfigHandlerTest.cs
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019, Optimizely
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if !NETSTANDARD1_6 && !NET35
+
+using NUnit.Framework;
+using System.Configuration;
+
+namespace OptimizelySDK.Tests
+{
+ [TestFixture]
+ public class ClientConfigHandlerTest
+ {
+
+ [Test]
+ public void TestHTTPAppConfigSection()
+ {
+ var configSection = ConfigurationManager.GetSection("optlySDKConfigSection") as OptimizelySDKConfigSection;
+ var httpSetting = configSection.HttpProjectConfig;
+ Assert.IsNotNull(httpSetting);
+ Assert.IsTrue(httpSetting.AutoUpdate);
+ Assert.AreEqual(httpSetting.BlockingTimeOutPeriod, 10000);
+ Assert.AreEqual(httpSetting.Format, "https://cdn.optimizely.com/data/{0}.json");
+ Assert.IsTrue(httpSetting.DefaultStart);
+ Assert.AreEqual(httpSetting.PollingInterval, 2000);
+ Assert.AreEqual(httpSetting.SDKKey, "43214321");
+ Assert.AreEqual(httpSetting.Url, "www.testurl.com");
+ }
+
+ [Test]
+ public void TestBatchEventAppConfigSection()
+ {
+ var configSection = ConfigurationManager.GetSection("optlySDKConfigSection") as OptimizelySDKConfigSection;
+ var batchSetting = configSection.BatchEventProcessor;
+ Assert.IsNotNull(batchSetting);
+ Assert.AreEqual(batchSetting.BatchSize, 10);
+ Assert.AreEqual(batchSetting.FlushInterval, 2000);
+ Assert.AreEqual(batchSetting.TimeoutInterval, 10000);
+ Assert.IsTrue(batchSetting.DefaultStart);
+ }
+
+ }
+}
+#endif
diff --git a/OptimizelySDK.Tests/ConfigTest/HttpProjectConfigManagerTest.cs b/OptimizelySDK.Tests/ConfigTest/HttpProjectConfigManagerTest.cs
index b7bea2e3..ffe3229d 100644
--- a/OptimizelySDK.Tests/ConfigTest/HttpProjectConfigManagerTest.cs
+++ b/OptimizelySDK.Tests/ConfigTest/HttpProjectConfigManagerTest.cs
@@ -55,6 +55,22 @@ public void TestHttpConfigManagerRetreiveProjectConfigByURL()
Assert.NotNull(httpManager.GetConfig());
}
+ [Test]
+ public void TestHttpConfigManagerRetreiveProjectConfigGivenEmptyFormatUseDefaultFormat()
+ {
+ HttpProjectConfigManager httpManager = new HttpProjectConfigManager.Builder()
+ .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z")
+ .WithFormat("")
+ .WithLogger(LoggerMock.Object)
+ .WithPollingInterval(TimeSpan.FromMilliseconds(1000))
+ .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500))
+ .WithStartByDefault()
+ .Build();
+
+ httpManager.OnReady().Wait(System.Threading.Timeout.Infinite);
+ Assert.NotNull(httpManager.GetConfig());
+ }
+
[Test]
public void TestHttpConfigManagerRetreiveProjectConfigBySDKKey()
{
diff --git a/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj b/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj
index 85e05edc..c777eb91 100644
--- a/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj
+++ b/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj
@@ -86,6 +86,7 @@
+
diff --git a/OptimizelySDK/ClientConfigHandler.cs b/OptimizelySDK/ClientConfigHandler.cs
new file mode 100644
index 00000000..a32bea97
--- /dev/null
+++ b/OptimizelySDK/ClientConfigHandler.cs
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2019, Optimizely
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Configuration;
+
+namespace OptimizelySDK
+{
+ public class HttpProjectConfigElement : ConfigurationElement
+ {
+ [ConfigurationProperty("sdkKey", IsRequired = true, IsKey = true)]
+ public string SDKKey
+ {
+ get { return (string)base["sdkKey"]; }
+ }
+
+ [ConfigurationProperty("url")]
+ public string Url
+ {
+ get { return (string)base["url"]; }
+ }
+
+ [ConfigurationProperty("format")]
+ public string Format
+ {
+ get { return (string)base["format"]; }
+ }
+
+ [ConfigurationProperty("pollingInterval")]
+ public int PollingInterval
+ {
+ get { return base["pollingInterval"] is int ? (int)base["pollingInterval"] : 0; }
+ }
+
+ [ConfigurationProperty("blockingTimeOutPeriod")]
+ public int BlockingTimeOutPeriod
+ {
+ get { return base["blockingTimeOutPeriod"] is int ? (int)base["blockingTimeOutPeriod"] : 0; }
+ }
+
+ [ConfigurationProperty("autoUpdate")]
+ public bool AutoUpdate
+ {
+ get { return (bool)base["autoUpdate"]; }
+ }
+
+ [ConfigurationProperty("defaultStart")]
+ public bool DefaultStart
+ {
+ get { return (bool)base["defaultStart"]; }
+ }
+ }
+
+ public class BatchEventProcessorElement : ConfigurationElement
+ {
+ [ConfigurationProperty("batchSize")]
+ public int BatchSize
+ {
+ get { return (int)base["batchSize"]; }
+ }
+
+ [ConfigurationProperty("flushInterval")]
+ public int FlushInterval
+ {
+ get { return base["flushInterval"] is int ? (int)base["flushInterval"] : 0; }
+ }
+
+ [ConfigurationProperty("timeoutInterval")]
+ public int TimeoutInterval
+ {
+ get { return base["timeoutInterval"] is int ? (int)base["timeoutInterval"] : 0; }
+ }
+
+ [ConfigurationProperty("defaultStart")]
+ public bool DefaultStart
+ {
+ get { return (bool)base["defaultStart"]; }
+ }
+ }
+
+ public class OptimizelySDKConfigSection : ConfigurationSection
+ {
+ [ConfigurationProperty("HttpProjectConfig")]
+ public HttpProjectConfigElement HttpProjectConfig
+ {
+ get { return (HttpProjectConfigElement)base["HttpProjectConfig"]; }
+ set { base["HttpProjectConfig"] = value; }
+ }
+
+ [ConfigurationProperty("BatchEventProcessor")]
+ public BatchEventProcessorElement BatchEventProcessor {
+ get { return (BatchEventProcessorElement)(base["BatchEventProcessor"]); }
+ set { base["BatchEventProcessor"] = value; }
+ }
+ }
+}
diff --git a/OptimizelySDK/Config/HttpProjectConfigManager.cs b/OptimizelySDK/Config/HttpProjectConfigManager.cs
index 8768a69e..22a0d20d 100644
--- a/OptimizelySDK/Config/HttpProjectConfigManager.cs
+++ b/OptimizelySDK/Config/HttpProjectConfigManager.cs
@@ -124,11 +124,12 @@ public class Builder
private const long MAX_MILLISECONDS_LIMIT = 4294967294;
private readonly TimeSpan DEFAULT_PERIOD = TimeSpan.FromMinutes(5);
private readonly TimeSpan DEFAULT_BLOCKINGOUT_PERIOD = TimeSpan.FromSeconds(15);
+ private readonly string DEFAULT_FORMAT = "https://cdn.optimizely.com/datafiles/{0}.json";
private string Datafile;
private string SdkKey;
private string Url;
- private string Format = "https://cdn.optimizely.com/datafiles/{0}.json";
+ private string Format;
private ILogger Logger;
private IErrorHandler ErrorHandler;
private TimeSpan Period;
@@ -247,6 +248,10 @@ public HttpProjectConfigManager Build(bool defer)
if (ErrorHandler == null)
ErrorHandler = new DefaultErrorHandler();
+ if (string.IsNullOrEmpty(Format)) {
+ Format = DEFAULT_FORMAT;
+ }
+
if (string.IsNullOrEmpty(Url) && string.IsNullOrEmpty(SdkKey))
{
ErrorHandler.HandleError(new Exception("SdkKey cannot be null"));
diff --git a/OptimizelySDK/OptimizelyFactory.cs b/OptimizelySDK/OptimizelyFactory.cs
index 559646e7..e077b412 100644
--- a/OptimizelySDK/OptimizelyFactory.cs
+++ b/OptimizelySDK/OptimizelyFactory.cs
@@ -14,6 +14,10 @@
* limitations under the License.
*/
using System;
+#if !NETSTANDARD1_6 && !NET35
+using System.Configuration;
+#endif
+
using OptimizelySDK.Bucketing;
using OptimizelySDK.Config;
using OptimizelySDK.ErrorHandler;
@@ -32,6 +36,7 @@ public static class OptimizelyFactory
private static int MaxEventBatchSize;
private static TimeSpan MaxEventFlushInterval;
private static ILogger OptimizelyLogger;
+ private const string ConfigSectionName = "optlySDKConfigSection";
#if !NETSTANDARD1_6 && !NET35
public static void SetBatchSize(int batchSize)
@@ -48,7 +53,61 @@ public static void SetLogger(ILogger logger)
{
OptimizelyLogger = logger;
}
+
+ public static Optimizely NewDefaultInstance()
+ {
+ var logger = OptimizelyLogger ?? new DefaultLogger();
+ OptimizelySDKConfigSection OptlySDKConfigSection = null;
+ try
+ {
+ OptlySDKConfigSection = ConfigurationManager.GetSection(ConfigSectionName) as OptimizelySDKConfigSection;
+ }
+ catch (ConfigurationErrorsException ex)
+ {
+ logger.Log(LogLevel.ERROR, "Invalid App.Config. Unable to initialize optimizely instance" + ex.Message);
+ return null;
+ }
+
+ HttpProjectConfigElement httpProjectConfigElement = OptlySDKConfigSection.HttpProjectConfig;
+
+ if (httpProjectConfigElement == null) return null;
+
+ var errorHandler = new DefaultErrorHandler();
+ var eventDispatcher = new DefaultEventDispatcher(logger);
+ var builder = new HttpProjectConfigManager.Builder();
+ var notificationCenter = new NotificationCenter();
+
+ var configManager = builder
+ .WithSdkKey(httpProjectConfigElement.SDKKey)
+ .WithUrl(httpProjectConfigElement.Url)
+ .WithFormat(httpProjectConfigElement.Format)
+ .WithPollingInterval(TimeSpan.FromMilliseconds(httpProjectConfigElement.PollingInterval))
+ .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(httpProjectConfigElement.BlockingTimeOutPeriod))
+ .WithLogger(logger)
+ .WithErrorHandler(errorHandler)
+ .WithNotificationCenter(notificationCenter)
+ .Build(true);
+
+ EventProcessor eventProcessor = null;
+
+ var batchEventProcessorElement = OptlySDKConfigSection.BatchEventProcessor;
+
+ if (batchEventProcessorElement == null) return null;
+
+ eventProcessor = new BatchEventProcessor.Builder()
+ .WithMaxBatchSize(batchEventProcessorElement.BatchSize)
+ .WithFlushInterval(TimeSpan.FromMilliseconds(batchEventProcessorElement.FlushInterval))
+ .WithTimeoutInterval(TimeSpan.FromMilliseconds(batchEventProcessorElement.TimeoutInterval))
+ .WithLogger(logger)
+ .WithEventDispatcher(eventDispatcher)
+ .WithNotificationCenter(notificationCenter)
+ .Build();
+
+ return NewDefaultInstance(configManager, notificationCenter, eventDispatcher, errorHandler, logger, eventProcessor: eventProcessor);
+
+ }
#endif
+
public static Optimizely NewDefaultInstance(string sdkKey)
{
return NewDefaultInstance(sdkKey, null);
@@ -70,12 +129,6 @@ public static Optimizely NewDefaultInstance(string sdkKey, string fallback)
.WithNotificationCenter(notificationCenter)
.Build(true);
- return NewDefaultInstance(configManager, notificationCenter, eventDispatcher, errorHandler, logger);
- }
-
- public static Optimizely NewDefaultInstance(ProjectConfigManager configManager, NotificationCenter notificationCenter = null, IEventDispatcher eventDispatcher = null,
- IErrorHandler errorHandler = null, ILogger logger = null, UserProfileService userprofileService = null)
- {
EventProcessor eventProcessor = null;
#if !NETSTANDARD1_6 && !NET35
@@ -87,6 +140,13 @@ public static Optimizely NewDefaultInstance(ProjectConfigManager configManager,
.WithNotificationCenter(notificationCenter)
.Build();
#endif
+
+ return NewDefaultInstance(configManager, notificationCenter, eventDispatcher, errorHandler, logger, eventProcessor: eventProcessor);
+ }
+
+ public static Optimizely NewDefaultInstance(ProjectConfigManager configManager, NotificationCenter notificationCenter = null, IEventDispatcher eventDispatcher = null,
+ IErrorHandler errorHandler = null, ILogger logger = null, UserProfileService userprofileService = null, EventProcessor eventProcessor = null)
+ {
return new Optimizely(configManager, notificationCenter, eventDispatcher, logger, errorHandler, userprofileService, eventProcessor);
}
}
diff --git a/OptimizelySDK/OptimizelySDK.csproj b/OptimizelySDK/OptimizelySDK.csproj
index ebda9ab5..2d1593be 100644
--- a/OptimizelySDK/OptimizelySDK.csproj
+++ b/OptimizelySDK/OptimizelySDK.csproj
@@ -51,6 +51,7 @@
True
+
@@ -70,6 +71,7 @@
+
diff --git a/README.md b/README.md
index a14d612c..68c4cf35 100644
--- a/README.md
+++ b/README.md
@@ -90,6 +90,42 @@ You can also provide default datafile with the SDK key.
```
Optimizely optimizely = OptimizelyFactory.newDefaultInstance(<>, <>);
```
+##### Using App.config in OptimizelyFactory
+
+OptimizelyFactory provides support of setting configuration variables in App.config:
+User can provide variables using following procedure:
+1. In App.config file of your project in **** add following:
+```
+
+
+
+```
+2. Now add **optlySDKConfigSection** below ****. In this section you can add and set following **HttpProjectConfigManager** and **BatchEventProcessor** variables:
+```
+
+
+
+
+
+
+
+
+
+```
+3. After setting these variables you can instantiate the Optimizely SDK using function:
+```
+Optimizely optimizely = OptimizelyFactory.newDefaultInstance();
+```
#### HttpProjectConfigManager