Skip to content

Commit

Permalink
merge v1.1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
GrafGenerator committed Nov 24, 2022
2 parents 0f99574 + b9e8a5a commit dc12a9d
Show file tree
Hide file tree
Showing 161 changed files with 5,550 additions and 5,081 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Expand Up @@ -351,4 +351,6 @@ MigrationBackup/

# JB
.idea
*.csproj.DotSettings
*.csproj.DotSettings
dotCover.Output
dotCover.output.*
6 changes: 0 additions & 6 deletions ABSmartly.DotNet.sln
Expand Up @@ -5,8 +5,6 @@ VisualStudioVersion = 17.2.32630.192
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ABSmartly.Sdk", "src\ABSmartly.Sdk\ABSmartly.Sdk.csproj", "{6F864363-8E21-4DC1-92E6-B77BFDA38BC7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ABSmartly.Sdk.TestsOld", "tests\ABSmartly.Sdk.TestsOld\ABSmartly.Sdk.TestsOld.csproj", "{66416968-0301-4511-8DE1-7CCC299E853D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{4B12CBE9-2387-4B0D-8676-A42FA4D07B3B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ABSmartlyExamples.SkiResortApp", "examples\Blazor\ABSmartlyExamples.SkiResortApp\ABSmartlyExamples.SkiResortApp.csproj", "{54B66373-B29C-44BD-BD5D-FBBE3D09C4BF}"
Expand Down Expand Up @@ -34,10 +32,6 @@ Global
{6F864363-8E21-4DC1-92E6-B77BFDA38BC7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6F864363-8E21-4DC1-92E6-B77BFDA38BC7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6F864363-8E21-4DC1-92E6-B77BFDA38BC7}.Release|Any CPU.Build.0 = Release|Any CPU
{66416968-0301-4511-8DE1-7CCC299E853D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66416968-0301-4511-8DE1-7CCC299E853D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66416968-0301-4511-8DE1-7CCC299E853D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66416968-0301-4511-8DE1-7CCC299E853D}.Release|Any CPU.Build.0 = Release|Any CPU
{54B66373-B29C-44BD-BD5D-FBBE3D09C4BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{54B66373-B29C-44BD-BD5D-FBBE3D09C4BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{54B66373-B29C-44BD-BD5D-FBBE3D09C4BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down
84 changes: 60 additions & 24 deletions README.md
@@ -1,12 +1,15 @@
# A/B Smartly DotNet SDK

Latest stable: [![NuGet stable](https://img.shields.io/nuget/v/ABSmartly.Sdk?style=flat-square)](https://www.nuget.org/packages/ABSmartly.Sdk)
Latest
stable: [![NuGet stable](https://img.shields.io/nuget/v/ABSmartly.Sdk?style=flat-square)](https://www.nuget.org/packages/ABSmartly.Sdk)

Current prerelease: [![NuGet pre](https://img.shields.io/nuget/vpre/ABSmartly.Sdk?style=flat-square)](https://www.nuget.org/packages/ABSmartly.Sdk)
Current
prerelease: [![NuGet pre](https://img.shields.io/nuget/vpre/ABSmartly.Sdk?style=flat-square)](https://www.nuget.org/packages/ABSmartly.Sdk)

## Installation

Install the A/B Smartly DotNet SDK from Nuget

```shell
dotnet add package ABSmartly.Sdk --version 1.0.0
```
Expand All @@ -16,11 +19,14 @@ SDK targets .NET Standard 2.0 and .NET 5.
## Getting Started

#### Initialization
Following examples assume an Api Key, an Application, and an Environment have been created in the A/B Smartly web console.

Following examples assume an Api Key, an Application, and an Environment have been created in the A/B Smartly web
console.

Given that project uses .NET dependency injection, the default setup for the SDK can be used:

Startup code:

```csharp
using ABSmartly;
using ABSmartly.DependencyInjection;
Expand All @@ -35,6 +41,7 @@ builder.Services.AddABSmartly(builder.Configuration.GetSection("ABSmartly"), Htt
```

appsettings.json:

```json
{
"ABSmartly": {
Expand All @@ -47,6 +54,7 @@ appsettings.json:
```

ABSdk instance is added as a singleton then, and can be injected at usage places:

```csharp
using ABSmartly;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -64,12 +72,11 @@ public class Test : ControllerBase
}
```

AddABSmartly extension method allows to configure SDK settings, HTTP connection settings, inject custom
implementation if context-specific services, and also configure additional HTTP requests policies using Polly.

AddABSmartly extension method allows to configure SDK settings, HTTP connection settings, inject custom
implementation if context-specific services, and also configure additional HTTP requests policies using Polly.

Alternatively, SDK instance can be created manually like in the following example.

Alternatively, SDK instance can be created manually like in the following example.
```csharp
using ABSmartly;
using ABSmartly.Services;
Expand All @@ -89,15 +96,18 @@ var abSdk = new ABSdk(new ABSdkHttpClientFactory(httpClientFactory), new ABSmart
...
```

SDK uses IHttpClientFactory abstraction to effectively manage HTTP connections pool. This factory is
SDK uses IHttpClientFactory abstraction to effectively manage HTTP connections pool. This factory is
injected using IABSdkHttpClientFactory as seen in the example above.
In case custom behavior or implementation is required, inject own implementation of either
IHttpClientFactory or IABSdkHttpClientFactory.
In case of injecting IABSdkHttpClientFactory implementation make sure it creates named IHttpClient
In case custom behavior or implementation is required, inject own implementation of either
IHttpClientFactory or IABSdkHttpClientFactory.
In case of injecting IABSdkHttpClientFactory implementation make sure it creates instances of IABSdkHttpClient
interface, which is a wrapper on top of HttpClient. SDK already has implementation that can be used for this,
see `ABSmartly.Services.ABSdkHttpClientFactory.HttpClientWrapper` class.
In case of injecting IHttpClientFactory implementation make sure it creates named IHttpClient
instances with name `ABSmartlySDK.HttpClient` (you can use static field in ABSdk class, `ABSdk.HttpClientName`).


#### Creating a new Context synchronously

```csharp
// define a new context request
var config = new ContextConfig()
Expand All @@ -106,6 +116,7 @@ instances with name `ABSmartlySDK.HttpClient` (you can use static field in ABSdk
```

#### Creating a new Context asynchronously

```csharp
// define a new context request
var config = new ContextConfig()
Expand All @@ -114,6 +125,7 @@ instances with name `ABSmartlySDK.HttpClient` (you can use static field in ABSdk
```

#### Creating a new Context with pre-fetched data

Creating a context involves a round-trip to the A/B Smartly event collector.
We can avoid repeating the round-trip on the client-side by re-using data previously retrieved.

Expand All @@ -129,9 +141,12 @@ We can avoid repeating the round-trip on the client-side by re-using data previo
```

#### Setting extra units for a context

You can add additional units to a context by calling the `SetUnit()` or the `SetUnits()` method.
This method may be used for example, when a user logs in to your application, and you want to use the new unit type to the context.
Please note that **you cannot override an already set unit type** as that would be a change of identity, and will throw an exception. In this case, you must create a new context instead.
This method may be used for example, when a user logs in to your application, and you want to use the new unit type to
the context.
Please note that **you cannot override an already set unit type** as that would be a change of identity, and will throw
an exception. In this case, you must create a new context instead.
The `SetUnit()` and `SetUnits()` methods can be called before the context is ready.

```csharp
Expand All @@ -143,7 +158,9 @@ The `SetUnit()` and `SetUnits()` methods can be called before the context is rea
```

#### Setting context attributes

The `SetAttribute()` and `SetAttributes()` methods can be called before the context is ready.

```csharp
context.SetAttribute('user_agent', Request.Headers["User-Agent"]);

Expand All @@ -153,6 +170,7 @@ The `SetAttribute()` and `SetAttributes()` methods can be called before the cont
```

#### Selecting a treatment

```csharp
if (context.GetTreament("exp_test_experiment") == 0) {
// user is in control group (variant 0)
Expand All @@ -162,12 +180,15 @@ The `SetAttribute()` and `SetAttributes()` methods can be called before the cont
```

#### Selecting a treatment variable

```csharp
var variable = context.GetVariableValue("my_variable");
```

#### Tracking a goal achievement

Goals are created in the A/B Smartly web console.

```csharp
context.Track("payment", new Dictionary<string, object>() {
{ "item_count", 1 },
Expand All @@ -176,25 +197,30 @@ Goals are created in the A/B Smartly web console.
```

#### Publishing pending data

Sometimes it is necessary to ensure all events have been published to the A/B Smartly collector, before proceeding.
You can explicitly call the `Publish()` or `PublishAsync()` methods.

```csharp
context.Publish();
```

#### Disposing
Context implements IDisposable and IAsyncDisposable interfaces to ensure all events have been published to the A/B
Smartly collector, like `Publish()`, and will also "seal" the context, throwing an error if any method that could

Context implements IDisposable and IAsyncDisposable interfaces to ensure all events have been published to the A/B
Smartly collector, like `Publish()`, and will also "seal" the context, throwing an error if any method that could
generate an event is called.

Instead calling `Publish()` directly, `using` pattern can be used.
Instead calling `Publish()` directly, `using` pattern can be used.

```csharp
using var context = _abSdk.CreateContext(config);
```

#### Refreshing the context with fresh experiment data

Sometimes for long-running contexts, the context is usually created once when the application is first started.
However, any experiments being tracked in your production code, but started after the context was created, will
However, any experiments being tracked in your production code, but started after the context was created, will
not be triggered.
To mitigate this, we can use the `RefreshInterval` property on the context config.

Expand All @@ -205,17 +231,20 @@ To mitigate this, we can use the `RefreshInterval` property on the context confi
```

Alternatively, the `Refresh()` method can be called manually.
The `Refresh()` method pulls updated experiment data from the A/B Smartly collector and will trigger recently
The `Refresh()` method pulls updated experiment data from the A/B Smartly collector and will trigger recently
started experiments when `GetTreatment()` is called again.

```csharp
context.Refresh();
// or
await context.RefreshAsync();
```

#### Using a custom Event Logger

The A/B Smartly SDK can be instantiated with an event logger used for all contexts.
In addition, an event logger can be specified when creating a particular context, in the `ContextConfig`.

```csharp
// example implementation
public class CustomEventLogger : IContextEventLogger
Expand Down Expand Up @@ -278,9 +307,9 @@ Currently, the SDK logs the following events:
| `Goal` | `Context.Track()` method succeeds | `GoalAchievement` enqueued for publishing |
| `Close` | `Context` disposal succeeds | `null` |


#### Peek at treatment variants
Although generally not recommended, it is sometimes necessary to peek at a treatment or variable without triggering

Although generally not recommended, it is sometimes necessary to peek at a treatment or variable without triggering
an exposure.
The A/B Smartly SDK provides a `PeekTreatment()` method for that.

Expand All @@ -293,14 +322,17 @@ The A/B Smartly SDK provides a `PeekTreatment()` method for that.
```

##### Peeking at variables

```csharp
var variable = context.PeekVariableValue("my_variable");
```

#### Overriding treatment variants
During development, for example, it is useful to force a treatment for an experiment. This can be achieved with

During development, for example, it is useful to force a treatment for an experiment. This can be achieved with
the `SetOverride()` and/or `SetOverrides()` methods.
The `SetOverride()` and `SetOverrides()` methods can be called before the context is ready.

```csharp
context.SetOverride("exp_test_experiment", 1); // force variant 1 of treatment
context.SetOverrides(new Dictionary<string, int>() {
Expand All @@ -310,10 +342,14 @@ The `SetOverride()` and `SetOverrides()` methods can be called before the contex
```

## About A/B Smartly
**A/B Smartly** is the leading provider of state-of-the-art, on-premises, full-stack experimentation platforms for engineering and product teams that want to confidently deploy features as fast as they can develop them.
A/B Smartly's real-time analytics helps engineering and product teams ensure that new features will improve the customer experience without breaking or degrading performance and/or business metrics.

**A/B Smartly** is the leading provider of state-of-the-art, on-premises, full-stack experimentation platforms for
engineering and product teams that want to confidently deploy features as fast as they can develop them.
A/B Smartly's real-time analytics helps engineering and product teams ensure that new features will improve the customer
experience without breaking or degrading performance and/or business metrics.

### Have a look at our growing list of clients and SDKs:

- [Java SDK](https://www.github.com/absmartly/java-sdk)
- [JavaScript SDK](https://www.github.com/absmartly/javascript-sdk)
- [PHP SDK](https://www.github.com/absmartly/php-sdk)
Expand Down
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\ABSmartly.Sdk\ABSmartly.Sdk.csproj" />
<PackageReference Include="ABSmartly.Sdk" Version="1.1.1" />
</ItemGroup>

</Project>
Expand Up @@ -93,7 +93,7 @@ public async Task Book(string userId)

private class CustomEventLogger : IContextEventLogger
{
public void HandleEvent(Context context, EventType eventType, object data)
public void HandleEvent(IContext context, EventType eventType, object data)
{
switch (eventType)
{
Expand Down
Expand Up @@ -3,7 +3,7 @@ namespace ABSmartlyExamples.SkiResortApp.Data;
public class WeatherForecast
{
public string? UserId { get; set; }

public DateTime Date { get; set; }

public int TemperatureC { get; set; }
Expand Down

0 comments on commit dc12a9d

Please sign in to comment.