Skip to content

Commit d1ebc8e

Browse files
authored
Converted all the files into proper md file format (#368)
1 parent bfe4e64 commit d1ebc8e

21 files changed

+1146
-1371
lines changed

docs/readme-sync/sdk-reference-guides/csharp-sdk/010 - install-sdk-csharp.md

+5-13
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,12 @@ hidden: false
55
createdAt: "2019-09-11T13:55:51.015Z"
66
updatedAt: "2019-09-11T13:58:07.201Z"
77
---
8-
TEST CHANGE
98

109
The C# SDK is distributed through NuGet.
1110

1211
For Windows, to install, run the command `Install-Package Optimizely.SDK` in the Package Manager Console:
13-
[block:code]
14-
{
15-
"codes": [
16-
{
17-
"code": "PM> Install-Package Optimizely.SDK -Version 3.0.0\n\n",
18-
"language": "shell",
19-
"name": "Install the SDK"
20-
}
21-
]
22-
}
23-
[/block]
24-
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.
12+
13+
```shell
14+
PM> Install-Package Optimizely.SDK -Version 3.0.0
15+
```
16+
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.

docs/readme-sync/sdk-reference-guides/csharp-sdk/010 -install-sdk-csharp.md

+7-12
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,13 @@ hidden: false
55
createdAt: "2019-09-11T13:55:51.015Z"
66
updatedAt: "2019-09-11T13:58:07.201Z"
77
---
8+
89
The C# SDK is distributed through NuGet.
910

1011
For Windows, to install, run the command `Install-Package Optimizely.SDK` in the Package Manager Console:
11-
[block:code]
12-
{
13-
"codes": [
14-
{
15-
"code": "PM> Install-Package Optimizely.SDK -Version 3.0.0\n\n",
16-
"language": "shell",
17-
"name": "Install the SDK"
18-
}
19-
]
20-
}
21-
[/block]
22-
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.
12+
13+
```shell
14+
PM> Install-Package Optimizely.SDK -Version 3.0.0
15+
```
16+
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.
17+

docs/readme-sync/sdk-reference-guides/csharp-sdk/020 - initialize-sdk-csharp.md

+144-187
Large diffs are not rendered by default.

docs/readme-sync/sdk-reference-guides/csharp-sdk/030 - example-usage-csharp.md

+30-6
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,37 @@ This example demonstrates the basic usage of each of these concepts. This exampl
1313
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.
1414

1515
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.
16-
[block:code]
16+
```csharp
17+
// Import Optimizely SDK
18+
using OptimizelySDK;
19+
20+
// Instantiate an Optimizely client
21+
var optimizelyClient = new Optimizely(datafile);
22+
23+
// Evaluate a feature flag and a variable
24+
bool isFeatureEnabled = optimizelyClient.IsFeatureEnabled("price_filter", userId);
25+
int? min_price = optimizelyClient.GetFeatureVariableInteger("price_filter", "min_price", userId);
26+
27+
// Activate an A/B test
28+
var variation = optimizelyClient.Activate("app_redesign", userId);
29+
30+
if (variation != null && !string.IsNullOrEmpty(variation.Key))
1731
{
18-
"codes": [
32+
if (variation.Key == "control")
33+
{
34+
// Execute code for variation A
35+
}
36+
else if (variation.Key == "treatment")
1937
{
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
2239
}
23-
]
2440
}
25-
[/block]
41+
else
42+
{
43+
// Execute code for your users who don’t qualify for the experiment
44+
}
45+
46+
// Track an event
47+
optimizelyClient.Track("purchased", userId);
48+
49+
```

docs/readme-sync/sdk-reference-guides/csharp-sdk/040 - optimizelyconfig-csharp.md

+84-43
Original file line numberDiff line numberDiff line change
@@ -5,68 +5,109 @@ hidden: false
55
createdAt: "2020-01-17T11:52:50.547Z"
66
updatedAt: "2020-01-28T21:53:11.290Z"
77
---
8-
[block:api-header]
9-
{
10-
"title": "Overview"
11-
}
12-
[/block]
8+
9+
## Overview
10+
1311
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".
1412

1513
In this document, we extend our public APIs to define data models and access methods, which clients can use to access project configuration data.
1614

17-
[block:api-header]
18-
{
19-
"title": "OptimizelyConfig API"
20-
}
21-
[/block]
15+
## OptimizelyConfig API
2216

2317
A public configuration data model (OptimizelyConfig) is defined below as a structured format of static Optimizely Project data.
2418

2519
OptimizelyConfig can be accessed from OptimizelyClient (top-level) with this public API call:
26-
[block:code]
20+
21+
```csharp
22+
public OptimizelyConfig GetOptimizelyConfig()
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.
30+
public class OptimizelyConfig
2731
{
28-
"codes": [
29-
{
30-
"code": "public OptimizelyConfig GetOptimizelyConfig()",
31-
"language": "csharp"
32-
}
33-
]
32+
public string Revision { get; private set; }
33+
public IDictionary<string, OptimizelyExperiment> ExperimentsMap { get; private set; }
34+
public IDictionary<string, OptimizelyFeature> FeaturesMap { get; private set; }
3435
}
35-
[/block]
36-
`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.
38+
public abstract class IdKeyEntity : Entity, IEquatable<object>
3839
{
39-
"type": "info",
40-
"title": "Note",
41-
"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+
public string Id { get; set; }
41+
public string Key { get; set; }
4242
}
43-
[/block]
4443

45-
[block:code]
44+
// OptimizelyFeature is a class describing a feature and inherited from Entity.IdKeyEntity.
45+
public class OptimizelyFeature : Entity.IdKeyEntity
4646
{
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}",
50-
"language": "csharp"
51-
}
52-
]
47+
public IDictionary<string, OptimizelyExperiment> ExperimentsMap { get; private set; }
48+
public IDictionary<string, OptimizelyVariable> VariablesMap { get; private set; }
5349
}
54-
[/block]
5550

