Skip to content

.NET SDK

FeatureBoard .NET SDK for .NET core and framework applications.

Installation

Terminal window
dotnet add package FeatureBoard.DotnetSdk

Setup

Create a Features model

You can either manually create your model or use the cli tool or nx plugin to generate a model from your configuration in FeatureBoard.

cli tool

The FeatureBoard CLI Tool can generate a fully type safe API for your application based on the configuration of your FeatureBoard project.

First run npx @featureboard/cli login to authenticate, then from a folder containing the target .NET csproj run npx @featureboard/cli code-gen --template dotnet-api --output ./ to generate a Features.cs file in the output path or update an existing one.

nx plugin

  1. Install the plugin by running npm install @featureboard/nx-plugin
  2. Login to FeatureBoard by running npx @featureboard/cli login
  3. Generate a Features.cs file by running npm exec nx generate @featureboard/nx-plugin:code-gen --featureBoardProductName="My Product" --projectName=my-api --template=dotnet-api --subFolder=./

Manual creation

Note that FeatureKeyName can be used here to apply the correct feature key to a property, otherwise FeatureBoard will do it’s best to convert the property to a kebab case key.

using FeatureBoard.DotnetSdk.Models;
public class WeatherFeatures : IFeatures
{
[FeatureKeyName("weather-imperial")]
public bool WeatherImperial { get; set; }
}

Implement the audience provider

This provides the audiences of the current user or application context. For example it could pull the roles from the User and add the audience key role-admin, or it could pull a location header which your CDN provides and have country-australia as an audience.

using FeatureBoard.DotnetSdk;
public class ClaimsAudienceProvider : IAudienceProvider
{
public List<string> AudienceKeys { get; }
public ClaimsAudienceProvider(IHttpContextAccessor contextAccessor)
{
AudienceKeys = contextAccessor.HttpContext?.User.Claims
.Where(x => x.Type == "audience")
.Select(x => x.Value).ToList() ?? new List<string>();
}
}

Then register the IAudienceProvider provider with its corresponding implementation. This allows FeatureBoard to use your custom audience provider. e.g. inside Program.cs :

builder.Services.AddScoped<IAudienceProvider, ClaimsAudienceProvider>();

Register the provider in program.cs with an update strategy

FeatureBoard SDKs are designed to work with different update strategies to accommodate various application architectures.

This strategy means that the FeatureBoard service is polled for updates on a frequency based on the MaxAge configuration option in appsettings.json . Default value is 30 seconds.

var builder = WebApplication.CreateBuilder(args);
// Other typical Program.cs configuration entries go here
// Register FeatureBoard with polling strategy and the above ClaimsAudienceProvider
builder.Services.AddScoped<IAudienceProvider, ClaimsAudienceProvider>();
builder.Services.AddFeatureBoard<WeatherFeatures>(builder.Configuration)
.WithPollingUpdateStrategy();

Request update strategy

This strategy is useful for serverless applications where the VM gets paused between invocations, it will guarantee that the feature values are always up to date for the current invocation at the cost of an additional server call for every request.

var builder = WebApplication.CreateBuilder(args);
// Other typical Program.cs configuration entries go here
// Register FeatureBoard with polling strategy and the above ClaimsAudienceProvider
builder.Services.AddScoped<IAudienceProvider, ClaimsAudienceProvider>();
builder.Services.AddFeatureBoard<WeatherFeatures>(builder.Configuration)
.WithOnRequestUpdateStrategy();

Add middleware

// Add featureBoard middleware
app.UseFeatureBoard();

Azure Function Support

Azure Function 4.x support under .NET 8 has deprecated In-Process Azure Functions, as such to use .NET 8 with Azure Function 4.x Runtime requires a slight change. Here is an example Program.cs:

