Skip to main content

DevCycle .NET / C# SDK

Welcome to the DevCycle .NET Server SDK, which requests the bucketing config from DevCycle servers on DVCLocalClient initialization. Periodic calls are made to the config CDN to retrieve the latest config, but no userdata is used outside of the application.

All calls to the client will then perform local bucketing to determine if a user receives a specific variation. Events are queued and flushed periodically in the background to the events api including the user body.

This version uses .NET Standard 2.1 and utilizes more resources to perform local bucketing.

The SDK is available as a package on Nuget. It is also open source and can be viewed on Github.

Nuget GitHub

Frameworks supported

  • .NET & .NET Core >=3.0
  • Mono >=6.4
  • Xamarin.iOS >=12.16
  • Xamarin.Mac >=5.16
  • Xamarin.Android >=10.0
  • Unity >=2021.2

Dependencies

  • FubarCoder.RestSharp.Portable.Core >=4.0.8
  • FubarCoder.RestSharp.Portable.HttpClient >=4.0.8
  • JsonSubTypes >=1.8.0
  • Microsoft.Extensions.Logging.Abstractions >= 6.0.1
  • Microsoft.Extensions.Logging.Console >= 6.0.1
  • Microsoft.Extensions.Logging >= 6.0.0
  • Newtonsoft.Json >=13.0.1
  • TypeSupport >= 1.1.12
  • Wasmtime >= 0.34.0-preview1

Installation

Download the SDK from Nuget - https://nuget.info/packages/DevCycle.SDK.Server.Local/ and use the namespaces:

using DevCycle.SDK.Server.Local.Api;

Getting Started

using System;
using System.Diagnostics;
using DevCycle.SDK.Server.Local.Api;

namespace Example
{
public class Example
{
static Main(string[] args)
{
DVCLocalClientBuilder apiBuilder = new DVCLocalClientBuilder();
using DVCLocalClient api = apiBuilder.SetEnvironmentKey("INSERT_SDK_KEY")
.Build();
}
}
}

Usage

User Object

The user object is required for all methods. The only required field in the user object is userId

See the User class in .NET User model doc for all accepted fields.

User user = new User("a_user_id");

Getting All Features

This method will fetch all features for a given user and return them as Dictionary<String, Feature>

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using DevCycle.SDK.Server.Local.Api;
using DevCycle.SDK.Server.Common;
using Microsoft.Extensions.Logging;

namespace Example
{
public class AllFeaturesExample
{
private static DVCLocalClient api;

static async Task Main(string[] args)
{
var user = new User("test");

DVCLocalClientBuilder apiBuilder = new DVCLocalClientBuilder();
api = ((DVCLocalClientBuilder)apiBuilder.SetEnvironmentKey("INSERT_SDK_KEY")
.SetOptions(new DVCOptions(1000, 5000)))
.SetInitializedSubscriber((o, e) =>
{
if (e.Success)
{
ClientInitialized(user);
}
else
{
Console.WriteLine($"Client did not initialize. Error: {e.Error}");
}
})
.SetLogger(LoggerFactory.Create(builder => builder.AddConsole()))
.Build();

try
{
await Task.Delay(5000);
}
catch (TaskCanceledException)
{
System.Environment.Exit(0);
}
}

private static void ClientInitialized(User user)
{
Dictionary<string, Feature> result = api.AllFeatures(user);

foreach (KeyValuePair<string, Feature> entry in result)
{
Console.WriteLine(entry.Key + " : " + entry.Value);
}
}
}
}

Get all Variables

To get values from your Variables, the Value field inside the variable object can be accessed.

This method will fetch all variables for a given user and returned as Dictionary<String, Variable>

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using DevCycle.SDK.Server.Local.Api;
using DevCycle.SDK.Server.Common;
using Microsoft.Extensions.Logging;

namespace Example
{
public class AllVariablesExample
{
private static DVCLocalClient api;

static async Task Main(string[] args)
{
var user = new User("test");

DVCLocalClientBuilder apiBuilder = new DVCLocalClientBuilder();
api = ((DVCLocalClientBuilder)apiBuilder.SetEnvironmentKey("INSERT_SDK_KEY")
.SetOptions(new DVCOptions(1000, 5000)))
.SetInitializedSubscriber((o, e) =>
{
if (e.Success)
{
ClientInitialized(user);
}
else
{
Console.WriteLine($"Client did not initialize. Error: {e.Error}");
}
})
.SetLogger(LoggerFactory.Create(builder => builder.AddConsole()))
.Build();

try
{
await Task.Delay(5000);
}
catch (TaskCanceledException)
{
System.Environment.Exit(0);
}
}

private static void ClientInitialized(User user)
{
Dictionary<string, Feature> result = api.AllVariables(user);

foreach (KeyValuePair<string, Variable> entry in result.GetAll())
{
Console.WriteLine(entry.Key + " : " + entry.Value);
}
}
}
}

