From 85507eaed72227ac206c18f6fb7173f3c27a7202 Mon Sep 17 00:00:00 2001 From: Muhammad Noman Date: Wed, 23 Aug 2023 21:21:03 +0500 Subject: [PATCH] Converted all the files into proper md file format --- .../csharp-sdk/010 - install-sdk-csharp.md | 18 +- .../csharp-sdk/010 -install-sdk-csharp.md | 19 +- .../csharp-sdk/020 - initialize-sdk-csharp.md | 331 +++++++------- .../csharp-sdk/030 - example-usage-csharp.md | 36 +- .../040 - optimizelyconfig-csharp.md | 127 ++++-- .../050 - implement-a-user-profile-csharp.md | 83 ++-- ...060 - configure-event-dispatcher-csharp.md | 53 ++- .../csharp-sdk/070 - event-batching-csharp.md | 251 +++++------ .../080 - customize-logger-csharp.md | 75 ++-- .../090 - customize-error-handler-csharp.md | 29 +- ...00 - pass-in-audience-attributes-csharp.md | 27 +- ...0 - set-up-notification-listener-csharp.md | 137 +++--- .../csharp-sdk/120 - activate-csharp.md | 161 +++---- .../130 - get-enabled-features-csharp.md | 85 ++-- .../140 - get-feature-variable-csharp.md | 187 +++----- .../150 - get-forced-variation-csharp.md | 93 ++-- .../csharp-sdk/160 - get-variation-csharp.md | 404 +++++++++--------- .../170 - is-feature-enabled-csharp.md | 109 ++--- .../180 - set-forced-variation-csharp.md | 111 ++--- .../csharp-sdk/190 - track-csharp.md | 176 +++----- .../sdk-reference-guides/csharp-sdk/index.md | 5 +- 21 files changed, 1146 insertions(+), 1371 deletions(-) diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/010 - install-sdk-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/010 - install-sdk-csharp.md index 8b17af31..cf1a3085 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/010 - install-sdk-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/010 - install-sdk-csharp.md @@ -5,20 +5,12 @@ hidden: false createdAt: "2019-09-11T13:55:51.015Z" updatedAt: "2019-09-11T13:58:07.201Z" --- -TEST CHANGE The C# SDK is distributed through NuGet. For Windows, to install, run the command `Install-Package Optimizely.SDK` in the Package Manager Console: -[block:code] -{ - "codes": [ - { - "code": "PM> Install-Package Optimizely.SDK -Version 3.0.0\n\n", - "language": "shell", - "name": "Install the SDK" - } - ] -} -[/block] -The package is on NuGet at https://www.nuget.org/packages/Optimizely.SDK. The full source code is at https://github.com/optimizely/csharp-sdk. \ No newline at end of file + +```shell +PM> Install-Package Optimizely.SDK -Version 3.0.0 +``` +The package is on NuGet at https://www.nuget.org/packages/Optimizely.SDK. The full source code is at https://github.com/optimizely/csharp-sdk. diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/010 -install-sdk-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/010 -install-sdk-csharp.md index e02ebfae..ce278628 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/010 -install-sdk-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/010 -install-sdk-csharp.md @@ -5,18 +5,13 @@ hidden: false createdAt: "2019-09-11T13:55:51.015Z" updatedAt: "2019-09-11T13:58:07.201Z" --- + The C# SDK is distributed through NuGet. For Windows, to install, run the command `Install-Package Optimizely.SDK` in the Package Manager Console: -[block:code] -{ - "codes": [ - { - "code": "PM> Install-Package Optimizely.SDK -Version 3.0.0\n\n", - "language": "shell", - "name": "Install the SDK" - } - ] -} -[/block] -The package is on NuGet at https://www.nuget.org/packages/Optimizely.SDK. The full source code is at https://github.com/optimizely/csharp-sdk. \ No newline at end of file + +```shell +PM> Install-Package Optimizely.SDK -Version 3.0.0 +``` +The package is on NuGet at https://www.nuget.org/packages/Optimizely.SDK. The full source code is at https://github.com/optimizely/csharp-sdk. + diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/020 - initialize-sdk-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/020 - initialize-sdk-csharp.md index afd5d63f..7c1ab993 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/020 - initialize-sdk-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/020 - initialize-sdk-csharp.md @@ -5,150 +5,144 @@ hidden: false createdAt: "2019-09-11T14:15:47.848Z" updatedAt: "2020-04-10T00:11:24.283Z" --- + +# Initialize SDK + Use the `instantiate` method to initialize the C# SDK and instantiate an instance of the Optimizely client class that exposes API methods like [Get Enabled Features](doc:get-enabled-features-csharp). Each client corresponds to the datafile representing the state of a project for a certain environment. -[block:api-header] -{ - "title": "Version" -} -[/block] + +## Version + SDK v3.2.0 -[block:api-header] -{ - "title": "Description" -} -[/block] + +## Description + The constructor accepts a configuration object to configure Optimizely. Some parameters are optional because the SDK provides a default implementation, but you may want to override these for your production environments. For example, you may want override these to set up an [error handler](doc:customize-error-handler-csharp) and [logger](doc:customize-logger-csharp) to catch issues, an event dispatcher to manage network calls, and a User Profile Service to ensure sticky bucketing. -[block:api-header] -{ - "title": "Parameters" -} -[/block] + +## Parameters + The table below lists the required and optional parameters in C#. -[block:parameters] -{ - "data": { - "h-0": "Parameter", - "h-1": "Type", - "h-2": "Description", - "0-0": "**datafile**\n*optional* ", - "0-1": "string", - "0-2": "The JSON string representing the project.", - "1-0": "**configManager**\n*optional*", - "1-1": "ProjectConfigManager", - "1-2": "The project config manager provides the project config to the client.", - "2-0": "**eventDispatcher**\n*optional*", - "2-1": "IEventDispatcher", - "2-2": "An event handler to manage network calls.", - "3-0": "**logger**\n*optional*", - "3-1": "ILogger", - "3-2": "A logger implementation to log issues.", - "4-0": "**errorHandler**\n*optional*", - "4-1": "IErrorHandler", - "4-2": "An error handler object to handle errors.", - "5-0": "**userProfileService**\n*optional*", - "5-1": "UserProfileService", - "5-2": "A user profile service.", - "6-0": "**skipJsonValidation**\n*optional*", - "6-1": "boolean", - "6-2": "Specifies whether the JSON should be validated. Set to `true` to skip JSON validation on the schema, or `false` to perform validation." - }, - "cols": 3, - "rows": 7 -} -[/block] -[block:api-header] -{ - "title": "Returns" -} -[/block] +| 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. | + +## Returns + Instantiates an instance of the Optimzely class. -[block:api-header] -{ - "title": "Automatic datafile management (ADM)" -} -[/block] + +## Automatic datafile management (ADM) + Optimizely 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 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 will poll for datafile changes in the background at regular intervals. -* When initializing with just the datafile, the SDK will NOT poll for datafile changes in the background. -* When initializing with both the SDK key and datafile, the SDK will use the given datafile and start polling for datafile changes in the background. +- When initializing with just the SDK key, the SDK will poll for datafile changes in the background at regular intervals. +- When initializing with just the datafile, the SDK will NOT poll for datafile changes in the background. +- When initializing with both the SDK key and datafile, the SDK will use the given datafile and start polling for datafile changes in the background. ### Basic example The following code example shows basic C# ADM usage. -[block:code] + +```csharp +using OptimizelySDK; + +public class App { - "codes": [ + public static void Main(string[] args) { - "code": "using OptimizelySDK;\n\npublic class App\n{\n public static void Main(string[] args)\n {\n string sdkKey = args[0];\n \t Optimizely optimizely = OptimizelyFactory.NewDefaultInstance(sdkKey);\n }\n}\n\n", - "language": "csharp" + string sdkKey = args[0]; + Optimizely optimizely = OptimizelyFactory.NewDefaultInstance(sdkKey); } - ] } -[/block] -### Advanced examples +``` +# Advanced examples +> If you are configuring a logger, make sure to pass it into the `ProjectConfigManager` instance as well. -[block:callout] -{ - "type": "warning", - "body": "If you are configuring a logger, make sure to pass it into the `ProjectConfigManager` instance as well." -} -[/block] 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. -[block:callout] -{ - "type": "warning", - "title": "", - "body": "Pass all components (Logger, ErrorHandler, NotificationCenter) to the Optimizely constructor. Not passing a component will fail to enable its respective functionality. In other words, components only work when passed to the constructor." -} -[/block] -[block:code] -{ - "codes": [ - { - "code": "// Initialize with SDK key and default configuration\nvar sdkKey = \"\" // replace with your own SDK Key\nOptimizely optimizely = OptimizelyFactory.newDefaultInstance(sdkKey);\n\n\n// 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.\nvar projectConfigManager =\n new HttpProjectConfigManager.Builder()\n .WithSdkKey(sdkKey)\n .WithPollingInterval(TimeSpan.FromMinutes(5))\n // .WithLogger(logger) - this is needed if you are configuring a logger for the optimizely instance\n// .WithErrorHandler(errorHandler) - this is needed if you are configuring an errorhandler for the optimizely instance.\n// .WithNotificationCenter(notificationCenter) this is needed if you are subscribing config update\n .Build();\n\nvar Optimizely = new Optimizely(projectConfigManager);\n\n// Initialize with Logger\n// var Optimizely = new Optimizely(projectConfigManager, logger: logger);\n\n// Initialize with Logger, ErrorHandler\n// var Optimizely = new Optimizely(projectConfigManager, errorHandler: errorHandler, logger: logger);\n\n// Initialize with NotificationCenter, Logger, ErrorHandler\n// var Optimizely = new Optimizely(projectConfigManager, notificationCenter: NotificationCenter, errorHandler: errorHandler, logger: logger);\n\n// Note: Use OptimizelyFactory NewDefaultInstance method to use same logger, errorHandler and notificationCenter for all of its Components (Optimizely, EventProcessor, HttpProjectConfigManager)\n", - "language": "csharp" - } - ] -} -[/block] -Here is a code example showing advanced configuration for C# ADM. Advanced configuration properties are described in the sections below. 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. -[block:code] +> Pass all components (Logger, ErrorHandler, NotificationCenter) to the Optimizely constructor. Not passing a component will fail to enable its respective functionality. In other words, components only work when passed to the constructor. + +```csharp +// Initialize with SDK key and default configuration +var sdkKey = "" // replace with your own SDK Key +Optimizely 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) - this is needed if you are configuring a logger for the optimizely instance + // .WithErrorHandler(errorHandler) - this is needed if you are configuring an errorhandler for the optimizely instance. + // .WithNotificationCenter(notificationCenter) this is 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) +``` +# Advanced Configuration for C# ADM + +This code example demonstrates advanced configuration for C# ADM (Application Development Manager). The advanced configuration properties are described in the sections below. This example showcases how to construct individual components directly to override various configurations, allowing full control over which implementations to use and how to use them. + +## Code Example + +```csharp +using OptimizelySDK; +using OptimizelySDK.Config; + +public class App { - "codes": [ + public static void Main(string[] args) { - "code": "using OptimizelySDK;\nusing OptimizelySDK.Config;\n\npublic class App\n{\n public static void Main(string[] args)\n {\n string sdkKey = args[0];\n // You can also use your own implementation of the ProjectConfigManager interface\n ProjectConfigManager projectConfigManager =\n new HttpProjectConfigManager.Builder()\n\t .WithSdkKey(sdkKey)\n\t .WithPollingInterval(TimeSpan.FromMinutes(1))\n\t .Build();\n\n Optimizely optimizely = new Optimizely(configManager);\n }\n}\n\n", - "language": "csharp" + string sdkKey = args[0]; + // You can also use your own implementation of the ProjectConfigManager interface + ProjectConfigManager projectConfigManager = + new HttpProjectConfigManager.Builder() + .WithSdkKey(sdkKey) + .WithPollingInterval(TimeSpan.FromMinutes(1)) + .Build(); + + Optimizely optimizely = new Optimizely(configManager); } - ] } -[/block] -### HttpProjectConfigManager +``` +## HttpProjectConfigManager [HttpProjectConfigManager](https://github.com/optimizely/csharp-sdk/blob/fahad/dfm-readme/OptimizelySDK/Config/HttpProjectConfigManager.cs) is an implementation of the abstract [PollingProjectConfigManager](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Config/PollingProjectConfigManager.cs). 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` will block 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`. -[block:code] -{ - "codes": [ - { - "code": "ProjectConfigManager projectConfigManager =\n new HttpProjectConfigManager.Builder()\n\t .WithSdkKey(sdkKey)\n\t .WithPollingInterval(TimeSpan.FromMinutes(1))\n\t .Build();\n\n", - "language": "csharp" - } - ] -} -[/block] +By default, `HttpProjectConfigManager` will block until the first successful datafile retrieval, up to a configurable timeout. You can set the frequency of the polling method and the blocking timeout using the `HttpProjectConfigManager.Builder`. + +```csharp +ProjectConfigManager projectConfigManager = + new HttpProjectConfigManager.Builder() + .WithSdkKey(sdkKey) + .WithPollingInterval(TimeSpan.FromMinutes(1)) + .Build(); +``` #### SDK key The SDK key is used to compose the outbound HTTP request to the default datafile location on the Optimizely CDN. @@ -163,91 +157,54 @@ You can provide an initial datafile via the builder to bootstrap the `ProjectCon The initial datafile will be discarded after the first successful datafile poll. -#### Builder methods +## Builder Methods -Use the following builder methods to customize the `HttpProjectConfigManager` configuration. -[block:parameters] -{ - "data": { - "0-0": "**WithDatafile(string)**", - "1-0": "**WithUrl(string)**", - "2-0": "**WithFormat(string)**", - "3-0": "**WithPollingInterval(TimeSpan)**", - "0-1": "null", - "1-1": "null", - "2-1": "null", - "3-2": "Fixed delay between fetches for the datafile", - "3-1": "5 minutes", - "1-2": "URL override location used to specify custom HTTP source for the Optimizely datafile", - "0-2": "Initial datafile, typically sourced from a local cached source", - "2-2": "Parameterized datafile URL by SDK key", - "4-0": "**WithBlockingTimeoutPeriod(TimeSpan)**", - "4-1": "15 seconds", - "h-0": "Property", - "h-1": "Default value", - "h-2": "Description", - "4-2": "Maximum time to wait for initial bootstrapping. The valid timeout duration is 1 to 4294967294 milliseconds.", - "5-0": "**WithSdkKey(string)**", - "5-1": "null", - "5-2": "Optimizely project SDK key; required unless source URL is overridden" - }, - "cols": 3, - "rows": 6 -} -[/block] -#### Update config notifications +Use the following builder methods to customize the `HttpProjectConfigManager` configuration: -A notification signal will be triggered whenever a new datafile is fetched. To subscribe to these notifications, use method `NotificationCenter.AddNotification()`. -[block:code] -{ - "codes": [ - { - "code": "optimizely.NotificationCenter.AddNotification(\n NotificationCenter.NotificationType.OptimizelyConfigUpdate,\n () => Console.WriteLine(\"Received new datafile configuration\")\n);\n\n", - "language": "csharp" - } - ] -} -[/block] -### OptimizelyFactory +| 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 a 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 project SDK key; required unless the source URL is overridden. | -[OptimizelyFactory](https://github.com/optimizely/csharp-sdk/blob/fahad/dfm-readme/OptimizelySDK/OptimizelyFactory.cs) provides basic utility to instantiate the Optimizely SDK with a minimal number of configuration options. +## Update Config Notifications -OptimizelyFactory does not capture all configuration and initialization options. For more use cases, build the resources with their constructors. +A notification signal will be triggered whenever a new datafile is fetched. To subscribe to these notifications, use the method `NotificationCenter.AddNotification()`. -You must provide the SDK key at runtime, directly via the factory method: -[block:code] -{ - "codes": [ - { - "code": "Optimizely optimizely = OptimizelyFactory.NewDefaultInstance(<>);\n\n", - "language": "csharp" - } - ] -} -[/block] +```csharp +optimizely.NotificationCenter.AddNotification( + NotificationCenter.NotificationType.OptimizelyConfigUpdate, + () => Console.WriteLine("Received new datafile configuration") +); +``` +## OptimizelyFactory + +[OptimizelyFactory](https://github.com/optimizely/csharp-sdk/blob/fahad/dfm-readme/OptimizelySDK/OptimizelyFactory.cs) provides a basic utility to instantiate the Optimizely SDK with a minimal number of configuration options. + +OptimizelyFactory does not capture all configuration and initialization options. For more use cases, consider building the necessary resources using their constructors. + +To instantiate the Optimizely SDK, you need to provide the SDK key at runtime directly via the factory method: + +```csharp +Optimizely optimizely = OptimizelyFactory.NewDefaultInstance(<>); +``` +### Instantiate using datafile -[block:api-header] -{ - "title": "Instantiate using datafile" -} -[/block] You can also instantiate with a hard-coded datafile. If you don't pass in an SDK key, the Optimizely Client will not automatically sync newer versions of the datafile. Any time you retrieve an updated datafile, just re-instantiate the same client. For simple applications, all you need to provide to instantiate a client is a datafile specifying the project configuration for a given environment. For most advanced implementations, you'll want to [customize the logger](doc:customize-logger-csharp) or [error handler](doc:customize-error-handler-csharp) for your specific requirements. -[block:code] -{ - "codes": [ - { - "code": "using OptimizelySDK;\n\n// Instantiate an Optimizely client\nvar datafile = \"\"\nOptimizely OptimizelyClient = new Optimizely(datafile);\n\n", - "language": "csharp" - } - ] -} -[/block] -[block:api-header] -{ - "title": "Source files" -} -[/block] -The language/platform source files containing the implementation for C# are at [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). \ No newline at end of file +```csharp +using OptimizelySDK; + +// Instantiate an Optimizely client +var datafile = ""; +Optimizely OptimizelyClient = new Optimizely(datafile); +```` + +### Source files + +The language/platform source files containing the implementation for C# can be found at [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/030 - example-usage-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/030 - example-usage-csharp.md index 05c4f303..b5e6d52b 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/030 - example-usage-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/030 - example-usage-csharp.md @@ -13,13 +13,37 @@ This example demonstrates the basic usage of each of these concepts. This exampl 2. Run an A/B test called `app_redesign`. This experiment has two variations, `control` and `treatment`. It uses the `activate` method to assign the user to a variation, returning its key. As a side effect, the activate function also sends an impression event to Optimizely to record that the current user has been exposed to the experiment. 3. Use event tracking to track an event called `purchased`. This conversion event measures the impact of an experiment. Using the track method, the purchase is automatically attributed back to the running A/B and feature tests we've activated, and the SDK sends a network request to Optimizely via the customizable event dispatcher so we can count it in your results page. -[block:code] +```csharp +// Import Optimizely SDK +using OptimizelySDK; + +// Instantiate an Optimizely client +var optimizelyClient = new Optimizely(datafile); + +// Evaluate a feature flag and a variable +bool isFeatureEnabled = optimizelyClient.IsFeatureEnabled("price_filter", userId); +int? min_price = optimizelyClient.GetFeatureVariableInteger("price_filter", "min_price", userId); + +// Activate an A/B test +var variation = optimizelyClient.Activate("app_redesign", userId); + +if (variation != null && !string.IsNullOrEmpty(variation.Key)) { - "codes": [ + if (variation.Key == "control") + { + // Execute code for variation A + } + else if (variation.Key == "treatment") { - "code": "//Import Optimizely SDK\nusing OptimizelySDK;\n\n// Instantiate an Optimizely client\nvar optimizelyClient = new Optimizely(datafile);\n\n// Evaluate a feature flag and a variable\nbool isFeatureEnabled = optimizelyClient.IsFeatureEnabled(\"price_filter\", userId);\nint? min_price = optimizelyClient.GetFeatureVariableInteger(\"price_filter\", \"min_price\", userId);\n\n// Activate an A/B test\nvar variation = optimizelyClient.Activate(\"app_redesign\", userId);\n\tif (variation != null && !string.IsNullOrEmpty(variation.Key))\n\t{\n\t\tif (variation.Key == \"control\")\n\t\t{\n\t\t\t// Execute code for variation A\n\t\t}\n\t\telse if (variation.Key == \"treatment\")\n\t\t{\n\t\t\t// Execute code for variation B\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Execute code for your users who don’t qualify for the experiment\n\t}\n\n// Track an event\noptimizelyClient.Track(\"purchased\", userId);\n\n", - "language": "csharp" + // Execute code for variation B } - ] } -[/block] \ No newline at end of file +else +{ + // Execute code for your users who don’t qualify for the experiment +} + +// Track an event +optimizelyClient.Track("purchased", userId); + +``` \ No newline at end of file diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/040 - optimizelyconfig-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/040 - optimizelyconfig-csharp.md index 0bbda239..ac3e93f3 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/040 - optimizelyconfig-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/040 - optimizelyconfig-csharp.md @@ -5,68 +5,109 @@ hidden: false createdAt: "2020-01-17T11:52:50.547Z" updatedAt: "2020-01-28T21:53:11.290Z" --- -[block:api-header] -{ - "title": "Overview" -} -[/block] + +## Overview + Optimizely Feature Experimentation SDKs open a well-defined set of public APIs, hiding all implementation details. However, some clients may need access to project configuration data within the "datafile". In this document, we extend our public APIs to define data models and access methods, which clients can use to access project configuration data. -[block:api-header] -{ - "title": "OptimizelyConfig API" -} -[/block] +## OptimizelyConfig API A public configuration data model (OptimizelyConfig) is defined below as a structured format of static Optimizely Project data. OptimizelyConfig can be accessed from OptimizelyClient (top-level) with this public API call: -[block:code] + +```csharp +public OptimizelyConfig GetOptimizelyConfig() +``` +`GetOptimizelyConfig` returns an `OptimizelyConfig` instance which includes a datafile revision number, all experiments, and feature flags mapped by their key values. + +> **Note:** When the SDK datafile is updated (the client can add a notification listener for `OPTIMIZELY_CONFIG_UPDATE` to get notified), the client is expected to call the method to get the updated OptimizelyConfig data. See examples below. + +```csharp +// OptimizelyConfig is a class describing the current project configuration data being used by this SDK instance. +public class OptimizelyConfig { - "codes": [ - { - "code": "public OptimizelyConfig GetOptimizelyConfig()", - "language": "csharp" - } - ] + public string Revision { get; private set; } + public IDictionary ExperimentsMap { get; private set; } + public IDictionary FeaturesMap { get; private set; } } -[/block] -`GetOptimizelyConfig` returns an `OptimizelyConfig` instance which include a datafile revision number, all experiments, and feature flags mapped by their key values. -[block:callout] + +// Entity.IdKeyEntity is an abstract class used for inheritance in OptimizelyExperiment, OptimizelyFeature, OptimizelyVariation, and OptimizelyVariable classes. +public abstract class IdKeyEntity : Entity, IEquatable { - "type": "info", - "title": "Note", - "body": "When the SDK datafile is updated (the client can add a notification listener for `OPTIMIZELY_CONFIG_UPDATE` to get notified), the client is expected to call the method to get the updated OptimizelyConfig data. See examples below." + public string Id { get; set; } + public string Key { get; set; } } -[/block] -[block:code] +// OptimizelyFeature is a class describing a feature and inherited from Entity.IdKeyEntity. +public class OptimizelyFeature : Entity.IdKeyEntity { - "codes": [ - { - "code": "// OptimizelyConfig is class describing the current project configuration data being used by this SDK instance.\n public class OptimizelyConfig\n {\n public string Revision { get; private set; }\n public IDictionary ExperimentsMap { get; private set; }\n public IDictionary FeaturesMap { get; private set; } \n }\n\n// Entity.IdKeyEntity is an abstract class used for inheritance in OptimizelyExperiment, OptimizelyFeature, OptimizelyVariation and OptimizelyVariable classes.\npublic abstract class IdKeyEntity : Entity, IEquatable\n{\n public string Id { get; set; }\n public string Key { get; set; }\n}\n\n// OptimizelyFeature is a class describing a feature and inherited from Entity.IdKeyEntity.\npublic class OptimizelyFeature : Entity.IdKeyEntity\n{\n public IDictionary ExperimentsMap { get; private set; }\n public IDictionary VariablesMap { get; private set; }\n}\n\n\n// OptimizelyExperiment is a class describing a feature test or an A/B test and inherited from Entity.IdKeyEntity.\npublic class OptimizelyExperiment : Entity.IdKeyEntity\n{\n public IDictionary VariationsMap { get; private set; }\n}\n\n\n// OptimizelyVariation is a class describing a variation in a feature test or A/B test and inherited from Entity.IdKeyEntity.\npublic class OptimizelyVariation : Entity.IdKeyEntity\n{\n [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]\n public bool? FeatureEnabled { get; private set; }\n public IDictionary VariablesMap { get; private set; }\n}\n\n\n// OptimizelyVariable is a class describing a feature variable and inherited from Entity.IdKeyEntity.\npublic class OptimizelyVariable : Entity.IdKeyEntity\n{\n public string Type { get; private set; }\n public string Value { get; private set; }\n}", - "language": "csharp" - } - ] + public IDictionary ExperimentsMap { get; private set; } + public IDictionary VariablesMap { get; private set; } } -[/block] -[block:api-header] +// OptimizelyExperiment is a class describing a feature test or an A/B test and inherited from Entity.IdKeyEntity. +public class OptimizelyExperiment : Entity.IdKeyEntity { - "title": "Examples" + public IDictionary VariationsMap { get; private set; } } -[/block] -OptimizelyConfig can be accessed from OptimizelyClient (top-level) like this: -[block:code] +// OptimizelyVariation is a class describing a variation in a feature test or A/B test and inherited from Entity.IdKeyEntity. +public class OptimizelyVariation : Entity.IdKeyEntity { - "codes": [ - { - "code": "var optimizelyConfig = optimizely.GetOptimizelyConfig();\n\n// all experiment keys\nvar experimentKeys = optimizelyConfig.ExperimentsMap.Keys;\nforeach(var experimentKey in experimentKeys) {\n // use experiment key data here.\n}\n\n// all experiments\nvar experiments = optimizelyConfig.ExperimentsMap.Values;\nforeach(var experiment in experiments) {\n // all variations\n var variations = experiment.VariationsMap.Values;\n foreach(var variation in variations) {\n var variables = variation.VariablesMap.Values;\n foreach(var variable in variables) {\n // use variable data here.\n }\n }\n}\n\n\n\n// all features\nvar features = optimizelyConfig.FeaturesMap.Values;\nforeach(var feature in features) {\n var experiments = feature.ExperimentsMap.Values;\n foreach(var experiment in experiments) {\n // use experiment data here.\n }\n}\n\n\n// listen to OPTIMIZELY_CONFIG_UPDATE to get updated data\nNotificationCenter.OptimizelyConfigUpdateCallback configUpdateListener = () => {\n var optimizelyConfig = optimizely.GetOptimizelyConfig();\n };\n optimizely.NotificationCenter.AddNotification(NotificationCenter.NotificationType.OptimizelyConfigUpdate, configUpdateListener);\n", - "language": "csharp" + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public bool? FeatureEnabled { get; private set; } + public IDictionary VariablesMap { get; private set; } +} + +// OptimizelyVariable is a class describing a feature variable and inherited from Entity.IdKeyEntity. +public class OptimizelyVariable : Entity.IdKeyEntity +{ + public string Type { get; private set; } + public string Value { get; private set; } +} +``` + +## Examples + +You can access the `OptimizelyConfig` from the `OptimizelyClient` (top-level) as shown below: + +```csharp +var optimizelyConfig = optimizely.GetOptimizelyConfig(); + +// All experiment keys +var experimentKeys = optimizelyConfig.ExperimentsMap.Keys; +foreach(var experimentKey in experimentKeys) { + // Use experiment key data here. +} + +// All experiments +var experiments = optimizelyConfig.ExperimentsMap.Values; +foreach(var experiment in experiments) { + // All variations + var variations = experiment.VariationsMap.Values; + foreach(var variation in variations) { + var variables = variation.VariablesMap.Values; + foreach(var variable in variables) { + // Use variable data here. } - ] + } } -[/block] \ No newline at end of file + +// All features +var features = optimizelyConfig.FeaturesMap.Values; +foreach(var feature in features) { + var experiments = feature.ExperimentsMap.Values; + foreach(var experiment in experiments) { + // Use experiment data here. + } +} + +// Listen to OPTIMIZELY_CONFIG_UPDATE to get updated data +NotificationCenter.OptimizelyConfigUpdateCallback configUpdateListener = () => { + var optimizelyConfig = optimizely.GetOptimizelyConfig(); +}; +optimizely.NotificationCenter.AddNotification(NotificationCenter.NotificationType.OptimizelyConfigUpdate, configUpdateListener); +``` \ No newline at end of file diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/050 - implement-a-user-profile-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/050 - implement-a-user-profile-csharp.md index 28a43f46..ac090f10 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/050 - implement-a-user-profile-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/050 - implement-a-user-profile-csharp.md @@ -8,42 +8,75 @@ updatedAt: "2019-09-12T13:45:24.114Z" Use a **User Profile Service** to persist information about your users and ensure variation assignments are sticky. For example, if you are working on a backend website, you can create an implementation that reads and saves user profiles from a Redis or memcached store. In the C# SDK, there is no default implementation. Implementing a User Profile Service is optional and is only necessary if you want to keep variation assignments sticky even when experiment conditions are changed while it is running (for example, audiences, attributes, variation pausing, and traffic distribution). Otherwise, the C# SDK is stateless and rely on deterministic bucketing to return consistent assignments. See [How bucketing works](doc:how-bucketing-works) for more information. -[block:api-header] -{ - "title": "Implement a service" -} -[/block] -Refer to the code samples below to provide your own User Profile Service. It should expose two functions with the following signatures: +## Implement a Service + +To implement a User Profile Service, you can refer to the code samples provided below. Your User Profile Service should expose two functions with the following signatures: + +- `lookup`: Takes a user ID string and returns a user profile matching the specified schema. +- `save`: Takes a user profile and persists it. -* `lookup`: Takes a user ID string and returns a user profile matching the schema below. -* `save`: Takes a user profile and persists it. +If you intend to use the User Profile Service purely for tracking purposes and not sticky bucketing, you can implement only the `save` method and always return `null` from the `lookup` method. -If you want to use the User Profile Service purely for tracking purposes and not sticky bucketing, you can implement only the `save` method (always return `nil` from `lookup`). -[block:code] +Here's an example implementation using C#: + +```csharp +using System.Collections.Generic; +using OptimizelySDK; +using OptimizelySDK.Bucketing; + +class InMemoryUserProfileService : UserProfileService { - "codes": [ + private Dictionary> userProfiles = new Dictionary>(); + + public override Dictionary Lookup(string userId) { - "code": "using System.Collections.Generic;\n\nusing OptimizelySDK;\nusing OptimizelySDK.Bucketing;\n\nclass InMemoryUserProfileService : UserProfileService\n{\n private Dictionary> userProfiles = new Dictionary>();\n Dictionary UserProfileService.Lookup(string userId)\n {\n // Retrieve and return user profile\n // Replace with userprofile variable\n return null;\n }\n\n void UserProfileService.Save(Dictionary userProfile)\n {\n // Save user profile\n }\n}\n\n\tvar optimizelyClient = new Optimizely(\n\t\tdatafile: datafile,\n userProfileService: userProfileService);\n\n", - "language": "csharp" + // Retrieve and return user profile + // Replace with the actual userprofile variable + return null; + } + + public override void Save(Dictionary userProfile) + { + // Save user profile + // Implement the logic to persist the user profile data } - ] } -[/block] -The code example below shows the JSON schema for the user profile object. -Use `experiment_bucket_map` to override the default bucketing behavior and define an alternate experiment variation for a given user. For each experiment that you want to override, add an object to the map. Use the experiment ID as the key and include a `variation_id` property that specifies the desired variation. If there isn't an entry for an experiment, then the default bucketing behavior persists. +var optimizelyClient = new Optimizely( + datafile: datafile, + userProfileService: new InMemoryUserProfileService() +); +``` +## User Profile JSON Schema + +The following JSON schema represents the structure of a user profile object. This schema can be used to define user profiles within your User Profile Service. -In the example below, `^[a-zA-Z0-9]+$` is the experiment ID. -[block:code] +Use the `experiment_bucket_map` field to override the default bucketing behavior and specify an alternate experiment variation for a given user. For each experiment that you want to override, add an object to the `experiment_bucket_map`. Use the experiment ID as the key and include a `variation_id` property that specifies the desired variation. If there is no entry for an experiment, the default bucketing behavior persists. + +In the example below, `^[a-zA-Z0-9]+$` represents the pattern for an experiment ID: + +```json { - "codes": [ - { - "code": "{\n \"title\": \"UserProfile\",\n \"type\": \"object\",\n \"properties\": {\n \"user_id\": {\"type\": \"string\"},\n \"experiment_bucket_map\": {\"type\": \"object\",\n \"patternProperties\": {\n \"^[a-zA-Z0-9]+$\": {\"type\": \"object\",\n \"properties\": {\"variation_id\": {\"type\":\"string\"}},\n \"required\": [\"variation_id\"]}\n }\n }\n },\n \"required\": [\"user_id\", \"experiment_bucket_map\"]\n}\n\n", - "language": "json" + "title": "UserProfile", + "type": "object", + "properties": { + "user_id": {"type": "string"}, + "experiment_bucket_map": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9]+$": { + "type": "object", + "properties": { + "variation_id": {"type": "string"} + }, + "required": ["variation_id"] + } + } } - ] + }, + "required": ["user_id", "experiment_bucket_map"] } -[/block] +``` The C# SDK uses the User Profile Service you provide to override Optimizely's default bucketing behavior in cases when an experiment assignment has been saved. When implementing your own User Profile Service, we recommend loading the user profiles into the User Profile Service on initialization and avoiding performing expensive, blocking lookups on the lookup function to minimize the performance impact of incorporating the service. diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/060 - configure-event-dispatcher-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/060 - configure-event-dispatcher-csharp.md index 512b1be4..9a8a438e 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/060 - configure-event-dispatcher-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/060 - configure-event-dispatcher-csharp.md @@ -9,22 +9,45 @@ The Optimizely SDKs make HTTP requests for every impression or conversion that g The C# SDK has an out-of-the-box asynchronous dispatcher. We recommend customizing the event dispatcher you use in production to ensure that you queue and send events in a manner that scales to the volumes handled by your application. Customizing the event dispatcher allows you to take advantage of features like batching, which makes it easier to handle large event volumes efficiently or to implement retry logic when a request fails. You can build your dispatcher from scratch or start with the provided dispatcher. -The examples show that to customize the event dispatcher, initialize the Optimizely client (or manager) with an event dispatcher instance. -[block:code] +## Customizing Event Dispatcher + +To customize the event dispatcher in the Optimizely SDK, you can initialize the Optimizely client (or manager) with a custom event dispatcher instance. The following code example demonstrates how to achieve this: + +```csharp +using OptimizelySDK; +using OptimizelySDK.Event.Dispatcher; + +// Create an Optimizely client with a custom event dispatcher +Optimizely OptimizelyClient = new Optimizely( + datafile: datafile, + eventDispatcher: new CustomEventDispatcher(new OptimizelySDK.Logger.DefaultLogger()) +); +``` +## Implementing a Custom Event Dispatcher + +To implement a custom event dispatcher in the Optimizely SDK, you need to create a class that implements the `IEventDispatcher` interface and provides the `dispatchEvent` function. This function takes in three arguments: `httpVerb`, `url`, and `params`, which are generated by the internal `EventBuilder` class. The custom event dispatcher should send a `POST` request to the specified `url` using the `params` as the body of the request (make sure to stringify it to JSON) and include the `{content-type: 'application/json'}` header. + +Here's how you can create a custom event dispatcher: + +```csharp +using System.Net.Http; +using System.Threading.Tasks; +using OptimizelySDK.Event.Dispatcher; + +class CustomEventDispatcher : IEventDispatcher { - "codes": [ + private readonly HttpClient _httpClient = new HttpClient(); + + public async Task DispatchEvent(string httpVerb, string url, string params) { - "code": "using OptimizelySDK;\nusing OptimizelySDK.Event.Dispatcher;\n\n// Create an Optimizely client with the default event dispatcher\n\tOptimizely OptimizelyClient = new Optimizely(\n\t\t\tdatafile: datafile,\n\t\t\teventDispatcher: new DefaultEventDispatcher(new OptimizelySDK.Logger.DefaultLogger()));\n\n", - "language": "csharp" + var request = new HttpRequestMessage(HttpMethod.Post, url) + { + Content = new StringContent(params, Encoding.UTF8, "application/json") + }; + + HttpResponseMessage response = await _httpClient.SendAsync(request); + + // Handle response if needed } - ] -} -[/block] -The event dispatcher should implement a `dispatchEvent` function, which takes in three arguments: `httpVerb`, `url`, and `params`, all of which are created by the internal `EventBuilder` class. In this function, you should send a `POST` request to the given `url` using the `params` as the body of the request (be sure to stringify it to JSON) and `{content-type: 'application/json'}` in the headers. -[block:callout] -{ - "type": "warning", - "title": "Important", - "body": "If you are using a custom event dispatcher, do not modify the event payload returned from Optimizely. Modifying this payload will alter your results." } -[/block] \ No newline at end of file +``` \ No newline at end of file diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/070 - event-batching-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/070 - event-batching-csharp.md index 236c2222..97e0a6c8 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/070 - event-batching-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/070 - event-batching-csharp.md @@ -5,7 +5,8 @@ hidden: false createdAt: "2019-09-12T13:44:04.059Z" updatedAt: "2019-12-13T00:25:39.892Z" --- -The [Optimizely Feature Experimentation C# SDK](https://github.com/optimizely/csharp-sdk) now batches impression and conversion events into a single payload before sending it to Optimizely. This is achieved through a new SDK component called the event processor. + +The [Optimizely Feature Experimentation C# SDK](https://github.com/optimizely/csharp-sdk) now supports event batching, a feature that reduces the number of outbound requests to Optimizely by batching impression and conversion events into a single payload. This is achieved through a new SDK component called the event processor. Event batching has the advantage of reducing the number of outbound requests to Optimizely depending on how you define, configure, and use the event processor. It means less network traffic for the same number of Impression and conversion events tracked. @@ -15,169 +16,123 @@ In the C# SDK, `BatchEventProcessor` provides implementation of the `EventProces - Flush interval: Defines the amount of time after which any batched events should be sent to Optimizely. An event consisting of the batched payload is sent as soon as the batch size reaches the specified limit or flush interval reaches the specified time limit. `BatchEventProcessor` options are described in more detail below. -[block:callout] -{ - "type": "info", - "title": "Note", - "body": "Event batching works with both out-of-the-box and custom event dispatchers.\n\nThe event batching process doesn't remove any personally identifiable information (PII) from events. You must still ensure that you aren't sending any unnecessary PII to Optimizely." -} -[/block] -[block:api-header] -{ - "title": "Basic example" -} -[/block] +> **Note** +> Event batching works with both out-of-the-box and custom event dispatchers. +> The event batching process doesn't remove any personally identifiable information (PII) from events. You must still ensure that you aren't sending any unnecessary PII to Optimizely. +### Basic example + +You can create an Optimizely Client using the `OptimizelyFactory.NewDefaultInstance` method. Here's a basic example of how to do this: + +```csharp +using OptimizelySDK; -[block:code] +class App { - "codes": [ + static void Main(string[] args) { - "code": "using OptimizelySDK;\n\nclass App\n{\n static void Main(string[] args)\n {\n string sdkKey = args[0];\n // Returns Optimizely Client\n OptimizelyFactory.NewDefaultInstance(sdkKey);\n }\n}", - "language": "csharp" + string sdkKey = args[0]; + // Returns Optimizely Client + OptimizelyFactory.NewDefaultInstance(sdkKey); } - ] } -[/block] -By default, batch size is 10 and flush interval is 30 seconds. -[block:api-header] -{ - "title": "Advanced Example" -} -[/block] +``` +### Advanced Example + +In this advanced example, you can customize the batch size and flush interval of the `BatchEventProcessor` in the Optimizely Client. -[block:code] +```csharp +using OptimizelySDK; + +class App { - "codes": [ + static void Main(string[] args) { - "code": "using OptimizelySDK;\n\nclass App\n{\n static void Main(string[] args)\n {\n string sdkKey = args[0];\n ProjectConfigManager projectConfigManager = HttpProjectConfigManager.builder()\n .WithSdkKey(sdkKey)\n .Build();\n\n BatchEventProcessor batchEventProcessor = new BatchEventProcessor.Builder()\n .WithMaxBatchSize(10)\n .WithFlushInterval(TimeSpan.FromSeconds(30))\n .Build();\n\n Optimizely optimizely = new Optimizely(\n projectConfigManager,\n .. // Other Params\n ..batchEventProcessor\n );\n }\n}", - "language": "csharp" + string sdkKey = args[0]; + + ProjectConfigManager projectConfigManager = HttpProjectConfigManager.builder() + .WithSdkKey(sdkKey) + .Build(); + + BatchEventProcessor batchEventProcessor = new BatchEventProcessor.Builder() + .WithMaxBatchSize(10) // Set the batch size to 10 + .WithFlushInterval(TimeSpan.FromSeconds(30)) // Set the flush interval to 30 seconds + .Build(); + + Optimizely optimizely = new Optimizely( + projectConfigManager, + .. // Other Params + ..batchEventProcessor + ); } - ] } -[/block] +``` +### BatchEventProcessor -[block:api-header] -{ - "title": "BatchEventProcessor" -} -[/block] -`BatchEventProcessor` is an implementation of `EventProcessor` where events are batched. The class maintains a single consumer thread that pulls events off of the `BlockingCollection` and buffers them for either a configured batch size or a maximum duration before the resulting `LogEvent` is sent to the `EventDispatcher` and `NotificationCenter`. +`BatchEventProcessor` is an implementation of the `EventProcessor` interface that batches events. It maintains a single consumer thread that pulls events from a `BlockingCollection` and buffers them either until a configured batch size is reached or a maximum duration elapses. Once the batch size or time limit is met, the resulting `LogEvent` is sent to the `EventDispatcher` and `NotificationCenter`. + +You can customize the configuration of `BatchEventProcessor` using its Builder class. Here are the configurable properties: + +- **EventDispatcher**: The event dispatcher used to dispatch event payload to Optimizely. (Default: DefaultEventDispatcher) +- **BatchSize**: The maximum number of events to batch before dispatching. Once this number is reached, all queued events are flushed and sent to Optimizely. (Default: 10) +- **FlushInterval**: Milliseconds to wait before batching and dispatching events. (Default: 30000, or 30 seconds) +- **EventQueue**: A `BlockingCollection` that queues individual events to be batched and dispatched by the executor. (Default: 1000) +- **NotificationCenter**: Notification center instance to be used to trigger any notifications. (Default: null) + +These properties allow you to tailor the batch processing behavior based on your organization's requirements and resource availability. + +Keep in mind that the batch processing mechanism works seamlessly with both the out-of-the-box and custom event dispatchers provided by Optimizely. + +For more information, refer to the [Optimizely C# SDK documentation](https://github.com/optimizely/csharp-sdk). -The following properties can be used to customize the BatchEventProcessor configuration *using the Builder class* -[block:parameters] -{ - "data": { - "h-0": "Property", - "h-1": "Default value", - "0-0": "**EventDispatcher**", - "0-1": "DefautEventDispatcher", - "1-1": "10", - "1-0": "**BatchSize**", - "h-2": "Description", - "h-3": "Server", - "0-2": "Used to dispatch event payload to Optimizely.", - "1-2": "The maximum number of events to batch before dispatching. Once this number is reached, all queued events are flushed and sent to Optimizely.", - "0-3": "Based on your organization's requirements.", - "1-3": "Based on your organization's requirements.", - "3-0": "**EventQueue**", - "3-1": "1000", - "3-2": "BlockingCollection that queues individual events to be batched and dispatched by the executor.", - "2-0": "**FlushInterval**", - "2-1": "30000 (30 Seconds)", - "2-2": "Milliseconds to wait before batching and dispatching events.", - "4-0": "**NotificationCenter**", - "4-1": "null", - "4-2": "Notification center instance to be used to trigger any notifications." - }, - "cols": 3, - "rows": 5 -} -[/block] For more information, see [Initialize SDK](doc:initialize-sdk-csharp). -[block:api-header] -{ - "title": "Side effects" -} -[/block] -The table lists other Optimizely functionality that may be triggered by using this class. -[block:parameters] -{ - "data": { - "h-0": "Functionality", - "h-1": "Description", - "0-1": "Whenever the event processor produces a batch of events, a LogEvent object will be created using the EventFactory.\nIt contains batch of conversion and impression events. \nThis object will be dispatched using the provided event dispatcher and also it will be sent to the notification subscribers.", - "1-1": "Flush invokes the LOGEVENT [notification listener](doc:set-up-notification-listener-csharp) if this listener is subscribed to.", - "1-0": "Notification Listeners", - "0-0": "[LogEvent](https://staging-optimizely-parent.readme.io/staging-optimizely-full-stack/docs/logevent-c#)" - }, - "cols": 2, - "rows": 2 -} -[/block] -### Registering LogEvent listener +### Side Effects -To register a LogEvent listener -[block:code] -{ - "codes": [ - { - "code": "NotificationCenter.AddNotification(\n \t\t\t\t\t\t\t\t\t\tNotificationType.LogEvent, \n \t new LogEventCallback((logevent) => {\n \t\t // Your code here\n \t\t\t\t\t})\n );", - "language": "csharp" - } - ] -} -[/block] -### LogEvent +When using the `BatchEventProcessor` class, there are certain Optimizely functionalities that may be triggered. Here's a summary of those functionalities: -LogEvent object gets created using [EventFactory](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Event/EventFactory.cs).It represents the batch of impression and conversion events we send to the Optimizely backend. -[block:parameters] -{ - "data": { - "h-0": "Object", - "h-1": "Type", - "h-2": "Description", - "0-0": "**Url**\nRequired", - "0-1": " string ", - "0-2": "URL to dispatch log event to.", - "1-2": "Parameters to be set in the log event. It contains [EventBatch](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Event/Entity/EventBatch.cs) of all UserEvents inside [Visitors](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Event/Entity/EventBatch.cs#L45).", - "2-2": "The HTTP verb to use when dispatching the log event. It can be GET or POST.", - "3-2": "Headers to be set when sending the request.", - "3-0": "**Headers** ", - "2-0": "**HttpVerb**\nRequired", - "1-0": "**Params**\nRequired", - "1-1": "Dictionary", - "3-1": "Dictionary Headers", - "2-1": "string" - }, - "cols": 3, - "rows": 4 -} -[/block] +- **LogEvent**: Whenever the event processor produces a batch of events, a `LogEvent` object will be created using the `EventFactory`. This `LogEvent` object contains a batch of conversion and impression events. The object will be dispatched using the provided event dispatcher and will also be sent to the notification subscribers. + +- **Notification Listeners**: The `Flush` method invokes the `LOGEVENT` [notification listener](doc:set-up-notification-listener-csharp) if this listener is subscribed to. This allows you to be notified when events are being flushed, providing insights into the event batching process. + +For more information, you can refer to the [Optimizely C# SDK documentation](https://github.com/optimizely/csharp-sdk). + +Also, for detailed instructions on initializing the SDK, please see the [Initialize SDK](doc:initialize-sdk-csharp) documentation. +### Registering LogEvent Listener + +To register a `LogEvent` listener, you can use the following code snippet: + +```csharp +NotificationCenter.AddNotification( + NotificationType.LogEvent, + new LogEventCallback((logevent) => { + // Your code here + }) +); +``` +### LogEvent + +The `LogEvent` object is created using [EventFactory](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Event/EventFactory.cs). It represents the batch of impression and conversion events that are sent to the Optimizely backend. + +| Object | Type | Description | +|-----------|-----------------------|---------------------------------------------------------| +| **Url** | Required (string) | URL to dispatch the log event to. | +| **Params**| Required (Dictionary) | Parameters to be set in the log event. It contains an [EventBatch](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Event/Entity/EventBatch.cs) of all `UserEvents` inside [Visitors](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Event/Entity/EventBatch.cs#L45). | +| **HttpVerb** | Required (string) | The HTTP verb to use when dispatching the log event. It can be GET or POST. | +| **Headers** | Dictionary | Headers to be set when sending the request. | + +The `LogEvent` object encapsulates the information needed to send a batch of events to the Optimizely backend for processing. It plays a crucial role in the event batching and dispatching process. + +For more details on the `LogEvent` object and its usage, you can refer to the [Optimizely C# SDK documentation](https://github.com/optimizely/csharp-sdk). + + +# Dispose Optimizely on application exit -[block:api-header] -{ - "title": "Dispose Optimizely on application exit" -} -[/block] If you enable event batching, it's important that you call the Close method (`optimizely.Dispose()`) prior to exiting. This ensures that queued events are flushed as soon as possible to avoid any data loss. -[block:callout] -{ - "type": "warning", - "title": "Important", - "body": "Because the Optimizely client maintains a buffer of queued events, we recommend that you call `Dispose()` on the Optimizely instance before shutting down your application or whenever dereferencing the instance." -} -[/block] -[block:parameters] -{ - "data": { - "0-0": "**Dispose()**", - "h-0": "Method", - "h-1": "Description", - "0-1": "Stops all timers and flushes the event queue. This method will also stop any timers that are happening for the data-file manager." - }, - "cols": 2, - "rows": 1 -} -[/block] \ No newline at end of file +> **Important** +> Because the Optimizely client maintains a buffer of queued events, we recommend that you call `Dispose()` on the Optimizely instance before shutting down your application or whenever dereferencing the instance. + +## Method: Dispose() + +**Description** +Stops all timers and flushes the event queue. This method will also stop any timers that are happening for the data-file manager. diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/080 - customize-logger-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/080 - customize-logger-csharp.md index 02134627..c211eddb 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/080 - customize-logger-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/080 - customize-logger-csharp.md @@ -5,41 +5,56 @@ hidden: false createdAt: "2019-09-12T13:44:11.768Z" updatedAt: "2019-09-12T13:47:56.603Z" --- + The **logger** logs information about your experiments to help you with debugging. You can customize where log information is sent and what kind of information is tracked. -To improve your experience setting up the SDK and configuring your production environment, we recommend that you pass in a logger for your Optimizely client. See the code example below. -[block:code] +To improve your experience setting up the SDK and configuring your production environment, we recommend that you pass in a logger for your Optimizely client. See the code example below. + +```csharp +using OptimizelySDK.Logger; + +/** + * Log a message at a certain level. + * - Parameter level: The priority level of the log. + * - Parameter message: The message to log. + **/ +public class CustomLogger : ILogger { - "codes": [ + private LogLevel MinLogLevel; + + public CustomLogger(LogLevel minLogLevel) { - "code": "using OptimizelySDK.Logger;\n\n/**\n * Log a message at a certain level.\n * - Parameter level: The priority level of the log.\n * - Parameter message: The message to log.\n **/\npublic class CustomLogger : ILogger\n{\n private LogLevel MinLogLevel;\n\n public CustomLogger(LogLevel minLogLevel)\n {\n this.MinLogLevel = minLogLevel;\n }\n public void Log(LogLevel level, string message)\n {\n if (MinLogLevel <= level) {\n switch (level) {\n case LogLevel.DEBUG:\n // DEBUG log message\n break;\n case LogLevel.INFO:\n // INFO log message\n break;\n case LogLevel.WARN:\n // WARNING log message\n break;\n case LogLevel.ERROR:\n // ERROR log message\n break;\n }\n }\n }\n}\n\n", - "language": "csharp" + this.MinLogLevel = minLogLevel; } - ] -} -[/block] -[block:api-header] -{ - "title": "Log levels" + public void Log(LogLevel level, string message) + { + if (MinLogLevel <= level) { + switch (level) { + case LogLevel.DEBUG: + // DEBUG log message + break; + case LogLevel.INFO: + // INFO log message + break; + case LogLevel.WARN: + // WARNING log message + break; + case LogLevel.ERROR: + // ERROR log message + break; + } + } + } } -[/block] +``` +# Log levels + The table below lists the log levels for the C# SDK. -[block:parameters] -{ - "data": { - "h-0": "Log Level", - "h-1": "Explanation", - "0-0": "**OptimizelySDK.Logger.LogLevel.ERROR**", - "0-1": "Events that prevent feature flags from functioning correctly (for example, invalid datafile in initialization and invalid feature keys) are logged. The user can take action to correct.", - "1-0": "**OptimizelySDK.Logger.LogLevel.WARN**", - "1-1": "Events that don't prevent feature flags from functioning correctly, but can have unexpected outcomes (for example, future API deprecation, logger or error handler are not set properly, and nil values from getters) are logged.", - "2-0": "**OptimizelySDK.Logger.LogLevel.INFO**", - "2-1": "Events of significance (for example, activate started, activate succeeded, tracking started, and tracking succeeded) are logged. This is helpful in showing the lifecycle of an API call.", - "3-1": "Any information related to errors that can help us debug the issue (for example, the feature flag is not running, user is not included in the rollout) are logged.", - "3-0": "**OptimizelySDK.Logger.LogLevel.DEBUG**" - }, - "cols": 2, - "rows": 4 -} -[/block] \ No newline at end of file + +| Log Level | Explanation | +|--------------------------------------|----------------------------------------------------------------------------------------------------------------------| +| **OptimizelySDK.Logger.LogLevel.ERROR** | Events that prevent feature flags from functioning correctly (for example, invalid datafile in initialization and invalid feature keys) are logged. The user can take action to correct. | +| **OptimizelySDK.Logger.LogLevel.WARN** | Events that don't prevent feature flags from functioning correctly, but can have unexpected outcomes (for example, future API deprecation, logger or error handler are not set properly, and nil values from getters) are logged. | +| **OptimizelySDK.Logger.LogLevel.INFO** | Events of significance (for example, activate started, activate succeeded, tracking started, and tracking succeeded) are logged. This is helpful in showing the lifecycle of an API call. | +| **OptimizelySDK.Logger.LogLevel.DEBUG** | Any information related to errors that can help us debug the issue (for example, the feature flag is not running, user is not included in the rollout) are logged. | diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/090 - customize-error-handler-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/090 - customize-error-handler-csharp.md index 56c0d45a..0cc88f14 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/090 - customize-error-handler-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/090 - customize-error-handler-csharp.md @@ -5,18 +5,31 @@ hidden: false createdAt: "2019-09-12T13:44:18.412Z" updatedAt: "2019-09-12T13:48:38.080Z" --- -You can provide your own custom **error handler** logic to standardize across your production environment. -This error handler is called when SDK is not executed as expected, it may be because of arguments provided to the SDK or running in an environment where network or any other disruptions occur. +You can provide your own custom **error handler** logic to standardize across your production environment. + +This error handler is called when the SDK is not executed as expected, which may be due to arguments provided to the SDK or running in an environment where network or other disruptions occur. See the code example below. If the error handler is not overridden, a no-op error handler is used by default. -[block:code] + +```csharp +using System; +using OptimizelySDK.ErrorHandler; + +/** + * Creates a CustomErrorHandler and calls HandleError when an exception is raised by the SDK. + **/ +/** CustomErrorHandler should be inherited by IErrorHandler, a namespace of OptimizelySDK.ErrorHandler. + **/ +public class CustomErrorHandler : IErrorHandler { - "codes": [ + /// + /// Handle exceptions when raised by the SDK. + /// + /// object of Exception raised by the SDK. + public void HandleError(Exception exception) { - "code": "using System;\nusing OptimizelySDK.ErrorHandler;\n\n/**\n * Creates a CustomErrorHandler and calls HandleError when exception is raised by the SDK. \n **/\n/** CustomErrorHandler should be inherited by IErrorHandler, namespace of OptimizelySDK.ErrorHandler.\n **/\npublic class CustomErrorHandler : IErrorHandler\n{\n /// \n /// Handle exceptions when raised by the SDK.\n /// \n /// object of Exception raised by the SDK.\n public void HandleError(Exception exception)\n {\n throw new NotImplementedException();\n }\n}\n\n", - "language": "csharp" + throw new NotImplementedException(); } - ] } -[/block] \ No newline at end of file +``` \ No newline at end of file diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/100 - pass-in-audience-attributes-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/100 - pass-in-audience-attributes-csharp.md index 858f4f4a..e49d985e 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/100 - pass-in-audience-attributes-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/100 - pass-in-audience-attributes-csharp.md @@ -5,22 +5,17 @@ hidden: false createdAt: "2019-09-12T13:44:29.855Z" updatedAt: "2019-09-12T20:30:05.154Z" --- + You can pass strings, numbers, Booleans, and null as user attribute values. The example below shows how to pass in attributes. -[block:code] -{ - "codes": [ - { - "code": "UserAttributes attributes = new UserAttributes\n{\n { \"DEVICE\", \"iPhone\" },\n { \"AD_SOURCE\", \"my_campaign\" }\n};\n\nbool enabled = OptimizelyClient.IsFeatureEnabled(\"new_feature\", \"user123\", attributes);\n\n", - "language": "csharp" - } - ] -} -[/block] -[block:callout] +```csharp +UserAttributes attributes = new UserAttributes { - "type": "warning", - "title": "Important", - "body": "During audience evaluation, note that if you don't pass a valid attribute value for a given audience condition—for example, if you pass a string when the audience condition requires a Boolean, or if you simply forget to pass a value—then that condition will be skipped. The [SDK logs](doc:customize-logger-csharp) will include warnings when this occurs." -} -[/block] \ No newline at end of file + { "DEVICE", "iPhone" }, + { "AD_SOURCE", "my_campaign" } +}; + +bool enabled = OptimizelyClient.IsFeatureEnabled("new_feature", "user123", attributes); +``` +> **Important** +> During audience evaluation, note that if you don't pass a valid attribute value for a given audience condition—for example, if you pass a string when the audience condition requires a Boolean, or if you simply forget to pass a value—then that condition will be skipped. The [SDK logs](doc:customize-logger-csharp) will include warnings when this occurs. diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/110 - set-up-notification-listener-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/110 - set-up-notification-listener-csharp.md index eb8ecfd3..a08dd2da 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/110 - set-up-notification-listener-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/110 - set-up-notification-listener-csharp.md @@ -5,7 +5,8 @@ hidden: false createdAt: "2019-09-12T13:44:24.921Z" updatedAt: "2020-02-10T19:46:50.861Z" --- -Notification listeners trigger a callback function that you define when certain actions are triggered in the SDK. + +Notification listeners trigger a callback function that you define when certain actions are triggered in the SDK. The most common use case is to send a stream of all feature flag decisions to an analytics provider or to an internal data warehouse to join it with other data that you have about your users. @@ -15,11 +16,9 @@ To track feature usage: 3. Follow your analytics provider's documentation and send events from within the decision listener callback Steps 1 and 3 aren't covered in this documentation. However, setting up a 'DECISION' notification listener is covered below. -[block:api-header] -{ - "title": "Set up a DECISION notification listener" -} -[/block] + +# Set up a DECISION notification listener + The `DECISION` notification listener enables you to be notified whenever the SDK determines what decision value to return for a feature. The callback is triggered with the decision type, associated decision information, user ID, and attributes. `DECISION` listeners are triggered in multiple cases. Please see the tables at the end of this section for complete detail. @@ -27,58 +26,80 @@ The `DECISION` notification listener enables you to be notified whenever the SDK To set up a `DECISION` listener: 1. Define a callback to be called when the `DECISION` event is triggered 2. Add the callback to the notification center on the Optimizely instance +```csharp +using OptimizelySDK; +using OptimizelySDK.Entity; +using OptimizelySDK.Event; +using OptimizelySDK.Notifications; +using NotificationType = OptimizelySDK.Notifications.NotificationCenter.NotificationType; + +var optimizelyClient = new Optimizely(datafile); -The example code below shows how to add a listener, remove a listener, remove all listeners of a specific type (such as all decision listeners), and remove all listeners. -[block:code] +NotificationCenter.DecisionCallback OnDecision = (type, userId, userAttributes, decisionInfo) => { - "codes": [ - { - "code": "using OptimizelySDK;\nusing OptimizelySDK.Entity;\nusing OptimizelySDK.Event;\nusing OptimizelySDK.Notifications;\nusing NotificationType = OptimizelySDK.Notifications.NotificationCenter.NotificationType;\n\nvar optimizelyClient = new Optimizely(datafile);\n\n\nNotificationCenter.DecisionCallback OnDecision = (type, userId, userAttributes, decisionInfo) =>\n{\n if (type == \"feature\")\n {\n Console.WriteLine(string.Format(\"Feature access related information: {0}\", decisionInfo.ToString()));\n // Send data to analytics provider here\n }\n};\n\n// Add a Decision notification listener\nint decisionListenerId = optimizely.NotificationCenter.AddNotification(NotificationType.Decision, OnDecision);\n\n// Remove notification listener\noptimizelyClient.NotificationCenter.RemoveNotification(decisionListenerId);\n\n// Clear all notification listeners of a certain type\noptimizelyClient.NotificationCenter.ClearNotifications(NotificationType.Decision);\n\n// Clear all notifications\noptimizelyClient.NotificationCenter.ClearAllNotifications();\n\n", - "language": "csharp" - } - ] -} -[/block] + if (type == "feature") + { + Console.WriteLine(string.Format("Feature access related information: {0}", decisionInfo.ToString())); + // Send data to analytics provider here + } +}; + +// Add a Decision notification listener +int decisionListenerId = optimizely.NotificationCenter.AddNotification(NotificationType.Decision, OnDecision); + +// Remove notification listener +optimizelyClient.NotificationCenter.RemoveNotification(decisionListenerId); + +// Clear all notification listeners of a certain type +optimizelyClient.NotificationCenter.ClearNotifications(NotificationType.Decision); + +// Clear all notifications +optimizelyClient.NotificationCenter.ClearAllNotifications(); +``` The tables below show the information provided to the listener when it is triggered. -[block:parameters] -{ - "data": { - "0-0": "**type**", - "0-1": "string", - "0-2": "- `feature`: Returned when you use the Is Feature Enabled to determine if user has access to one specific feature, or Get Enabled Features method to determine if user has access to multiple features.\n\n- `ab-test`: Returned when you use activate or get_variation to determine the variation for a user, and the given experiment is not associated to any feature.\n\n- `feature-test`: Returned when you use activate or get_variation to determine the variation for a user, and the given experiment is associated to some feature.\n\n- `feature-variable`: Returned when you use one of the get_feature_variable methods to determine value of some feature variable. Such as get_feature_variable_boolean.", - "1-0": "**decision info**", - "1-1": "map", - "2-0": "**user ID**", - "2-1": "string", - "3-0": "**attributes**", - "3-1": "map", - "1-2": "Key-value map that consists of data corresponding to the decision and based on the `type`.\nSee the table below for valid fields and values for each `type`.", - "h-0": "Field", - "h-1": "Type", - "h-2": "Description", - "2-2": "The user ID.", - "3-2": "A map of custom key-value string pairs specifying attributes for the user that are used for audience targeting. Non-string values are only supported in the 3.0 SDK and above." - }, - "cols": 3, - "rows": 4 -} -[/block] - -[block:parameters] -{ - "data": { - "0-1": "- `featureKey`: String id of the feature.\n- `featureEnabled`: True or false based on whether the feature is enabled for the user.\n- `source`: String denoting how user gained access to the feature. Value is:\n - `feature-test` if the feature became enabled or disabled for the user because of some experiment associated with the feature.\n - `rollout` if the feature became enabled or disabled for the user because of the rollout configuration associated with the feature.\n- `sourceInfo`: Empty if the source is rollout. Holds experimentKey and variationKey if the source is feature-test.", - "0-0": "**feature**", - "h-0": "Type", - "h-1": "Decision Info Values", - "1-1": "- `experimentKey`: String key of the experiment\n- `variationKey`: String key of the variation to which the user got bucketed.", - "2-1": "- `experimentKey`: String key of the experiment\n- `variationKey`: String key of the variation to which the user got bucketed.", - "3-1": "- `featureKey`: String id of the feature.\n- `featureEnabled`: True or false based on whether the feature is enabled for the user.\n- `source`: String denoting how user gained access to the feature. Value is:\n - `feature-test` if the feature became enabled or disabled for the user because of some experiment associated with the feature.\n - `rollout` if the feature became enabled or disabled for the user because of the rollout configuration associated with the feature.\n- `variableKey`: String key of the feature variable.\n- `variableValue`: Mixed value of the feature variable for this user.\n- `variableType`: String type of the feature variable. Can be one of boolean, double, integer, string.\n- `sourceInfo`: Map denoting source of decision. Empty if the source is rollout. Holds experimentKey and variationKey if the source is feature-test.", - "3-0": "**feature-variable**", - "2-0": "**feature-test**", - "1-0": "**ab-test**" - }, - "cols": 2, - "rows": 4 -} -[/block] \ No newline at end of file +| Field | Type | Description | +|---------------|--------|----------------------------------------------------------------------------------------------------------------------------| +| **type** | string | - `feature`: Returned when you use the Is Feature Enabled to determine if the user has access to one specific feature, or Get Enabled Features method to determine if the user has access to multiple features.
- `ab-test`: Returned when you use activate or get_variation to determine the variation for a user, and the given experiment is not associated with any feature.
- `feature-test`: Returned when you use activate or get_variation to determine the variation for a user, and the given experiment is associated with some feature.
- `feature-variable`: Returned when you use one of the get_feature_variable methods to determine the value of some feature variable. Such as get_feature_variable_boolean. | +| **decision info** | map | Key-value map that consists of data corresponding to the decision and based on the `type`. | +| **user ID** | string | The user ID. | +| **attributes** | map | A map of custom key-value string pairs specifying attributes for the user that are used for audience targeting. Non-string values are only supported in the 3.0 SDK and above. | +--- +title: "Decision Listener Information" +--- + +## Decision Info Values + +### feature + +| Field | Decision Info Values | +|-------------------|----------------------------------------------------------------------------------------------------------------------| +| **featureKey** | String id of the feature. | +| **featureEnabled** | True or false based on whether the feature is enabled for the user. | +| **source** | String denoting how user gained access to the feature. Value is:
- `feature-test` if the feature became enabled or disabled for the user because of some experiment associated with the feature.
- `rollout` if the feature became enabled or disabled for the user because of the rollout configuration associated with the feature. | +| **sourceInfo** | Empty if the source is rollout. Holds `experimentKey` and `variationKey` if the source is feature-test. | + +### ab-test + +| Field | Decision Info Values | +|-------------------|--------------------------------------------------------| +| **experimentKey** | String key of the experiment. | +| **variationKey** | String key of the variation to which the user got bucketed. | + +### feature-test + +| Field | Decision Info Values | +|-------------------|--------------------------------------------------------| +| **experimentKey** | String key of the experiment. | +| **variationKey** | String key of the variation to which the user got bucketed. | + +### feature-variable + +| Field | Decision Info Values | +|-------------------|----------------------------------------------------------------------------------------------------------------------| +| **featureKey** | String id of the feature. | +| **featureEnabled** | True or false based on whether the feature is enabled for the user. | +| **source** | String denoting how user gained access to the feature. Value is:
- `feature-test` if the feature became enabled or disabled for the user because of some experiment associated with the feature.
- `rollout` if the feature became enabled or disabled for the user because of the rollout configuration associated with the feature. | +| **variableKey** | String key of the feature variable. | +| **variableValue** | Mixed value of the feature variable for this user. | +| **variableType** | String type of the feature variable. Can be one of boolean, double, integer, string. | +| **sourceInfo** | Map denoting source of decision. Empty if the source is rollout. Holds `experimentKey` and `variationKey` if the source is feature-test. | diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/120 - activate-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/120 - activate-csharp.md index 69dbe29d..2ab5f4ce 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/120 - activate-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/120 - activate-csharp.md @@ -5,18 +5,15 @@ hidden: false createdAt: "2019-09-12T13:51:40.641Z" updatedAt: "2019-09-12T20:31:54.396Z" --- + Activates an A/B test for the specified user to start an experiment: determines whether they qualify for the experiment, buckets a qualified user into a variation, and sends an impression event to Optimizely. -[block:api-header] -{ - "title": "Version" -} -[/block] + +## Version + 3.1.1 -[block:api-header] -{ - "title": "Description" -} -[/block] + +## Description + This method requires an experiment key, user ID, and (optionally) attributes. The experiment key must match the experiment key you created when you set up the experiment in the Optimizely app. The user ID string uniquely identifies the participant in the experiment. If the user qualifies for the experiment, the method returns the variation key that was chosen. If the user was not eligible—for example, because the experiment was not running in this environment or the user didn't match the targeting attributes and audience conditions—then the method returns null. @@ -34,91 +31,49 @@ Activate also respects customization of the SDK client. Throughout this process, * Raises errors via the error handler. * Remembers variation assignments via the User Profile Service. * Alerts notification listeners, as applicable. -[block:callout] -{ - "type": "info", - "title": "Note", - "body": "For more information on how the variation is chosen, see [How bucketing works](how-bucketing-works)." -} -[/block] - -[block:api-header] -{ - "title": "Parameters" -} -[/block] + +> **Note** +> For more information on how the variation is chosen, see [How bucketing works](how-bucketing-works). + +## Parameters + The parameter names for C# are listed below. -[block:parameters] -{ - "data": { - "h-0": "Parameter", - "h-1": "Type", - "h-2": "Description", - "0-0": "**experiment key**\n*required*", - "0-1": "string", - "1-0": "**user ID**\n*required*", - "1-1": "string", - "0-2": "The experiment to activate.", - "1-2": "The user ID.", - "2-0": "**userAttributes**\n*optional*", - "2-1": "map", - "2-2": "A map of custom key-value string pairs specifying attributes for the user that are used for audience targeting and results segmentation. Non-string values are only supported in the 3.0 SDK and above." - }, - "cols": 3, - "rows": 3 -} -[/block] - -[block:api-header] -{ - "title": "Returns" -} -[/block] -null|Variation Representing variation -[block:api-header] -{ - "title": "Example" -} -[/block] - -[block:code] -{ - "codes": [ - { - "code": "using OptimizelySDK.Entity;\n\nvar attributes = new UserAttributes {\n { \"device\", \"iPhone\" },\n { \"lifetime\", 24738388 },\n { \"is_logged_in\", true },\n};\n\nvar variation = optimizelyClient.Activate(\"my_experiment_key\", \"user_123\", attributes);\n\n", - "language": "csharp" - } - ] -} -[/block] - -[block:api-header] -{ - "title": "Side effects" -} -[/block] -The table lists other other Optimizely functionality that may be triggered by using this method. -[block:parameters] -{ - "data": { - "h-0": "Functionality", - "h-1": "Description", - "0-0": "Impressions", - "0-1": "Accessing this method triggers an impression if the user is included in an active A/B test. \n\nSee [Implement impressions](doc:implement-impressions) for guidance on when to use Activate versus [Get Variation](doc:get-variation-csharp).", - "1-0": "Notification Listeners", - "1-1": "In SDKs v3.0 and earlier: Activate invokes the `ACTIVATE` [notification listener](doc:set-up-notification-listener-csharp) if the user is included in an active A/B test.\n\nIn SDKs v3.1 and later: Invokes the `DECISION` notification listener if this listener is enabled." - }, - "cols": 2, - "rows": 2 -} -[/block] - -[block:api-header] -{ - "title": "Notes" -} -[/block] + +| Parameter | Type | Description | +|-------------------|--------|----------------------------------------------------------------------------------------------------------| +| **experiment key** **(required)** | string | The experiment to activate. | +| **user ID** **(required)** | string | The user ID. | +| **userAttributes** **(optional)** | map | A map of custom key-value string pairs specifying attributes for the user that are used for audience targeting and results segmentation. Non-string values are only supported in the 3.0 SDK and above. | + +## Returns + +`null` or `Variation`: Representing variation + +## Example + +```csharp +using OptimizelySDK.Entity; + +var attributes = new UserAttributes { + { "device", "iPhone" }, + { "lifetime", 24738388 }, + { "is_logged_in", true }, +}; + +var variation = optimizelyClient.Activate("my_experiment_key", "user_123", attributes); +``` +## Side effects + +The table lists other Optimizely functionality that may be triggered by using this method. + +| Functionality | Description | +|-------------------|---------------------------------------------------------------------------------------------------------------| +| Impressions | Accessing this method triggers an impression if the user is included in an active A/B test. See [Implement impressions](doc:implement-impressions) for guidance on when to use Activate versus [Get Variation](doc:get-variation-csharp). | +| Notification Listeners | In SDKs v3.0 and earlier: Activate invokes the `ACTIVATE` [notification listener](doc:set-up-notification-listener-csharp) if the user is included in an active A/B test. In SDKs v3.1 and later: Invokes the `DECISION` notification listener if this listener is enabled. | +## Notes + ### Activate versus Get Variation + Use Activate when the visitor actually sees the experiment. Use Get Variation when you need to know which bucket a visitor is in before showing the visitor the experiment. Impressions are tracked by [Is Feature Enabled](doc:is-feature-enabled) when there is a feature test running on the feature and the visitor qualifies for that feature test. For example, suppose you want your web server to show a visitor variation_1 but don't want the visitor to count until they open a feature that isn't visible when the variation loads, like a modal. In this case, use Get Variation in the backend to specify that your web server should respond with variation_1, and use Activate in the front end when the visitor sees the experiment. @@ -126,17 +81,9 @@ For example, suppose you want your web server to show a visitor variation_1 but Also, use Get Variation when you're trying to align your Optimizely results with client-side third-party analytics. In this case, use Get Variation to retrieve the variation—and even show it to the visitor—but only call Activate when the analytics call goes out. See [Implement impressions](doc:implement-impressions) for more information about whether to use Activate or Get Variation for a call. -[block:callout] -{ - "type": "info", - "title": "Note", - "body": "Conversion events can only be attributed to experiments with previously tracked impressions. Impressions are tracked by Activate, not by Get Variation. As a general rule, Optimizely impressions are required for experiment results and not only for billing." -} -[/block] - -[block:api-header] -{ - "title": "Source files" -} -[/block] -The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). \ No newline at end of file +> **Note** +> Conversion events can only be attributed to experiments with previously tracked impressions. Impressions are tracked by Activate, not by Get Variation. As a general rule, Optimizely impressions are required for experiment results and not only for billing. + +## Source files + +The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/130 - get-enabled-features-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/130 - get-enabled-features-csharp.md index 432f0cb5..20d15512 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/130 - get-enabled-features-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/130 - get-enabled-features-csharp.md @@ -5,71 +5,38 @@ hidden: false createdAt: "2019-09-12T13:53:46.225Z" updatedAt: "2019-09-12T20:33:07.026Z" --- + Retrieves a list of features that are enabled for the user. Invoking this method is equivalent to running [Is Feature Enabled](doc:is-feature-enabled-csharp) for each feature in the datafile sequentially. -This method takes into account the user `attributes` passed in, to determine if the user is part of the audience that qualifies for the experiment. -[block:api-header] -{ - "title": "Version" -} -[/block] +This method takes into account the user `attributes` passed in, to determine if the user is part of the audience that qualifies for the experiment. + +## Version + SDK v3.0 -[block:api-header] -{ - "title": "Description" -} -[/block] + +## Description This method iterates through all feature flags and for each feature flag invokes [Is Feature Enabled](doc:is-feature-enabled-csharp). If a feature is enabled, this method adds the feature’s key to the return list. -[block:api-header] -{ - "title": "Parameters" -} -[/block] +## Parameters + The table below lists the required and optional parameters in C#. -[block:parameters] -{ - "data": { - "h-0": "Parameter", - "h-1": "Type", - "h-2": "Description", - "0-0": "**userId**\n*required*", - "0-1": "string", - "1-0": "**userAttributes**\n*optional*", - "1-1": "map", - "0-2": "The ID of the user to check.", - "1-2": "A map of custom key-value string pairs specifying attributes for the user that are used for audience targeting. Non-string values are only supported in the 3.0 SDK and above." - }, - "cols": 3, - "rows": 2 -} -[/block] -[block:api-header] -{ - "title": "Returns" -} -[/block] +| Parameter | Type | Description | +|------------------|--------|----------------------------------------------------------------------------------------------------------| +| **userId**
*required* | string | The ID of the user to check. | +| **userAttributes**
*optional* | map | A map of custom key-value string pairs specifying attributes for the user that are used for audience targeting. Non-string values are only supported in the 3.0 SDK and above. | + +## Returns + A list of the feature keys that are enabled for the user, or an empty list if no features could be found for the specified user. -[block:api-header] -{ - "title": "Examples" -} -[/block] + +## Examples + This section shows a simple example of how you can use the method. -[block:code] -{ - "codes": [ - { - "code": "var actualFeaturesList = OptimizelyMock.Object.GetEnabledFeatures(TestUserId, userAttributes);\n\n", - "language": "csharp" - } - ] -} -[/block] -[block:api-header] -{ - "title": "Source files" -} -[/block] -The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). \ No newline at end of file +```csharp +var actualFeaturesList = OptimizelyMock.Object.GetEnabledFeatures(TestUserId, userAttributes); + +``` +## Source files + +The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/140 - get-feature-variable-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/140 - get-feature-variable-csharp.md index 8e14a3fd..1a1a4680 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/140 - get-feature-variable-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/140 - get-feature-variable-csharp.md @@ -5,7 +5,8 @@ hidden: false createdAt: "2019-09-12T13:51:45.265Z" updatedAt: "2019-09-16T23:48:13.270Z" --- -Evaluates the specified feature variable of a specific variable type and returns its value. + +Evaluates the specified feature variable of a specific variable type and returns its value. This method is used to evaluate and return a feature variable. Multiple versions of this method are available and are named according to the data type they return: * [Boolean](#section-boolean) @@ -18,142 +19,80 @@ This method takes into account the user `attributes` passed in, to determine if ### Boolean Returns the value of the specified Boolean variable. -[block:code] -{ - "codes": [ - { - "code": "public bool? GetFeatureVariableBoolean(string featureKey, string variableKey, string userId, UserAttributes userAttributes = null)\n \n ", - "language": "csharp" - } - ] -} -[/block] + +```csharp +public bool? GetFeatureVariableBoolean(string featureKey, string variableKey, string userId, UserAttributes userAttributes = null) +``` + ### Double Returns the value of the specified double variable. -[block:code] -{ - "codes": [ - { - "code": "public double? GetFeatureVariableDouble(string featureKey, string variableKey, string userId, UserAttributes userAttributes = null)\n \n ", - "language": "csharp" - } - ] -} -[/block] + +```csharp +public double? GetFeatureVariableDouble(string featureKey, string variableKey, string userId, UserAttributes userAttributes = null) +``` + ### Integer Returns the value of the specified integer variable. -[block:code] -{ - "codes": [ - { - "code": "public int? GetFeatureVariableInteger(string featureKey, string variableKey, string userId, UserAttributes userAttributes = null)\n \n ", - "language": "csharp" - } - ] -} -[/block] + +```csharp +public int? GetFeatureVariableInteger(string featureKey, string variableKey, string userId, UserAttributes userAttributes = null) +``` + ### String Returns the value of the specified string variable. -[block:code] -{ - "codes": [ - { - "code": "public string GetFeatureVariableString(string featureKey, string variableKey, string userId, UserAttributes userAttributes = null)\n \n ", - "language": "csharp" - } - ] -} -[/block] - -[block:api-header] -{ - "title": "Version" -} -[/block] + +```csharp +public string GetFeatureVariableString(string featureKey, string variableKey, string userId, UserAttributes userAttributes = null) +``` +## Version + SDK v3.0, v3.1 -[block:api-header] -{ - "title": "Description" -} -[/block] + +## Description + Each of the Get Feature Variable methods follows the same logic as [Is Feature Enabled](doc:is-feature-enabled-csharp): 1. Evaluate any feature tests running for a user. 2. Check the default configuration on a rollout. The default value is returned if neither of these are applicable for the specified user, or if the user is in a variation where the feature is disabled. -[block:callout] -{ - "type": "warning", - "title": "Important", - "body": "Unlike [Is Feature Enabled](doc:is-feature-enabled-csharp), the Get Feature Variable methods do not trigger an impression event. This means that if you're running a feature test, events won't be counted until you call Is Feature Enabled. If you don't call Is Feature Enabled, you won't see any visitors on your results page." -} -[/block] - -[block:api-header] -{ - "title": "Parameters" -} -[/block] + +> **Important** +> Unlike [Is Feature Enabled](doc:is-feature-enabled-csharp), the Get Feature Variable methods do not trigger an impression event. This means that if you're running a feature test, events won't be counted until you call Is Feature Enabled. If you don't call Is Feature Enabled, you won't see any visitors on your results page. + +## Parameters + Required and optional parameters in C# are listed below. -[block:parameters] -{ - "data": { - "h-0": "Parameter", - "h-1": "Type", - "h-2": "Description", - "0-0": "**featureKey**\n*required*", - "0-1": "string", - "1-0": "**variableKey**\n*required*", - "1-1": "string", - "0-2": "The feature key is defined from the Features dashboard.", - "1-2": "The key that identifies the feature variable.", - "2-0": "**userId**\n*required*", - "3-0": "**userAttributes**\n*required*", - "2-1": "string", - "3-1": "map", - "2-2": "The user ID string uniquely identifies the participant in the experiment.", - "3-2": "A map of custom key-value string pairs specifying attributes for the user that are used for audience targeting and results segmentation. Non-string values are only supported in the 3.0 SDK and above." - }, - "cols": 3, - "rows": 4 -} -[/block] - -[block:api-header] -{ - "title": "Returns" -} -[/block] -Feature variable value or null -[block:api-header] -{ - "title": "Example" -} -[/block] - -[block:code] -{ - "codes": [ - { - "code": "using OptimizelySDK.Entity;\n\nvar attributes = new UserAttributes {\n { \"device\", \"iPhone\" },\n { \"lifetime\", 24738388 },\n { \"is_logged_in\", true },\n};\n\nvar featureVariableValue = optimizelyClient.GetFeatureVariableDouble(\"my_feature_key\", \"double_variable_key\", \"user_123\", attributes);\n\n", - "language": "csharp" - } - ] -} -[/block] - -[block:api-header] -{ - "title": "Side effects" -} -[/block] -In SDKs v3.1 and later: Invokes the `DECISION` [notification listener](doc:set-up-notification-listener-csharp) if this listener is enabled. -[block:api-header] -{ - "title": "Source files" -} -[/block] -The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). \ No newline at end of file + +| Parameter | Type | Description | +|------------------|--------|----------------------------------------------------------------------------------------------------------| +| **featureKey**
*required* | string | The feature key is defined from the Features dashboard. | +| **variableKey**
*required* | string | The key that identifies the feature variable. | +| **userId**
*required* | string | The user ID string uniquely identifies the participant in the experiment. | +| **userAttributes**
*required* | map | A map of custom key-value string pairs specifying attributes for the user that are used for audience targeting and results segmentation. Non-string values are only supported in the 3.0 SDK and above. | +## Returns + +Feature variable value or `null` + +## Example + +```csharp +using OptimizelySDK.Entity; + +var attributes = new UserAttributes { + { "device", "iPhone" }, + { "lifetime", 24738388 }, + { "is_logged_in", true }, +}; + +var featureVariableValue = optimizelyClient.GetFeatureVariableDouble("my_feature_key", "double_variable_key", "user_123", attributes); +``` +## Side effects + +In SDKs v3.1 and later: Invokes the `DECISION` [notification listener](doc:set-up-notification-listener-csharp) if this listener is enabled. + +## Source files + +The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/150 - get-forced-variation-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/150 - get-forced-variation-csharp.md index bad6a204..8f549cd8 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/150 - get-forced-variation-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/150 - get-forced-variation-csharp.md @@ -5,79 +5,40 @@ hidden: false createdAt: "2019-09-12T13:51:51.169Z" updatedAt: "2019-09-12T20:34:30.074Z" --- + Returns the forced variation set by [Set Forced Variation](doc:set-forced-variation-csharp), or `null` if no variation was forced. A user can be forced into a variation for a given experiment for the lifetime of the Optimizely client. This method gets the variation that the user has been forced into. The forced variation value is runtime only and does not persist across application launches. -[block:api-header] -{ - "title": "Version" -} -[/block] + +## Version + SDK v3.0, v3.1 -[block:api-header] -{ - "title": "Description" -} -[/block] + +## Description + Forced bucketing variations take precedence over whitelisted variations, variations saved in a User Profile Service (if one exists), and the normal bucketed variation. Variations are overwritten when [Set Forced Variation](doc:set-forced-variation-csharp) is invoked. -[block:callout] -{ - "type": "info", - "title": "Note", - "body": "A forced variation only persists for the lifetime of an Optimizely client." -} -[/block] -[block:api-header] -{ - "title": "Parameters" -} -[/block] +> **Note** +> A forced variation only persists for the lifetime of an Optimizely client. + +## Parameters + This table lists the required and optional parameters for the C# SDK. -[block:parameters] -{ - "data": { - "h-0": "Parameter", - "h-1": "Type", - "h-2": "Description", - "0-0": "**experimentKey**\n*required*", - "0-1": "string", - "1-0": "**userId**\n*required*", - "1-1": "string", - "0-2": "The key of the experiment to retrieve the forced variation.", - "1-2": "The ID of the user in the forced variation." - }, - "cols": 3, - "rows": 2 -} -[/block] -[block:api-header] -{ - "title": "Returns" -} -[/block] -null|string The variation key. -[block:api-header] -{ - "title": "Example" -} -[/block] +| Parameter | Type | Description | +|-------------------|--------|---------------------------------------------| +| **experimentKey**
*required* | string | The key of the experiment to retrieve the forced variation. | +| **userId**
*required* | string | The ID of the user in the forced variation. | + +## Returns + +`null|string`: The variation key. + +## Example -[block:code] -{ - "codes": [ - { - "code": "var variation = optimizelyClient.GetForcedVariation(“my_experiment_key”, “user_123”);\n\n", - "language": "csharp" - } - ] -} -[/block] +```csharp +var variation = optimizelyClient.GetForcedVariation("my_experiment_key", "user_123"); +``` +## Source files -[block:api-header] -{ - "title": "Source files" -} -[/block] -The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). \ No newline at end of file +The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/160 - get-variation-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/160 - get-variation-csharp.md index 491743ed..b4994b69 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/160 - get-variation-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/160 - get-variation-csharp.md @@ -5,204 +5,222 @@ hidden: false createdAt: "2019-09-12T13:51:54.916Z" updatedAt: "2019-09-12T20:35:30.799Z" --- + Returns a variation where the visitor will be bucketed, without triggering an impression. -[block:api-header] -{ - "title": "Version" -} -[/block] + +## Version + SDK v3.0, v3.1 -[block:api-header] -{ - "title": "Description" -} -[/block] -Takes the same arguments and returns the same values as [Activate](doc:activate-csharp), but without sending an impression network request. The behavior of the two methods is identical otherwise. + +## Description + +Takes the same arguments and returns the same values as [Activate](doc:activate-csharp), but without sending an impression network request. The behavior of the two methods is identical otherwise. Use Get Variation if Activate has been called and the current variation assignment is needed for a given experiment and user. This method bypasses redundant network requests to Optimizely. See [Implement impressions](doc:implement-impressions) for guidance on when to use each method. -[block:api-header] -{ - "title": "Parameters" -} -[/block] + +## Parameters + This table lists the required and optional parameters for the C# SDK. -[block:parameters] -{ - "data": { - "h-0": "Parameter", - "h-1": "Type", - "h-2": "Description", - "0-0": "**experimentey**\n*required*", - "0-1": "string", - "1-0": "**userID**\n*required*", - "1-1": "string", - "0-2": "The key of the experiment.", - "1-2": "The ID of the user.", - "2-2": "A map of custom key-value string pairs specifying attributes for the user that are used for audience targeting and results segmentation. Non-string values are only supported in the 3.0 SDK and above.", - "2-1": "map", - "2-0": "**attributes**\n*optional*" - }, - "cols": 3, - "rows": 3 -} -[/block] + +| Parameter | Type | Description | +|-----------------|--------|------------------------------------------------------------------------------------------------------| +| **experimentKey**
*required* | string | The key of the experiment. | +| **userID**
*required* | string | The ID of the user. | +| **attributes**
*optional* | map | A map of custom key-value string pairs specifying attributes for the user that are used for audience targeting and results segmentation. Non-string values are only supported in the 3.0 SDK and above. | + + The specific parameter names for each supported language are as follows: -[block:code] -{ - "codes": [ - { - "code": "experimentKey\nuserId\nattributes\n\n", - "language": "text", - "name": "Android" - }, - { - "code": "experimentKey\nuserId\nuserAttributes\n\n", - "language": "text", - "name": "C#" - }, - { - "code": "experimentKey\nuserId\nattributes\n\n", - "language": "text", - "name": "Java" - }, - { - "code": "experimentKey\nuserId\nattributes\n\n", - "language": "text", - "name": "JavaScript" - }, - { - "code": "experimentKey\nuserId\nattributes\n\n", - "language": "text", - "name": "Node" - }, - { - "code": "experimentKey\nuserId\nattributes\n\n", - "language": "text", - "name": "Objective-C" - }, - { - "code": "experimentKey\nuserId\nattributes\n\n", - "language": "php", - "name": "PHP" - }, - { - "code": "experiment_key\nuser_id\nattributes\n\n", - "language": "text", - "name": "Python" - }, - { - "code": "experiment_key\nuser_id\nattributes\n\n", - "language": "text", - "name": "Ruby" - }, - { - "code": "experimentKey\nuserId\nattributes\n\n", - "language": "text", - "name": "Swift" - } - ] -} -[/block] +## Parameter Names for Supported Languages + +The specific parameter names for each supported language are as follows: + +### Android + +experimentKey +userId +attributes + +### C# +experimentKey +userId +userAttributes + +### Java +experimentKey +userId +attributes + +### JavaScript +experimentKey +userId +attributes + +### Node +experimentKey +userId +attributes + +### Objective-C +experimentKey +userId +attributes + +and same for PHP, Python, Ruby and Swift. + +## Returns -[block:api-header] -{ - "title": "Returns" -} -[/block] The table below lists the specific information returned for each supported language. -[block:parameters] -{ - "data": { - "h-0": "Language", - "h-1": "Return", - "0-0": "Android", - "0-1": "@return the variation for the provided experiment key, user id, and attributes", - "1-1": "null|Variation Representing variation", - "1-0": "C#", - "2-1": "@return the variation for the provided experiment key, user id, and attributes", - "2-0": "Java", - "3-0": "JavaScript (browser)", - "4-0": "JavaScript (Node)", - "5-0": "Objective-C", - "6-0": "PHP", - "7-0": "Python", - "8-0": "Ruby", - "9-0": "Swift", - "3-1": "@return {string|null} variation key", - "4-1": "@return {string|null} variation key", - "5-1": "@return The variation into which the user is bucketed. This value can be nil.", - "6-1": "@return null|string Representing the variation key", - "7-1": "Returns: Variation key representing the variation in which the user will be bucketed. None if user is not in experiment or if experiment is not running.", - "8-1": "@return [variation key] where visitor will be bucketed.\n@return [nil] if the experiment is not running, if the user is not in the experiment, or if the datafile is invalid.", - "9-1": "@return The variation into which the user was bucketed. This value can be nil." - }, - "cols": 2, - "rows": 10 -} -[/block] -[block:api-header] -{ - "title": "Example" -} -[/block] - -[block:code] -{ - "codes": [ - { - "code": "import com.optimizely.ab.config.Variation;\n\nMap attributes = new HashMap<>();\nattributes.put(\"device\", \"iPhone\");\nattributes.put(\"lifetime\", 24738388);\nattributes.put(\"is_logged_in\", true);\n\nVariation variation = optimizelyClient.getVariation(\"my_experiment_key\", \"user_123\", attributes);\n\n", - "language": "java", - "name": "Android" - }, - { - "code": "using OptimizelySDK.Entity;\n\nvar attributes = new UserAttributes {\n { \"device\", \"iPhone\" },\n { \"lifetime\", 24738388 },\n { \"is_logged_in\", true },\n};\n\nvar variation = optimizelyClient.GetVariation(\"my_experiment_key\", \"user_123\", attributes);\n\n", - "language": "csharp" - }, - { - "code": "import com.optimizely.ab.config.Variation;\n\nMap attributes = new HashMap<>();\nattributes.put(\"device\", \"iPhone\");\nattributes.put(\"lifetime\", 24738388);\nattributes.put(\"is_logged_in\", true);\n\nVariation variation = optimizelyClient.getVariation(\"my_experiment_key\", \"user_123\", attributes);\n\n", - "language": "java" - }, - { - "code": "var attributes = {\n device: 'iPhone',\n lifetime: 24738388,\n is_logged_in: true,\n};\n\nvar variationKey = optimizelyClient.getVariation('my_experiment_key', 'user_123', attributes);\n\n", - "language": "javascript" - }, - { - "code": "var attributes = {\n device: 'iPhone',\n lifetime: 24738388,\n is_logged_in: true,\n};\n\nvar variationKey = optimizelyClient.getVariation('my_experiment_key', 'user_123', attributes);\n\n", - "language": "javascript", - "name": "Node" - }, - { - "code": "NSDictionary *attributes = @{\n @\"device\": @\"iPhone\",\n @\"lifetime\": @24738388,\n @\"is_logged_in\": @true\n};\n\nNSString *variationKey = [optimizely getVariationKeyWithExperimentKey: @\"my_experiment_key\" \n userId:@\"user_123\"\n attributes:attributes\n error:nil];\n\n\n", - "language": "objectivec" - }, - { - "code": "$attributes = [\n 'device' => 'iPhone',\n 'lifetime' => 24738388,\n 'is_logged_in' => true\n];\n\n$variationKey = $optimizelyClient->getVariation('my_experiment_key', 'user_123', $attributes);\n\n", - "language": "php" - }, - { - "code": "attributes = {\n 'device': 'iPhone',\n 'lifetime': 24738388,\n 'is_logged_in': True,\n}\n\nvariation_key = optimizely_client.get_variation('my_experiment_key', 'user_123', attributes)\n\n", - "language": "python" - }, - { - "code": "attributes = {\n 'device' => 'iPhone',\n 'lifetime' => 24738388,\n 'is_logged_in' => true,\n}\n\nvariation_key = optimizely_client.get_variation('my_experiment_key', 'user_123', attributes)\n\n", - "language": "ruby" - }, - { - "code": "let attributes = [\n \"device\": \"iPhone\",\n \"lifetime\": 24738388,\n \"is_logged_in\": true,\n]\n\nlet variationKey = try? optimizely.getVariationKey(experimentKey: \"my_experiment_key\",\n\t\t\t\t\t\t\t\t\t\t\t\tuserId: \"user_123\",\n attributes: attributes)\n\n", - "language": "swift" - } - ] +| Language | Return | +|-------------------------|-------------------------------------------------------------------------------------------------| +| Android | `@return` the variation for the provided experiment key, user id, and attributes | +| C# | `@return` the variation for the provided experiment key, user id, and attributes | +| Java | `@return` the variation for the provided experiment key, user id, and attributes | +| JavaScript (browser) | `@return` {string|null} variation key | +| JavaScript (Node) | `@return` {string|null} variation key | +| Objective-C | `@return` The variation into which the user is bucketed. This value can be nil. | +| PHP | `@return` null|string Representing the variation key | +| Python | Returns: Variation key representing the variation in which the user will be bucketed. None if user is not in experiment or if experiment is not running. | +| Ruby | `@return` [variation key] where visitor will be bucketed.\n`@return` [nil] if the experiment is not running, if the user is not in the experiment, or if the datafile is invalid. | +| Swift | `@return` The variation into which the user was bucketed. This value can be nil. | + +## Example + +Here are usage examples for each supported language: + +### Android + +```java +import com.optimizely.ab.config.Variation; + +Map attributes = new HashMap<>(); +attributes.put("device", "iPhone"); +attributes.put("lifetime", 24738388); +attributes.put("is_logged_in", true); + +Variation variation = optimizelyClient.getVariation("my_experiment_key", "user_123", attributes); +``` + +### C# + +```csharp +using OptimizelySDK.Entity; + +var attributes = new UserAttributes { + { "device", "iPhone" }, + { "lifetime", 24738388 }, + { "is_logged_in", true }, +}; + +var variation = optimizelyClient.GetVariation("my_experiment_key", "user_123", attributes); +``` + +### Android + +```java +import com.optimizely.ab.config.Variation; + +Map attributes = new HashMap<>(); +attributes.put("device", "iPhone"); +attributes.put("lifetime", 24738388); +attributes.put("is_logged_in", true); + +Variation variation = optimizelyClient.getVariation("my_experiment_key", "user_123", attributes); +``` + +### JavaScript (browser) +```javascript +var attributes = { + device: 'iPhone', + lifetime: 24738388, + is_logged_in: true, +}; + +var variationKey = optimizelyClient.getVariation('my_experiment_key', 'user_123', attributes); + +``` + +### JavaScript (Node) +```javascript +var attributes = { + device: 'iPhone', + lifetime: 24738388, + is_logged_in: true, +}; + +var variationKey = optimizelyClient.getVariation('my_experiment_key', 'user_123', attributes); + +``` + +### Objective-C +```objective-c +NSDictionary *attributes = @{ + @"device": @"iPhone", + @"lifetime": @24738388, + @"is_logged_in": @true +}; + +NSString *variationKey = [optimizely getVariationKeyWithExperimentKey: @"my_experiment_key" + userId: @"user_123" + attributes: attributes + error:nil]; + +``` + +### PHP +```php +$attributes = [ + 'device' => 'iPhone', + 'lifetime' => 24738388, + 'is_logged_in' => true +]; + +$variationKey = $optimizelyClient->getVariation('my_experiment_key', 'user_123', $attributes); + +``` + +### Python +```python +attributes = { + 'device': 'iPhone', + 'lifetime': 24738388, + 'is_logged_in': True, } -[/block] -[block:api-header] -{ - "title": "Notes" +variation_key = optimizely_client.get_variation('my_experiment_key', 'user_123', attributes) + +``` + +### Ruby +```ruby +attributes = { + 'device' => 'iPhone', + 'lifetime' => 24738388, + 'is_logged_in' => true, } -[/block] + +variation_key = optimizely_client.get_variation('my_experiment_key', 'user_123', attributes) + +``` + +### Swift +```swift +let attributes = [ + "device": "iPhone", + "lifetime": 24738388, + "is_logged_in": true, +] + +let variationKey = try? optimizely.getVariationKey(experimentKey: "my_experiment_key", + userId: "user_123", + attributes: attributes) + +``` + +## Notes + ### Activate versus Get Variation Use Activate when the visitor actually sees the experiment. Use Get Variation when you need to know which bucket a visitor is in before showing the visitor the experiment. Impressions are tracked by [Is Feature Enabled](doc:is-feature-enabled-csharp) when there is a feature test running on the feature and the visitor qualifies for that feature test. @@ -212,17 +230,9 @@ For example, suppose you want your web server to show a visitor variation_1 but Also, use Get Variation when you're trying to align your Optimizely results with client-side third-party analytics. In this case, use Get Variation to retrieve the variation, and even show it to the visitor, but only call Activate when the analytics call goes out. See [Implement impressions](doc:implement-impressions) for more information about whether to use Activate or Get Variation for a call. -[block:callout] -{ - "type": "warning", - "title": "Important", - "body": "Conversion events can only be attributed to experiments with previously tracked impressions. Impressions are tracked by Activate, not by Get Variation. As a general rule, Optimizely impressions are required for experiment results and not only for billing." -} -[/block] -[block:api-header] -{ - "title": "Source files" -} -[/block] -The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). \ No newline at end of file +> **Important:** Conversion events can only be attributed to experiments with previously tracked impressions. Impressions are tracked by Activate, not by Get Variation. As a general rule, Optimizely impressions are required for experiment results and not only for billing. + +## Source files + +The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/170 - is-feature-enabled-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/170 - is-feature-enabled-csharp.md index 8badc3ae..be63b2f7 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/170 - is-feature-enabled-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/170 - is-feature-enabled-csharp.md @@ -1,80 +1,45 @@ ---- -title: "Is Feature Enabled" -slug: "is-feature-enabled-csharp" -hidden: false -createdAt: "2019-09-12T13:51:59.213Z" -updatedAt: "2019-09-12T20:36:35.281Z" ---- +## Is Feature Enabled + Determines whether a feature is enabled for a given user. The purpose of this method is to allow you to separate the process of developing and deploying features from the decision to turn on a feature. Build your feature and deploy it to your application behind this flag, then turn the feature on or off for specific users. -[block:api-header] -{ - "title": "Version" -} -[/block] + +### Version + SDK v3.0 -[block:api-header] -{ - "title": "Description" -} -[/block] + +### Description + This method traverses the client's datafile and checks the feature flag for the feature key that you specify. 1. Analyzes the user's attributes. 2. Hashes the userID. -The method then evaluates the feature rollout for a user. The method checks whether the rollout is enabled, whether the user qualifies for the audience targeting, and then randomly assigns either `on` or `off` based on the appropriate traffic allocation. If the feature rollout is on for a qualified user, the method returns `true`. -[block:api-header] -{ - "title": "Parameters" -} -[/block] +The method then evaluates the feature rollout for a user. The method checks whether the rollout is enabled, whether the user qualifies for the audience targeting, and then randomly assigns either `on` or `off` based on the appropriate traffic allocation. If the feature rollout is on for a qualified user, the method returns `true`. + +### Parameters + The table below lists the required and optional parameters in C#. -[block:parameters] -{ - "data": { - "h-0": "Parameter", - "h-1": "Type", - "0-0": "**featureKey**\n_required_", - "0-1": "string", - "1-0": "**userId**\n_required_", - "1-1": "string", - "2-0": "**userAttributes**\n_optional_", - "2-1": "map", - "h-2": "Description", - "0-2": "The key of the feature to check. The feature key is defined from the Features dashboard.", - "1-2": "The ID of the user to check.", - "2-2": "A map of custom key-value string pairs specifying attributes for the user that are used for audience targeting. Non-string values are only supported in the 3.0 SDK and above." - }, - "cols": 3, - "rows": 3 -} -[/block] - -[block:api-header] -{ - "title": "Returns" -} -[/block] -True if feature is enabled. Otherwise, false or null. -[block:api-header] -{ - "title": "Examples" -} -[/block] + +| Parameter | Type | Description | +|-----------------|------------|-------------------------------------------------------------------------------------------------------------| +| **featureKey** | string | _required_ - The key of the feature to check. The feature key is defined from the Features dashboard. | +| **userId** | string | _required_ - The ID of the user to check. | +| **userAttributes** | map | _optional_ - A map of custom key-value string pairs specifying attributes for the user that are used for audience targeting. Non-string values are only supported in the 3.0 SDK and above. | + + +## Returns + +True if the feature is enabled. Otherwise, false or null. + +## Examples + This section shows a simple example of how you can use the `IsFeatureEnabled` method. -[block:code] -{ - "codes": [ - { - "code": "// Evaluate a feature flag and a variable\nbool enabled = optimizelyClient.IsFeatureEnabled(\"price_filter\", userId);\n\nint? min_price = optimizelyClient.GetFeatureVariableInteger(\"price_filter\", variableKey: \"min_price\", userId: userId);\n\n", - "language": "csharp" - } - ] -} -[/block] - -[block:api-header] -{ - "title": "Source files" -} -[/block] -The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). \ No newline at end of file + +```csharp +// Evaluate a feature flag and a variable +bool enabled = optimizelyClient.IsFeatureEnabled("price_filter", userId); + +int? min_price = optimizelyClient.GetFeatureVariableInteger("price_filter", variableKey: "min_price", userId: userId); +``` + +## Source files + +The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/180 - set-forced-variation-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/180 - set-forced-variation-csharp.md index 45cf1f7d..fadae2a5 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/180 - set-forced-variation-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/180 - set-forced-variation-csharp.md @@ -1,24 +1,15 @@ ---- -title: "Set Forced Variation" -slug: "set-forced-variation-csharp" -hidden: false -createdAt: "2019-09-12T13:52:03.603Z" -updatedAt: "2019-09-16T23:46:57.219Z" ---- +## Set Forced Variation + Forces a user into a variation for a given experiment for the lifetime of the Optimizely client. The purpose of this method is to force a user into a specific variation or personalized experience for a given experiment. The forced variation value doesn't persist across application launches. -[block:api-header] -{ - "title": "Version" -} -[/block] + +### Version + SDK v3.0, v3.1 -[block:api-header] -{ - "title": "Description" -} -[/block] + +### Description + Forces a user into a variation for a given experiment for the lifetime of the Optimizely client. Any future calls to [Activate](doc:activate-csharp), [Is Feature Enabled](doc:is-feature-enabled-csharp), [Get Feature Variable](doc:get-feature-variable-csharp), and [Track](doc:track-csharp) for the given user ID returns the forced variation. Forced bucketing variations take precedence over whitelisted variations, variations saved in a User Profile Service (if one exists), and the normal bucketed variation. Impression and conversion events are still tracked when forced bucketing is enabled. @@ -28,65 +19,31 @@ Variations are overwritten with each set method call. To clear the forced variat This call will fail and return false if the experiment key is not in the project file or if the variation key is not in the experiment. You can also use Set Forced Variation for [feature tests](doc:run-feature-tests-csharp). -[block:api-header] -{ - "title": "Parameters" -} -[/block] -This table lists the required and optional parameters for the C# SDK. -[block:parameters] -{ - "data": { - "h-0": "Parameter", - "h-1": "Type", - "h-2": "Description", - "0-0": "**experimentKey**\n*required*", - "0-1": "string", - "1-0": "**userId**\n*required*", - "1-1": "string", - "0-2": "The key of the experiment to set with the forced variation.", - "1-2": "The ID of the user to force into the variation.", - "2-2": "The key of the forced variation. Set the value to `null` to clear the existing experiment-to-variation mapping.", - "2-0": "**variationKey**\n*optional*", - "2-1": "string" - }, - "cols": 3, - "rows": 3 -} -[/block] - -[block:api-header] -{ - "title": "Returns" -} -[/block] + +### Parameters + +The table below lists the required and optional parameters for the C# SDK. + +| Parameter | Type | Description | +|-----------|---------|-----------------------------------------------------------------------| +| experimentKey | string | The key of the experiment to set with the forced variation. | +| userId | string | The ID of the user to force into the variation. | +| variationKey | string | The key of the forced variation. Set the value to `null` to clear the existing experiment-to-variation mapping. | + +## Returns + A Boolean value that indicates if the set completed successfully. -[block:api-header] -{ - "title": "Example" -} -[/block] - -[block:code] -{ - "codes": [ - { - "code": "optimizelyClient.SetForcedVariation(\"my_experiment_key\", \"user_123\", \"some_variation_key\")\n \n ", - "language": "csharp" - } - ] -} -[/block] - -[block:api-header] -{ - "title": "Side effects" -} -[/block] + +## Example + +```csharp +optimizelyClient.SetForcedVariation("my_experiment_key", "user_123", "some_variation_key"); +``` + +## Side effects + In the receiving client instance, sets the forced variation for the specified user in the specified experiment. This forced variation is used instead of the variation that Optimizely would normally determine for that user and experiment. -[block:api-header] -{ - "title": "Source files" -} -[/block] -The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). \ No newline at end of file + +## Source files + +The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/190 - track-csharp.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/190 - track-csharp.md index ae006140..cc72983b 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/190 - track-csharp.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/190 - track-csharp.md @@ -1,110 +1,74 @@ ---- -title: "Track" -slug: "track-csharp" -hidden: false -createdAt: "2019-09-12T13:53:40.495Z" -updatedAt: "2020-02-21T19:34:45.905Z" ---- +# Track + Tracks a conversion event. Logs an error message if the specified event key doesn't match any existing events. -[block:api-header] -{ - "title": "Version" -} -[/block] + +## Version + SDK v3.0, v3.1 -[block:api-header] -{ - "title": "Description" -} -[/block] + +## Description + Use this method to track events across multiple experiments. You should only send one tracking event per conversion, even if many feature tests or A/B tests are measuring it. -[block:callout] -{ - "type": "info", - "title": "Note", - "body": "Events are counted in an experiment when an impression was sent as a result of the [Activate](doc:activate-csharp) or [Is Feature Enabled](doc:is-feature-enabled-csharp) method being called." -} -[/block] -The attributes passed to Track are only used for [results segmentation](doc:analyze-results#section-segment-results). -[block:api-header] -{ - "title": "Parameters" -} -[/block] + +**Note**: Events are counted in an experiment when an impression was sent as a result of the `Activate` or `Is Feature Enabled` method being called. + +The attributes passed to `Track` are only used for results segmentation. + +## Parameters + This table lists the required and optional parameters for the C# SDK. -[block:parameters] -{ - "data": { - "h-0": "Parameter", - "h-1": "Type", - "h-2": "Description", - "0-0": "**eventKey**\n*required*", - "0-1": "string", - "1-0": "**userId**\n*required*", - "1-1": "string", - "2-0": "**userAttributes**\n*optional*", - "3-0": "**eventTags**\n*optional*", - "3-1": "map", - "2-1": "map", - "0-2": "The key of the event to be tracked. This key must match the event key provided when the event was created in the Optimizely app.", - "1-2": "The ID of the user associated with the event being tracked. \n\n**Important**: This ID must match the user ID provided to Activate or Is Feature Enabled.", - "2-2": "A map of custom key-value string pairs specifying attributes for the user that are used for [results segmentation](doc:analyze-results#section-segment-results). Non-string values are only supported in the 3.0 SDK and above.", - "3-2": "A map of key-value pairs specifying tag names and their corresponding tag values for this particular event occurrence. Values can be strings, numbers, or booleans.\n\nThese can be used to track numeric metrics, allowing you to track actions beyond conversions, for example: revenue, load time, or total value. [See details on reserved tag keys.](https://docs.developers.optimizely.com/full-stack/docs/include-event-tags#section-reserved-tag-keys)" - }, - "cols": 3, - "rows": 4 -} -[/block] - -[block:api-header] -{ - "title": "Returns" -} -[/block] -This method sends conversion data to Optimizely. It doesn't provide return values. -[block:api-header] -{ - "title": "Example" -} -[/block] - -[block:code] -{ - "codes": [ - { - "code": "using OptimizelySDK.Entity;\n\nvar attributes = new UserAttributes {\n { \"device\", \"iPhone\" },\n { \"lifetime\", 24738388 },\n { \"is_logged_in\", true },\n};\n\nvar tags = new EventTags {\n { \"category\", \"shoes\" },\n { \"count\", 2 },\n};\n\noptimizelyClient.Track(\"my_purchase_event_key\", \"user_123\", attributes, tags);\n\n", - "language": "csharp" - } - ] -} -[/block] - -[block:api-header] -{ - "title": "Side effects" -} -[/block] -The table lists other other Optimizely functionality that may be triggered by using this method. -[block:parameters] -{ - "data": { - "h-0": "Functionality", - "h-1": "Description", - "0-0": "Conversions", - "0-1": "Calling this method records a conversion and attributes it to the variations that the user has seen.\n \nOptimizely Feature Experimentation 3.x supports retroactive metrics calculation. You can create [metrics](doc:choose-metrics) on this conversion event and add metrics to experiments even after the conversion has been tracked.\n\nFor more information, see the paragraph **Events are always on** in the introduction of [Events: Tracking clicks, pageviews, and other visitor actions](https://help.optimizely.com/Measure_success%3A_Track_visitor_behaviors/Events%3A_Tracking_clicks%2C_pageviews%2C_and_other_visitor_actions).\n\n**Important!** \n - This method won't track events when the specified event key is invalid.\n - Changing the traffic allocation of running experiments affects how conversions are recorded and variations are attributed to users.", - "1-0": "Impressions", - "1-1": "Track doesn't trigger impressions.", - "2-0": "Notification Listeners", - "2-1": "Accessing this method triggers a call to the `TRACK` notification listener. \n\n**Important!** This method won't call the `TRACK` notification listener when the specified event key is invalid." - }, - "cols": 2, - "rows": 3 -} -[/block] - -[block:api-header] -{ - "title": "Source files" -} -[/block] -The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). \ No newline at end of file + +| Parameter | Type | Description | +| ---------------- | -------------- | ----------- | +| **eventKey** | string | The key of the event to be tracked. This key must match the event key provided when the event was created in the Optimizely app. | +| **userId** | string | The ID of the user associated with the event being tracked. **Important**: This ID must match the user ID provided to `Activate` or `Is Feature Enabled`. | +| **userAttributes** | map (optional) | A map of custom key-value string pairs specifying attributes for the user that are used for results segmentation. Non-string values are only supported in the 3.0 SDK and above. | +| **eventTags** | map (optional) | A map of key-value pairs specifying tag names and their corresponding tag values for this particular event occurrence. Values can be strings, numbers, or booleans. These can be used to track numeric metrics, allowing you to track actions beyond conversions, such as revenue, load time, or total value. [See details on reserved tag keys.](https://docs.developers.optimizely.com/full-stack/docs/include-event-tags#section-reserved-tag-keys) | + +## Returns + +This method sends conversion data to Optimizely. It doesn't provide return values. + +## Example + +```csharp +using OptimizelySDK.Entity; + +var attributes = new UserAttributes { + { "device", "iPhone" }, + { "lifetime", 24738388 }, + { "is_logged_in", true }, +}; + +var tags = new EventTags { + { "category", "shoes" }, + { "count", 2 }, +}; + +optimizelyClient.Track("my_purchase_event_key", "user_123", attributes, tags); + +``` +# Side effects + +The table lists other Optimizely functionality that may be triggered by using this method. + +## Functionality | Description + +- **Conversions** + Calling this method records a conversion and attributes it to the variations that the user has seen. + Optimizely Feature Experimentation 3.x supports retroactive metrics calculation. You can create [metrics](doc:choose-metrics) on this conversion event and add metrics to experiments even after the conversion has been tracked. + For more information, see the paragraph **Events are always on** in the introduction of [Events: Tracking clicks, pageviews, and other visitor actions](https://help.optimizely.com/Measure_success%3A_Track_visitor_behaviors/Events%3A_Tracking_clicks%2C_pageviews%2C_and_other_visitor_actions). + **Important!** + - This method won't track events when the specified event key is invalid. + - Changing the traffic allocation of running experiments affects how conversions are recorded and variations are attributed to users. + +- **Impressions** + Track doesn't trigger impressions. + +- **Notification Listeners** + Accessing this method triggers a call to the `TRACK` notification listener. + **Important!** This method won't call the `TRACK` notification listener when the specified event key is invalid. + +# Source files + +The language/platform source files containing the implementation for C# is [Optimizely.cs](https://github.com/optimizely/csharp-sdk/blob/master/OptimizelySDK/Optimizely.cs). diff --git a/docs/readme-sync/sdk-reference-guides/csharp-sdk/index.md b/docs/readme-sync/sdk-reference-guides/csharp-sdk/index.md index a86109cf..674f66e1 100644 --- a/docs/readme-sync/sdk-reference-guides/csharp-sdk/index.md +++ b/docs/readme-sync/sdk-reference-guides/csharp-sdk/index.md @@ -7,8 +7,9 @@ metadata: createdAt: {} updatedAt: "2020-05-22T20:03:21.212Z" --- -This reference guide describes how to use the Optimizely C# SDK. Refer to the left hand navigation for all sections in this reference guide. + +This reference guide describes how to use the Optimizely C# SDK. Refer to the left-hand navigation for all sections in this reference guide. The Optimizely C# SDK is currently at version 3.4.1. -You can also use the [C# SDK quickstart](doc:c-sharp) or review the [C# SDK repo](https://github.com/optimizely/csharp-sdk) and [changelog](https://github.com/optimizely/csharp-sdk/blob/master/CHANGELOG.md). \ No newline at end of file +You can also use the [C# SDK quickstart](doc:c-sharp) or review the [C# SDK repo](https://github.com/optimizely/csharp-sdk) and [changelog](https://github.com/optimizely/csharp-sdk/blob/master/CHANGELOG.md).