MissionControl.Client 0.0.6

Prefix Reserved
dotnet add package MissionControl.Client --version 0.0.6
                    
NuGet\Install-Package MissionControl.Client -Version 0.0.6
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MissionControl.Client" Version="0.0.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MissionControl.Client" Version="0.0.6" />
                    
Directory.Packages.props
<PackageReference Include="MissionControl.Client" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MissionControl.Client --version 0.0.6
                    
#r "nuget: MissionControl.Client, 0.0.6"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MissionControl.Client@0.0.6
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MissionControl.Client&version=0.0.6
                    
Install as a Cake Addin
#tool nuget:?package=MissionControl.Client&version=0.0.6
                    
Install as a Cake Tool

MissionControl.Client — .NET SDK

The .NET SDK for the Mission:Control Partner API. Built on top of Kiota, it provides a strongly-typed, async client for all partner operations: listing products, managing reservations, and creating orders.

Requirements

.NET 8 or later

Installation

dotnet add package MissionControl.Client

Getting started

Creating a client

Credentials are obtained from the Client Credentials page in the Mission:Control portal.

using MissionControl.Client;

var client = new ClientBuilder()
    .WithAzureAdClientCredentials(
        clientId:     "your-client-id",
        clientSecret: "your-client-secret")
    .WithDefaultPartnerId("your-partner-id")
    .Build();

By default the client targets Production. To use the Sandbox environment during development:

var client = new ClientBuilder()
    .ForEnvironment(MissionControlEnvironment.Sandbox)
    .WithAzureAdClientCredentials(
        clientId:     "your-client-id",
        clientSecret: "your-client-secret")
    .WithDefaultPartnerId("your-partner-id")
    .Build();

Dependency injection (ASP.NET Core)

Register the client as a singleton so the underlying HttpClient and token cache are shared across the application lifetime.

// Program.cs / Startup.cs
builder.Services.AddSingleton(_ =>
    new ClientBuilder()
        .ForEnvironment(MissionControlEnvironment.Production)
        .WithAzureAdClientCredentials(
            clientId:     builder.Configuration["MissionControl:ClientId"]!,
            clientSecret: builder.Configuration["MissionControl:ClientSecret"]!)
        .WithDefaultPartnerId(builder.Configuration["MissionControl:PartnerId"]!)
        .Build());

Then inject MissionControl.Client.Generated.Client wherever you need it:

public class ProductService(MissionControl.Client.Generated.Client mcClient)
{
    public async Task<IReadOnlyList<Product>> GetAllAsync(CancellationToken ct = default)
    {
        var result = await mcClient.Product.GetAsync(cancellationToken: ct);
        return result?.Result ?? [];
    }
}

Usage examples

List products

var result = await client.Product.GetAsync();

foreach (var product in result!.Result!)
    Console.WriteLine($"{product.Id}  {product.Name}");

Check stock

var response = await client.Product.HasStock.PostAsync(new HasStockRequest
{
    ProductId = productId,
    RegionId  = regionId,
});

Console.WriteLine(response!.HasStock == true ? "In stock" : "Out of stock");

Reserve → claim (place an order)

// 1. Create a reservation — holds the key briefly while the customer checks out.
var reservation = await client.Reservation.PostAsync(new CreateReservationRequest
{
    ProductId = productId,
    RegionId  = regionId,
});

// 2. Claim the reservation to finalise the order and receive the key.
var order = await client.Order.ClaimReservation[reservation!.Id!.Value].PostAsync(
    new ClaimReservationRequest
    {
        RequestId        = Guid.NewGuid(),
        PartnerReference = "your-internal-order-ref",
        InvoiceDate      = DateTimeOffset.UtcNow,
        SalesChannel     = [],   // empty if selling directly to consumer
        EndConsumer = new Consumer
        {
            IpAddress = "1.2.3.4",
            Language  = "en-US",
            Location  = new Location { CountryCode = "NL" },
        },
        SalesPrice = new SalesPriceRequest
        {
            PriceIncludingVat = new Money { Value = 9.99, CurrencyCode = "EUR" },
            VatDetail         = new VatDetail { Rate = 21 },
        },
    });