Get and use Variable by key

To get values from your Variables, the Value field inside the variable object can be accessed.

This method will fetch a specific variable by key for a given user. It will return the variable object from the server unless an error occurs or the server has no response. In that case it will return a variable object with the value set to whatever was passed in as the defaultValue parameter.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using DevCycle.SDK.Server.Local.Api;
using DevCycle.SDK.Server.Common;
using Microsoft.Extensions.Logging;

namespace Example
{
public class VariableByKeyExample
{
private static DVCLocalClient api;

static async Task Main(string[] args)
{
var user = new User("test");

DVCLocalClientBuilder apiBuilder = new DVCLocalClientBuilder();
api = ((DVCLocalClientBuilder)apiBuilder.SetEnvironmentKey("INSERT_SDK_KEY")
.SetOptions(new DVCOptions(1000, 5000)))
.SetInitializedSubscriber((o, e) =>
{
if (e.Success)
{
ClientInitialized(user);
}
else
{
Console.WriteLine($"Client did not initialize. Error: {e.Error}");
}
})
.SetLogger(LoggerFactory.Create(builder => builder.AddConsole()))
.Build();

try
{
await Task.Delay(5000);
}
catch (TaskCanceledException)
{
System.Environment.Exit(0);
}
}

private static void ClientInitialized(User user)
{
string key = "my-bool-variable";
bool defaultValue = true;

Variable<bool> boolVariable = api.Variable(user, key, defaultValue);

Console.WriteLine(boolVariable);
}
}
}

Track Event

To POST custom event for a user, pass in the user and event object.

Calling Track will queue the event, which will be sent in batches to the DevCycle servers.

using System;
using System.Threading.Tasks;
using DevCycle.SDK.Server.Local.Api;
using DevCycle.SDK.Server.Common;
using Microsoft.Extensions.Logging;

namespace Example
{
class Program
{
private static DVCLocalClient api;

static async Task Main(string[] args)
{
var user = new User("test");

DVCLocalClientBuilder apiBuilder = new DVCLocalClientBuilder();
api = ((DVCLocalClientBuilder)apiBuilder.SetEnvironmentKey("INSERT_SDK_KEY")
.SetOptions(new DVCOptions(1000, 5000)))
.SetInitializedSubscriber((o, e) =>
{
if (e.Success)
{
ClientInitialized(user);
}
else
{
Console.WriteLine($"Client did not initialize. Error: {e.Error}");
}
})
.SetLogger(LoggerFactory.Create(builder => builder.AddConsole()))
.Build();

try
{
await Task.Delay(5000);
}
catch (TaskCanceledException)
{
System.Environment.Exit(0);
}
}

private static void ClientInitialized(User user)
{
DateTimeOffset now = DateTimeOffset.UtcNow;
long unixTimeMilliseconds = now.ToUnixTimeMilliseconds();

var @event = new Event("test event", "test target", unixTimeMilliseconds, 600);

try
{
api.Track(user, @event);
}
catch (Exception e)
{
Console.WriteLine("Exception when calling DVCLocalClient.Track: " + e.Message );
}
}
}
}

Flush Events

Calling this method will immediately send all queued events to the DevCycle servers

using System;
using System.Threading.Tasks;
using DevCycle.SDK.Server.Local.Api;
using DevCycle.SDK.Server.Common;
using Microsoft.Extensions.Logging;

namespace Example
{
class Program
{
private static DVCLocalClient api;

static async Task Main(string[] args)
{
var user = new User("test");

DVCLocalClientBuilder apiBuilder = new DVCLocalClientBuilder();
api = ((DVCLocalClientBuilder)apiBuilder.SetEnvironmentKey("INSERT_SDK_KEY")
.SetOptions(new DVCOptions(1000, 5000)))
.SetInitializedSubscriber((o, e) =>
{
if (e.Success)
{
ClientInitialized(user);
}
else
{
Console.WriteLine($"Client did not initialize. Error: {e.Error}");
}
})
.SetLogger(LoggerFactory.Create(builder => builder.AddConsole()))
.Build();

try
{
await Task.Delay(5000);
}
catch (TaskCanceledException)
{
System.Environment.Exit(0);
}
}

private static void ClientInitialized(User user)
{
api.FlushedEvents += (sender, args) =>
{
FlushedEvents(args);
};
api.FlushEvents();
}

private static void FlushedEvents(DVCEventArgs args)
{
if (!args.Success)
{
Console.WriteLine(args.Error);
}
}
}
}