You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/readme-sync/sdk-reference-guides/csharp-sdk/030 - example-usage-csharp.md
+30-6
Original file line number
Diff line number
Diff line change
@@ -13,13 +13,37 @@ This example demonstrates the basic usage of each of these concepts. This exampl
13
13
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.
14
14
15
15
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.
if (variation!=null&&!string.IsNullOrEmpty(variation.Key))
17
31
{
18
-
"codes": [
32
+
if (variation.Key=="control")
33
+
{
34
+
// Execute code for variation A
35
+
}
36
+
elseif (variation.Key=="treatment")
19
37
{
20
-
"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",
21
-
"language": "csharp"
38
+
// Execute code for variation B
22
39
}
23
-
]
24
40
}
25
-
[/block]
41
+
else
42
+
{
43
+
// Execute code for your users who don’t qualify for the experiment
Copy file name to clipboardExpand all lines: docs/readme-sync/sdk-reference-guides/csharp-sdk/040 - optimizelyconfig-csharp.md
+84-43
Original file line number
Diff line number
Diff line change
@@ -5,68 +5,109 @@ hidden: false
5
5
createdAt: "2020-01-17T11:52:50.547Z"
6
6
updatedAt: "2020-01-28T21:53:11.290Z"
7
7
---
8
-
[block:api-header]
9
-
{
10
-
"title": "Overview"
11
-
}
12
-
[/block]
8
+
9
+
## Overview
10
+
13
11
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".
14
12
15
13
In this document, we extend our public APIs to define data models and access methods, which clients can use to access project configuration data.
16
14
17
-
[block:api-header]
18
-
{
19
-
"title": "OptimizelyConfig API"
20
-
}
21
-
[/block]
15
+
## OptimizelyConfig API
22
16
23
17
A public configuration data model (OptimizelyConfig) is defined below as a structured format of static Optimizely Project data.
24
18
25
19
OptimizelyConfig can be accessed from OptimizelyClient (top-level) with this public API call:
26
-
[block:code]
20
+
21
+
```csharp
22
+
publicOptimizelyConfigGetOptimizelyConfig()
23
+
```
24
+
`GetOptimizelyConfig` returns an `OptimizelyConfig` instance which includes a datafile revision number, all experiments, and feature flags mapped by their key values.
25
+
26
+
> **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.
27
+
28
+
```csharp
29
+
// OptimizelyConfig is a class describing the current project configuration data being used by this SDK instance.
`GetOptimizelyConfig` returns an `OptimizelyConfig` instance which include a datafile revision number, all experiments, and feature flags mapped by their key values.
37
-
[block:callout]
36
+
37
+
// Entity.IdKeyEntity is an abstract class used for inheritance in OptimizelyExperiment, OptimizelyFeature, OptimizelyVariation, and OptimizelyVariable classes.
"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."
40
+
publicstringId { get; set; }
41
+
publicstringKey { get; set; }
42
42
}
43
-
[/block]
44
43
45
-
[block:code]
44
+
// OptimizelyFeature is a class describing a feature and inherited from Entity.IdKeyEntity.
45
+
publicclassOptimizelyFeature : Entity.IdKeyEntity
46
46
{
47
-
"codes": [
48
-
{
49
-
"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<string, OptimizelyExperiment> ExperimentsMap { get; private set; }\n public IDictionary<string, OptimizelyFeature> 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<object>\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<string, OptimizelyExperiment> ExperimentsMap { get; private set; }\n public IDictionary<string, OptimizelyVariable> 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<string, OptimizelyVariation> 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<string, OptimizelyVariable> 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}",
"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",
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.
9
9
10
10
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.
11
-
[block:api-header]
12
-
{
13
-
"title": "Implement a service"
14
-
}
15
-
[/block]
16
-
Refer to the code samples below to provide your own User Profile Service. It should expose two functions with the following signatures:
11
+
## Implement a Service
12
+
13
+
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:
14
+
15
+
-`lookup`: Takes a user ID string and returns a user profile matching the specified schema.
16
+
-`save`: Takes a user profile and persists it.
17
17
18
-
*`lookup`: Takes a user ID string and returns a user profile matching the schema below.
19
-
*`save`: Takes a user profile and persists it.
18
+
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.
20
19
21
-
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`).
// Implement the logic to persist the user profile data
28
42
}
29
-
]
30
43
}
31
-
[/block]
32
-
The code example below shows the JSON schema for the user profile object.
33
44
34
-
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.
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.
35
53
36
-
In the example below, `^[a-zA-Z0-9]+$` is the experiment ID.
37
-
[block:code]
54
+
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.
55
+
56
+
In the example below, `^[a-zA-Z0-9]+$` represents the pattern for an experiment ID:
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.
48
81
49
82
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.
0 commit comments