Initialize the C# SDK
Lists the steps required to initialize the Optimizely Feature Experimentation C# SDK in your application.
Use the builder to initialize the C# SDK and instantiate an instance of the Optimizely Feature Experimentation client class that exposes API methods like Decide methods.
Version
4.0.0-beta
Description
The constructor accepts a configuration object to configure Optimizely Feature Experimentation.
The SDK provides a default implementation, but you may want to override the optional parameters for your production environments. For example, you can override these to set up an error handler and logger to catch issues, an event dispatcher to manage network calls, and a User Profile Service to ensure sticky bucketing.
Parameters
The table below lists the required and optional parameters in C#.
Parameter | Type | Description |
---|---|---|
datafile optional | string | The JSON string representing the project. |
configManager optional | ProjectConfigManager | The project config manager provides the project config to the client. |
eventDispatcher optional | IEventDispatcher | An event handler to manage network calls. |
logger optional | ILogger | A logger implementation to log issues. |
errorHandler optional | IErrorHandler | An error handler object to handle errors. |
userProfileService optional | UserProfileService | A user profile service. |
skipJsonValidation optional | boolean | Specifies whether the JSON should be validated. Set to true to skip JSON validation on the schema, or false to perform validation. |
datafile_access_token optional | string | (Server-side only) An access token for Optimizely Feature Experimentation SDKs (in combination with an sdk key) to fetch the datafile from an authenticated endpoint. Find your datafile access token in the Optimizely app at Settings > Environments. Select your secure environment, and copy the Datafile access token. |
defaultDecideOptions optional | Array | Array of OptimizelyDecideOption enums. This parameter sets default decide options applied to all the Decide calls made during the lifetime of the Optimizely client. Additionally, you can pass options to individual Decide methods (does not override defaults). For details on decide options, see OptimizelyDecideOption. |
withOdpManager(OdpManager) | ** You must have the Optimizely Data Platform Advanced Audience Targeting integration enabled. |
Returns
Instantiates an instance of the Optimzely class.
Automatic datafile management (ADM)
Optimizely Feature Experimentation provides out-of-the-box functionality to dynamically manage datafiles (configuration files) on either the client or the server. The C# SDK provides default implementations of an Optimizely ProjectConfigManager
. The package also includes a factory class, OptimizelyFactory
, which you can use to instantiate the Optimizely Feature Experimentation SDK with the default configuration of HttpProjectConfigManager
.
Whenever the experiment configuration changes, the SDK uses automatic datafile management (ADM) to handle the change for you. In the C# SDK, you can provide either sdkKey
or datafile
or both.
- When initializing with just the SDK key, the SDK polls for datafile changes in the background at regular intervals.
- When initializing with just the datafile, the SDK does not poll for datafile changes in the background.
- When initializing with both the SDK key and datafile, the SDK uses the given datafile and start polling for datafile changes in the background.
Basic example
The following code example shows basic C# ADM usage.
using OptimizelySDK;
public class App
{
public static void Main(string[] args)
{
var sdkKey = args[0];
var optimizely = OptimizelyFactory.NewDefaultInstance(sdkKey);
}
}
Advanced examples
Important
When you configure a logger, you should pass it into the
ProjectConfigManager
instance as well.
In the C# SDK, you only need to pass the SDK key value to instantiate a client. Whenever the experiment configuration changes, the SDK handles the change for you.
Include sdkKey
as a string property in the options object you pass to the CreateInstance
method.
When you provide the sdkKey
, the SDK instance downloads the datafile associated with that sdkKey
. When the download completes, the SDK instance updates itself to use the downloaded datafile.
Important
Pass all components (
Logger
,ErrorHandler
,NotificationCenter
) to the Optimizely Feature Experimentation constructor. Not passing a component fails to enable its respective functionality. In other words, components only work when passed to the constructor.
// Initialize with SDK key and default configuration
var sdkKey = "<Your_SDK_Key>" // replace with your SDK Key
var optimizely = OptimizelyFactory.newDefaultInstance(sdkKey);
// You can also customize the SDK instance with custom configuration. In this example we are customizing the project config manager to poll every 5 minutes for the datafile.
var projectConfigManager = new HttpProjectConfigManager.Builder()
.WithSdkKey(sdkKey)
.WithPollingInterval(TimeSpan.FromMinutes(5))
// .WithLogger(logger) // needed if you are configuring a logger
// .WithErrorHandler(errorHandler) // needed if you are configuring an error handler
// .WithNotificationCenter(notificationCenter) // needed if you are subscribing config update
.Build();
var Optimizely = new Optimizely(projectConfigManager);
// Initialize with Logger
// var Optimizely = new Optimizely(projectConfigManager, logger: logger);
// Initialize with Logger, ErrorHandler
// var Optimizely = new Optimizely(projectConfigManager, errorHandler: errorHandler, logger: logger);
// Initialize with NotificationCenter, Logger, ErrorHandler
// var Optimizely = new Optimizely(projectConfigManager, notificationCenter: NotificationCenter, errorHandler: errorHandler, logger: logger);
// Note: Use OptimizelyFactory NewDefaultInstance method to use same logger, errorHandler and notificationCenter for all of its Components (Optimizely, EventProcessor, HttpProjectConfigManager)
Here is a code example showing advanced configuration for C# ADM. The sections below describes advanced configuration properties. This advanced example shows how to construct the individual components directly to override various configurations. This gives you full control over which implementations to use and how to use them.
using OptimizelySDK;
using OptimizelySDK.Config;
public class App
{
public static void Main(string[] args)
{
var sdkKey = args[0];
// You can also use your own implementation of the ProjectConfigManager interface
var projectConfigManager = new HttpProjectConfigManager.Builder()
.WithSdkKey(sdkKey)
.WithPollingInterval(TimeSpan.FromMinutes(1))
.Build();
var optimizely = new Optimizely(projectConfigManager);
}
}
HttpProjectConfigManager
HttpProjectConfigManager is an implementation of the abstract PollingProjectConfigManager. The Poll
method is extended and makes an HTTP GET
request to the configured URL to asynchronously download the project datafile and initialize an instance of the ProjectConfig
.
By default, HttpProjectConfigManager
blocks until the first successful datafile retrieval, up to a configurable timeout. Set the frequency of the polling method and the blocking timeout with HttpProjectConfigManager.Builder
.
var projectConfigManager = new HttpProjectConfigManager.Builder()
.WithSdkKey(sdkKey)
.WithPollingInterval(TimeSpan.FromMinutes(1))
.Build();
SDK key
The SDK key composes the outbound HTTP request to the default datafile location on the Optimizely CDN.
Polling interval
The polling interval specifies a fixed delay between consecutive HTTP requests for the datafile, using any range supported by Timespan
.
Initial datafile
You can provide an initial datafile via the builder to bootstrap the ProjectConfigManager
, allowing you to use it immediately without blocking execution. The initial datafile also serves as a fallback datafile if an HTTP connection cannot be established. This is useful in mobile environments, where internet connectivity is not guaranteed.
The SDK discards the initial datafile after the first successful datafile poll.
Builder methods
Use the following builder methods to customize the HttpProjectConfigManager
configuration.
Property | Default value | Description |
---|---|---|
WithDatafile(string) | null | Initial datafile, typically sourced from a local cached source |
WithUrl(string) | null | URL override location used to specify custom HTTP source for the Optimizely datafile |
WithFormat(string) | null | Parameterized datafile URL by SDK key |
WithPollingInterval(TimeSpan) | 5 minutes | Fixed delay between fetches for the datafile |
WithBlockingTimeoutPeriod(TimeSpan) | 15 seconds | Maximum time to wait for initial bootstrapping. The valid timeout duration is 1 to 4294967294 milliseconds. |
WithSdkKey(string) | null | Optimizely Feature Experimentation project SDK key; required unless source URL is overridden |
Update config notifications
The SDK triggers a notification signal after fetching a new datatfile. To subscribe to these notifications, use method NotificationCenter.AddNotification()
.
optimizely.NotificationCenter.AddNotification(
NotificationCenter.NotificationType.OptimizelyConfigUpdate,
() => Console.WriteLine("Received new datafile configuration"));
Note
You must set up the Optimizely Data Platform Audience Targeting integration between Optimizely Data Platform (ODP) and Optimizely Feature Experimentation to use
odpManager
.
// Continuing from above.
var yourCustomEventQueue = new BlockingCollection<object>(Constants.DEFAULT_QUEUE_CAPACITY);
var eventManager = new OdpEventManager.Builder()
.WithEventQueue(yourCustomEventQueue)
.WithOdpEventApiManager(eventApiManager)
.WithFlushInterval(TimeSpan.FromMinutes(3))
.WithTimeoutInterval(TimeSpan.FromSeconds(5))
.WithAutoStart(true)
.WithLogger(logger)
.WithErrorHandler(errorHandler)
.Build();
OptimizelyFactory
OptimizelyFactory provides basic utility to instantiate the Optimizely Feature Experimentation SDK with a minimal number of configuration options.
OptimizelyFactory
does not capture all configuration and initialization options. For more use cases, build the resources with their constructors.
You must provide the SDK key at runtime, directly via the factory method:
var optimizely = OptimizelyFactory.NewDefaultInstance("<Your_SDK_Key>");
Instantiate using datafile
You can also instantiate with a hard-coded datafile. If you do not pass in an SDK key, the Optimizely Client does not automatically sync newer versions of the datafile. Any time you retrieve an updated datafile, just re-instantiate the same client.
To instantiate a client for simple applications, provide a datafile specifying the project configuration for a given environment. For most advanced implementations, you should customize the logger or error handler for your specific requirements.
using OptimizelySDK;
// Instantiate an Optimizely client
var datafile = "<Your_Datafile_JSON_string>"
var OptimizelyClient = new Optimizely(datafile);
Use authenticated datafile in a secure environment
Note
Secure datafiles are in beta. Contact your Customer Success Manager if you are interested in becoming an early user of authenticated datafiles as part of the beta secure environment feature.
You can fetch the datafile from an authenticated endpoint using a server-side (only) Optimizely Feature Experimentation SDK. To use an authenticated datafile, download your environment's access token from the Optimizely app at Settings>Environments. Select your secure environment, and copy the Datafile access token. The example below shows how to initialize the Optimizely client using an access token and sdk_key, enabling the client to fetch the authenticated datafile and complete initialization.
// fetch the datafile from an authenticated endpoint
var datafileAccessToken = "<Your_Datafile_Access_Token>"
var sdkKey = "<Your_SDK_Key>"
var optimizelyClient = OptimizelyFactory.NewDefaultInstance(sdkKey, null, datafileAccessToken);
OdpManager
OdpManager
contains all the logic supporting Optimizely Data Platform (ODP)-related features, including audience segments.
Note
Advanced Audience Targeting is currently in beta. Contact your Customer Success Manager for more information or register now on Optimizely.com.
OdpSegmentManager
This module provides an interface to the remote ODP server for audience segment mappings.
It fetches all qualified segments for the given user context and returns them as a string array in the completion handler.
It also manages a segment's cache shared for all user contexts. The cache is in memory (not persistent), and a device reboot or app termination resets it.
OdpEventManager
This module provides an interface to the remote ODP server for events.
It queues all pending events (persistent) and sends them (in batches of up to 10) to the ODP server when all resources are available, including network connection and ODP public key (in the SDK's datafile).
Note
The C# SDK tries to dispatch all events (stored in a persistent queue and retried on recoverable errors) but does not guarantee completion.
using OptimizelySDK.ErrorHandler;
using OptimizelySDK.Logger;
using OptimizelySDK.Odp;
var logger = new DefaultLogger();
var errorHandler = new DefaultErrorHandler();
var httpClient = new HttpClient(); // or your own implementation of HttpClient
var segmentApiManager = new OdpSegmentApiManager(logger, errorHandler, httpClient);
var segmentManager = new OdpSegmentManager(
segmentApiManager,
cacheSize: 10_000, // default is 10_000
itemTimeout: TimeSpan.FromMinutes(10), // default is 10 minutes
logger);
var eventManager = new OdpEventManager.Builder().WithLogger(logger)
.WithErrorHandler(errorHandler)
// Optional. We suggest a BlockingCollection or your own thread-safe collection
// .WithEventQueue(new BlockingCollection<object>(10_000))
// Optional. If you choose to control the httpClient, you must also implement your own
// .WithOdpEventApiManager(new OdpEventApiManager(logger, errorHandler, httpClient))
.Build();
var odpManager = new OdpManager.Builder()
.WithSegmentManager(segmentManager)
.WithEventManager(eventManager)
.WithLogger(logger)
.WithErrorHandler(errorHandler)
.Build();
Customize OdpSegmentApiManager
When provided, OdpSegmentApiManager
allows for customization.
using OptimizelySDK.ErrorHandler;
using OptimizelySDK.Logger;
using OptimizelySDK.Odp;
var logger = new DefaultLogger();
var errorHandler = new DefaultErrorHandler();
var yourCustomHttpClient = new HttpClient();
var segmentApiManager = new OdpSegmentApiManager(logger, errorHandler, yourCustomHttpClient);
Customize OdpSegmentManager
You can provide your customized OdpSegmentApiManager
to the OdpSegmentManager
along with different values for cache size and item timeouts.
// Continuing from above.
var segmentManager = new OdpSegmentManager(
apiManager: segmentApiManager,
cacheSize: Constants.DEFAULT_MAX_CACHE_SIZE,
itemTimeout: TimeSpan.FromSeconds(Constants.DEFAULT_CACHE_SECONDS),
logger: logger);
Custom cache
You can use a custom caching mechanism for the OdpSegmentManager
to store the FetchQualifiedSegments
results. To provide a custom cache, you have to implement the ICache
interface or use our LruCache
.
// Continuing from above.
var segmentApiManager = new OdpSegmentApiManager(logger, errorHandler, yourCustomHttpClient);
var yourCustomSegmentCache = new LruCache<List<string>>();
var segmentManager = new OdpSegmentManager(
apiManager: segmentApiManager,
cache: yourCustomSegmentCache,
logger: logger);
Customize OdpEventApiManager
When created, OdpEventApiManager
allows for customization.
// Continuing from above.
var eventApiManager = new OdpEventApiManager(logger, errorHandler, yourCustomHttpClient);
Customize OdpEventManager
You can provide your customized Event API Manager to the OdpEventManager
along with adjusting flush interval, timeout interval, and auto-starting queue processing.
// Continuing from above.
var yourCustomEventQueue = new BlockingCollection<object>(Constants.DEFAULT_QUEUE_CAPACITY);
var eventManager = new OdpEventManager.Builder()
.WithEventQueue(yourCustomEventQueue)
.WithOdpEventApiManager(eventApiManager)
.WithFlushInterval(TimeSpan.FromMinutes(3))
.WithTimeoutInterval(TimeSpan.FromSeconds(5))
.WithAutoStart(true)
.WithLogger(logger)
.WithErrorHandler(errorHandler)
.Build();
Source files
The language/platform source files containing the implementation for C# are at Optimizely.cs.
Updated 5 days ago