Console.WriteLine($"Order {order!.Id} placed.");

Cancel a reservation

await client.Reservation[reservation!.Id!.Value].Cancel.PostAsync();

Filtering and pagination

All list endpoints accept an optional query parameter lambda for filtering and pagination. Every parameter is optional — only set what you need.

Filter products by publisher, name, and page size:

var result = await client.Product.GetAsync(q =>
{
    q.QueryParameters.PublisherId = [publisherId];
    q.QueryParameters.Name        = "minecraft";
    q.QueryParameters.PageSize    = 25;
    q.QueryParameters.PageIndex   = 0;
});

Configuration reference

Key Required Description
clientId Application (client) ID from the portal
clientSecret Client secret from the portal
partnerId Partner ID sent as X-Partner-Id with every request
environment Sandbox or Production (default: Production)
tenantId Azure AD tenant ID (defaults to the Mission:Control tenant)

ClientBuilder methods

Method Description
WithAzureAdClientCredentials(clientId, clientSecret, tenantId?) Configure authentication
WithDefaultPartnerId(partnerId) Set the X-Partner-Id header for every request
ForEnvironment(env) Target Sandbox or Production
WithBaseUrl(url) Override the base URL (e.g. for local development)
WithScope(scope) Override the OAuth scope
Build() Return the configured Client instance

Resilience

The SDK registers Kiota's default HTTP middleware pipeline, which includes a RetryHandler that automatically retries transient failures before surfacing an exception:

Status code Meaning Behaviour
429 Too Many Requests Retried after honouring Retry-After
503 Service Unavailable Retried with exponential back-off
504 Gateway Timeout Retried with exponential back-off

The handler retries up to three times by default. If all retries are exhausted without a successful response the last error response is returned to the caller (and mapped to a ProblemDetails exception where applicable).

No extra configuration is required — retries are active out of the box.

Error handling

The API returns errors as RFC 9457 Problem Details JSON objects. The SDK maps these to ProblemDetails exceptions, which you catch like any other exception.

ProblemDetails properties

Property Type Description
Status int? HTTP status code (e.g. 400, 500)
Title string? Short, human-readable summary of the problem
Detail string? Longer explanation of this specific occurrence
Type string? URI identifying the problem type
Instance string? URI identifying this specific occurrence
AdditionalData IDictionary<string,object> Any extra fields returned by the API (e.g. errors, traceId)

Status codes

Status When it occurs
400 The request failed validation — check AdditionalData["errors"] for per-field messages
500 An unexpected error occurred on the server — AdditionalData["traceId"] can be shared with support

Handling a validation error (400)

A 400 response from the API looks like:

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "ProductId": ["The value 'foobar' is not valid."]
  },
  "traceId": "00-90f2dadbc2e77ae87cbe3b8a25fe0689-dbff6f5f82d028d2-00"
}

errors and traceId are not first-class properties on the model — they land in AdditionalData because they are not part of the OpenAPI schema. Cast them as needed:

using MissionControl.Client.Generated.Models;

try
{
    var result = await client.Product.GetAsync(q =>
    {
        q.QueryParameters.ProductId = [Guid.Parse("not-a-guid")];
    });
}
catch (ProblemDetails ex)
{
    Console.WriteLine($"Failed: {ex.Title}");

    if (ex.AdditionalData.TryGetValue("errors", out var raw) &&
        raw is Dictionary<string, object> errors)
    {
        foreach (var (field, messages) in errors)
            Console.WriteLine($"  {field}: {messages}");
    }

    if (ex.AdditionalData.TryGetValue("traceId", out var traceId))
        Console.WriteLine($"  Trace ID: {traceId}");
}
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.6 110 4/8/2026