/Docs

ASP.NET Core integration

This guide targets ASP.NET Core on .NET 8 or later (Minimal API or MVC). The Avsb.SDK NuGet package provides an IServiceCollection.AddAvsb() extension, ASP.NET Core middleware for per-request context scoping, and an IAvsbClient interface for clean dependency injection. By the end you will be reading flags in controllers, Razor Pages, and Blazor components, and tracking events through the same typed client.

1

Install

terminal
bash
1dotnet add package Avsb.SDK
2

Obtain your SDK key

Open your A vs B project, go to Settings → Environments, and copy the Server SDK key. Store it in appsettings.json (non-secret environments) or in User Secrets / Azure Key Vault for production.

terminal — User Secrets for development
bash
1dotnet user-secrets set "Avsb:SdkKey" "sdk_production_..."
3

Register the SDK in Program.cs

Program.cs
csharp
1using Avsb.AspNetCore;
2
3var builder = WebApplication.CreateBuilder(args);
4
5builder.Services.AddAvsb(opts =>
6{
7 opts.SdkKey = builder.Configuration["Avsb:SdkKey"]!;
8
9 // Optional: build the EvalContext from each HttpContext.
10 opts.ContextFrom = ctx =>
11 {
12 var userId = ctx.User.FindFirst("sub")?.Value ?? "anon";
13 var plan = ctx.User.FindFirst("plan")?.Value ?? "free";
14 return new EvalContext
15 {
16 Kind = "user",
17 Key = userId,
18 Attributes = new Dictionary<string, object> { ["plan"] = plan },
19 };
20 };
21});
22
23var app = builder.Build();
24
25app.UseAvsb(); // registers per-request context middleware
26app.MapControllers();
27
28await app.RunAsync();
Startup initialisation
AddAvsb registers IAvsbClient and IAvsbServer as singletons. The SDK fetches the datafile during application startup (before the first request) so flags are immediately available with no async wait in your handlers.
4

Inject IAvsbClient into a controller

Controllers/CheckoutController.cs
csharp
1using Avsb;
2using Microsoft.AspNetCore.Mvc;
3
4[ApiController]
5[Route("[controller]")]
6public class CheckoutController : ControllerBase
7{
8 private readonly IAvsbClient _avsb;
9
10 public CheckoutController(IAvsbClient avsb) => _avsb = avsb;
11
12 [HttpGet]
13 public IActionResult Get()
14 {
15 var showNew = _avsb.GetBoolFlag("checkout-v2", false);
16 var theme = _avsb.GetStringFlag("ui-theme", "default");
17
18 return Ok(new { showNewCheckout = showNew.Value, theme = theme.Value });
19 }
20}
5

Read a flag

Every typed method returns a Flag<T>. The generic type is inferred from the default value.

csharp
1// Boolean flag
2var checkout = _avsb.GetBoolFlag("checkout-v2", false);
3if (checkout.Value) { /* serve new experience */ }
4
5// String flag
6var theme = _avsb.GetStringFlag("ui-theme", "default");
7
8// JSON flag (deserialised to a target type)
9var config = _avsb.GetJsonFlag<PricingConfig>("pricing-config", PricingConfig.Default);
10
11// Access metadata
12Console.WriteLine($"Source: {checkout.Source}, Variation: {checkout.VariationKey}");
6

Track an event

csharp
1_avsb.Track("purchase", new TrackPayload
2{
3 Value = 149.99m,
4 Properties = new Dictionary<string, object> { ["currency"] = "usd" },
5});
7

Identify a user

The middleware scopes IAvsbClient to the context built by yourContextFrom delegate. To evaluate against a different identity mid-request, inject IAvsbServer and call ForUser:

csharp
1// Constructor: private readonly IAvsbServer _server;
2var scoped = _server.ForUser(new EvalContext
3{
4 Kind = "user",
5 Key = user.Id.ToString(),
6 Attributes = new Dictionary<string, object>
7 {
8 ["plan"] = user.Plan,
9 ["orgId"] = user.OrgId.ToString(),
10 },
11});
12var flag = scoped.GetBoolFlag("checkout-v2", false);

Using flags in Blazor

Inject IAvsbClient into Blazor Server components. For Blazor WebAssembly, use the browser-side @avsbhq/react or @avsbhq/browser packages instead.

Components/CheckoutBanner.razor
csharp
1@inject IAvsbClient Avsb
2
3@if (Avsb.GetBoolFlag("checkout-v2", false).Value)
4{
5 <NewCheckoutComponent />
6}
7else
8{
9 <LegacyCheckoutComponent />
10}

Graceful shutdown

app.UseAvsb() registers the SDK as a hosted service that implementsIAsyncDisposable. ASP.NET Core's shutdown sequence calls DisposeAsync automatically — pending events are flushed and the polling background service is stopped cleanly with no extra configuration.

Testing

Tests/CheckoutControllerTests.cs
csharp
1using Avsb.Testing;
2using Microsoft.AspNetCore.Mvc.Testing;
3using Xunit;
4
5public class CheckoutControllerTests : IClassFixture<WebApplicationFactory<Program>>
6{
7 private readonly WebApplicationFactory<Program> _factory;
8
9 public CheckoutControllerTests(WebApplicationFactory<Program> factory)
10 => _factory = factory;
11
12 [Fact]
13 public async Task ReturnsNewCheckout_WhenFlagIsOn()
14 {
15 var factory = _factory.WithWebHostBuilder(builder =>
16 builder.ConfigureServices(services =>
17 services.AddAvsbMock(mock =>
18 mock.FlagOn("checkout-v2"))));
19
20 var client = factory.CreateClient();
21 var resp = await client.GetAsync("/checkout");
22
23 resp.EnsureSuccessStatusCode();
24 var body = await resp.Content.ReadFromJsonAsync<dynamic>();
25 Assert.True((bool)body!.showNewCheckout);
26 }
27}

What's next