56-
[block:api-header]
51+
// OptimizelyExperiment is a class describing a feature test or an A/B test and inherited from Entity.IdKeyEntity.
52+
public class OptimizelyExperiment : Entity.IdKeyEntity
5753
{
58-
"title": "Examples"
54+
public IDictionary<string, OptimizelyVariation> VariationsMap { get; private set; }
5955
}
60-
[/block]
61-
OptimizelyConfig can be accessed from OptimizelyClient (top-level) like this:
6256

63-
[block:code]
57+
// OptimizelyVariation is a class describing a variation in a feature test or A/B test and inherited from Entity.IdKeyEntity.
58+
public class OptimizelyVariation : Entity.IdKeyEntity
6459
{
65-
"codes": [
66-
{
67-
"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",
68-
"language": "csharp"
60+
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
61+
public bool? FeatureEnabled { get; private set; }
62+
public IDictionary<string, OptimizelyVariable> VariablesMap { get; private set; }
63+
}
64+
65+
// OptimizelyVariable is a class describing a feature variable and inherited from Entity.IdKeyEntity.
66+
public class OptimizelyVariable : Entity.IdKeyEntity
67+
{
68+
public string Type { get; private set; }
69+
public string Value { get; private set; }
70+
}
71+
```
72+
73+
## Examples
74+
75+
You can access the `OptimizelyConfig` from the `OptimizelyClient` (top-level) as shown below:
76+
77+
```csharp
78+
var optimizelyConfig = optimizely.GetOptimizelyConfig();
79+
80+
// All experiment keys
81+
var experimentKeys = optimizelyConfig.ExperimentsMap.Keys;
82+
foreach(var experimentKey in experimentKeys) {
83+
// Use experiment key data here.
84+
}
85+
86+
// All experiments
87+
var experiments = optimizelyConfig.ExperimentsMap.Values;
88+
foreach(var experiment in experiments) {
89+
// All variations
90+
var variations = experiment.VariationsMap.Values;
91+
foreach(var variation in variations) {
92+
var variables = variation.VariablesMap.Values;
93+
foreach(var variable in variables) {
94+
// Use variable data here.
6995
}
70-
]
96+
}
7197
}
72-
[/block]
98+
99+
// All features
100+
var features = optimizelyConfig.FeaturesMap.Values;
101+
foreach(var feature in features) {
102+
var experiments = feature.ExperimentsMap.Values;
103+
foreach(var experiment in experiments) {
104+
// Use experiment data here.
105+
}
106+
}
107+
108+
// Listen to OPTIMIZELY_CONFIG_UPDATE to get updated data
109+
NotificationCenter.OptimizelyConfigUpdateCallback configUpdateListener = () => {
110+
var optimizelyConfig = optimizely.GetOptimizelyConfig();
111+
};
112+
optimizely.NotificationCenter.AddNotification(NotificationCenter.NotificationType.OptimizelyConfigUpdate, configUpdateListener);
113+
```

docs/readme-sync/sdk-reference-guides/csharp-sdk/050 - implement-a-user-profile-csharp.md

+58-25
Original file line numberDiff line numberDiff line change
@@ -8,42 +8,75 @@ updatedAt: "2019-09-12T13:45:24.114Z"
88
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.
99

1010
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.
1717

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.
2019

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`).
22-
[block:code]
20+
Here's an example implementation using C#:
21+
22+
```csharp
23+
using System.Collections.Generic;
24+
using OptimizelySDK;
25+
using OptimizelySDK.Bucketing;
26+
27+
class InMemoryUserProfileService : UserProfileService
2328
{
24-
"codes": [
29+
private Dictionary<string, Dictionary<string, object>> userProfiles = new Dictionary<string, Dictionary<string, object>>();
30+
31+
public override Dictionary<string, object> Lookup(string userId)
2532
{
26-
"code": "using System.Collections.Generic;\n\nusing OptimizelySDK;\nusing OptimizelySDK.Bucketing;\n\nclass InMemoryUserProfileService : UserProfileService\n{\n private Dictionary<String, Dictionary<string, object>> userProfiles = new Dictionary<String, Dictionary<string, object>>();\n Dictionary<string, object> 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<string, object> userProfile)\n {\n // Save user profile\n }\n}\n\n\tvar optimizelyClient = new Optimizely(\n\t\tdatafile: datafile,\n userProfileService: userProfileService);\n\n",
27-
"language": "csharp"
33+
// Retrieve and return user profile
34+
// Replace with the actual userprofile variable
35+
return null;
36+
}
37+
38+
public override void Save(Dictionary<string, object> userProfile)
39+
{
40+
// Save user profile
41+
// Implement the logic to persist the user profile data
2842
}
29-
]
3043
}
31-
[/block]
32-
The code example below shows the JSON schema for the user profile object.
3344

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.
45+
var optimizelyClient = new Optimizely(
46+
datafile: datafile,
47+
userProfileService: new InMemoryUserProfileService()
48+
);
49+
```
50+
## User Profile JSON Schema
51+
52+
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.
3553

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:
57+
58+
```json
3859
{
39-
"codes": [
40-
{
41-
"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",
42-
"language": "json"
60+
"title": "UserProfile",
61+
"type": "object",
62+
"properties": {
63+
"user_id": {"type": "string"},
64+
"experiment_bucket_map": {
65+
"type": "object",
66+
"patternProperties": {
67+
"^[a-zA-Z0-9]+$": {
68+
"type": "object",
69+
"properties": {
70+
"variation_id": {"type": "string"}
71+
},
72+
"required": ["variation_id"]
73+
}
74+
}
4375
}
44-
]
76+
},
77+
"required": ["user_id", "experiment_bucket_map"]
4578
}
46-
[/block]
79+
```
4780
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.
4881

4982
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

Comments
 (0)