var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices((hostContext, services) =>
{
services.AddScoped<IAudienceProvider, ClaimsAudienceProvider>();
// Required for the FeatureBoard HTTP Client
services.AddHttpContextAccessor();
services
// An IConfiguration Root is required here
.AddFeatureBoard<FunctionFeatures>((hostContext.Configuration as IConfigurationRoot)!)
.WithPollingUpdateStrategy();
}).ConfigureLogging((hostingContext, logging) =>
{
// Required to bubble out library logging entries - will appear in App Insights
logging.AddConsole();
// Customise where appropriate
logging.AddConfiguration(hostingContext.Configuration.GetSection("MyLoggingSection"));
})
.Build();
host.Run();

Make sure "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated", is set. You may also need to add https://www.nuget.org/packages/Microsoft.Extensions.Http support to your project.

BackgroundService Support

Running a stand-alone background service as part of a Console app has a slightly different method of configuration. Given this example Program.cs:

var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddScoped<IAudienceProvider, ClaimsAudienceProvider>();
// Required for the FeatureBoard HTTP Client
services.AddHttpContextAccessor();
// An IConfiguration Root is required here
services.AddFeatureBoard<Features>((hostContext.Configuration as IConfigurationRoot)!)
.WithPollingUpdateStrategy();
// A class that implements BackgroundService. Note: register this last to ensure FeatureBoardSDK has
// refreshed values by the time the HostedService starts. Alternatively consider managing the HostedService
// started with an IHostApplicationLifetime instance.
services.AddHostedService<Worker>();
})
.Build();
host.Run();

You may also need to add https://www.nuget.org/packages/Microsoft.Extensions.Http support to your project.

Add the environment key to appsettings.json

.NET Application example:

{
....
"AllowedHosts": "*",
"FeatureBoardOptions": {
"EnvironmentApiKey": "YOUR KEY HERE",
"MaxAge": "00:00:30" // Optional (defaults to 30 seconds)
}
}

Azure Function example:

{
"Values": {
...
"FeatureBoardOptions__EnvironmentApiKey": "YOUR KEY HERE",
"FeatureBoardOptions__MaxAge": "00:00:30" // Optional (defaults to 30 seconds)
}
}

Usage

using FeatureBoard.DotnetSdk;
using FeatureBoardSdks.Examples.DotnetApi.Models;
using Microsoft.AspNetCore.Mvc;
namespace FeatureBoardSdks.Examples.DotnetApi.Controllers;

The FeatureBoard client can be injected into your class or controller with dependency injection and used directly to resolve features for the current users audience.

[ApiController]
[Route("[controller]")]
public class IconController : ControllerBase
{
private readonly IFeatureBoardClient<Features> _featureBoardClient;
public IconController(ILogger<IconController> logger, IFeatureBoardClient<Features> featureBoardClient)
{
_featureBoardClient = featureBoardClient;
}
[HttpPut(Name = "Icons")]
public IActionResult Put(IconUpdate update)
{
if (!_featureBoardClient.GetFeatureValue(features => features.AllowEdits, false))
{
return Unauthorized();
}
_repository.UpdateIcon(update)
}
}

Or if you have generated your features model though the cli you can use the generated FeatureFilter attributes to limit access

[ApiController]
[Route("[controller]")]
public class IconController : ControllerBase
{
private readonly IRepository _repository;
public IconController(ILogger<IconController> logger, IRepository _repository)
{
_featureBoardClient = featureBoardClient;
}
[HttpPut(Name = "Icons")]
[FeatureFilter(BooleanFeature.AllowEdits, false)]
public IActionResult Put(IconUpdate update)
{
_repository.UpdateIcon(update)
}
}

External State Store

You can create an external state store in the case where FeatureBoard is unavailable. To do this, implement IFeatureBoardExternalState.

using FeatureBoard.DotnetSdk.Models;
using FeatureBoard.DotnetSdk.States;
public class MyExternalState: IFeatureBoardExternalState
{
Task<IReadOnlyCollection<FeatureConfiguration>> GetState(CancellationToken cancellationToken);
{....}
Task UpdateState(IReadOnlyCollection<FeatureConfiguration> features, CancellationToken cancellationToken);
{....}
}

Then register it in Program.cs.

builder.Services.AddFeatureBoard<WeatherFeatures, QueryStringAudienceProvider>()
.WithPollingUpdateStrategy()
.WithExternalState<MyExternalState>();