Skip to content

SDK-Integration

.NET-SDK-Integration

Ein vollständiger Rundgang von null bis lizenziert: Produkt in Keyright anlegen, öffentlichen Schlüssel mit Keyright.NET einbetten, Funktionen offline schützen, online aktivieren und Schlüssel an Kunden ausgeben — konstruktionsbedingt fail-closed.

Dies ist der komplette Weg — von einem leeren Keyright-Arbeitsbereich bis zu einer ausgelieferten .NET-App, die bezahlte Funktionen gegen einen echten Lizenzschlüssel freischaltet. Er deckt beide Seiten ab: die Anbietereinrichtung, die Sie einmalig im Keyright-Dashboard vornehmen, und den Client-Code, den Sie mit dem Keyright.NET-SDK einbetten. Jeder Codeblock verwendet die echte SDK-Oberfläche; kopieren Sie ihn unverändert.

Wenn Sie nur den komprimierten Anbieterpfad möchten, siehe Erste Schritte. Diese Seite ist die durchgängige Version für Entwickler.

Was Sie bauen werden

Sie stellen Lizenzschlüssel serverseitig in Keyright aus — jeder Mandant (Ihr Arbeitsbereich) signiert sie mit seinem eigenen privaten RSA-Schlüssel, der den Server nie verlässt. Ihre App bettet nur den passenden öffentlichen Schlüssel ein und prüft Lizenzen offline dagegen, sodass eine Lizenzprüfung kein Netzwerk braucht. Für Platzdurchsetzung und Widerruf aktivieren Sie zusätzlich online: Die App tauscht einen Lizenzschlüssel gegen einen kurzlebigen signierten Lease, der an die Maschine gebunden ist, und arbeitet dann offline weiter, bis dieser Lease abläuft. Alles, was nicht stimmt — ungültige Signatur, falsches Produkt, Ablauf, Widerruf, eine zurückgestellte Uhr — löst zur Edition Free auf, statt eine Ausnahme zu werfen. Das SDK ist fail-closed.

Schritt 1 — Produkt in Keyright anlegen

Melden Sie sich im Dashboard unter /dashboard an (z. B. https://keyright.delta1labs.com/dashboard) und öffnen Sie Products → New product. Geben Sie ihm einen Namen und einen Slug — der Slug ist die Kennung, die das SDK Ihrer App als Product sendet; wählen Sie also etwas Stabiles in Kleinbuchstaben wie acme-app. Notieren Sie ihn; Sie fügen ihn in Schritt 5 in das SDK ein. (Das Dashboard öffnet sich in seiner Ansicht Basis, die genau die Seiten zeigt, die dieser Rundgang verwendet; die Dashboard-Kurzreferenz ordnet jede Aufgabe dem Ort zu, an dem sie zu finden ist.)

Ihr Arbeitsbereich besitzt bereits einen RSA-Signaturschlüssel, der beim Anlegen des Mandanten erzeugt wurde, und New product erzeugt standardmäßig einen produktspezifischen Schlüssel. Jede Lizenz und jeder Lease eines Produkts wird mit der privaten Hälfte signiert, die verschlüsselt auf dem Server gespeichert ist und ihn nie verlässt. Sie haben immer nur mit der öffentlichen Hälfte zu tun.

Dasselbe über die API:

curl -X POST $BASE/admin/products -H "X-Admin-Token: $TOKEN" -H "content-type: application/json" \
  -d '{"name":"Acme App","slug":"acme-app"}'

($BASE ist die URL Ihres Issuing-Service, $TOKEN ein Mandanten-Admin-/Sitzungstoken — siehe Erste Schritte.)

Schritt 2 — Öffentlichen Schlüssel holen

Öffnen Sie den Tab Signing key des Produkts (oder Developers → Keys, wo der Arbeitsbereichsschlüssel und jeder Produktschlüssel aufgeführt sind) und kopieren Sie den öffentlichen Schlüssel — einen base64-kodierten SubjectPublicKeyInfo-String. Die Seite Developers → Quickstart geht noch einen Schritt weiter und füllt das gesamte Snippet aus Schritt 5 für Sie vor. Oder rufen Sie den Arbeitsbereichsschlüssel über die API ab:

curl $BASE/admin/public-key -H "X-Admin-Token: $TOKEN"

Dieser Schlüssel ist kein Geheimnis. Er wird in Ihrer kompilierten Binärdatei ausgeliefert. Die gesamte Sicherheit beruht darauf, dass der private Schlüssel auf dem Server bleibt: Der öffentliche Schlüssel kann Signaturen nur prüfen, nie erzeugen. Ihn einzubetten, Ihre App zu dekompilieren, um ihn auszulesen, ihn sogar zu veröffentlichen — nichts davon erlaubt es jemandem, eine Lizenz zu fälschen.

Schritt 3 — Pläne & Entitlements definieren

Ein Produkt hat Tiers — das Dashboard nennt sie Editionen (z. B. pro, enterprise). Jede Edition trägt eine Platzanzahl und eine Entitlement-Vorlage — die benannten Flags und numerischen Limits, die in jede Lizenz dieser Edition eingebacken werden. Über Entitlements fragt Ihre App zur Laufzeit „Ist diese Funktion erlaubt?“. (Eine Edition kann außerdem eine Release-Abdeckungsrichtlinie tragen — welche Versionen ihre Lizenzen ausführen dürfen — behandelt in Schritt 11.)

Fügen Sie eine über den Tab Editions des Produkts im Dashboard hinzu (Add edition) oder über die API:

curl -X POST $BASE/admin/products/acme-app/tiers -H "X-Admin-Token: $TOKEN" -H "content-type: application/json" \
  -d '{"name":"pro","seats":3,"entitlements":{"export":"true","max-projects":"10"}}'

Entitlement-Werte sind auf der Leitung Strings: "true"/"false" für Flags, eine Ganzzahl oder das Literal "unlimited" für Limits. Ein Tier-String wird auf eine Edition abgebildet, auf die Ihre App verzweigen kann — enterprise → Enterprise, alles andere → Licensed, und gar keine Lizenz → Free.

Schritt 4 — SDK installieren

Keyright.NET ist auf NuGet verfügbar. Es ist Multi-Target für netstandard2.0 und net8.0 und läuft daher auf .NET Framework 4.8 und .NET 6–10.

dotnet add package Keyright.NET

Die Schwester-SDKs prüfen exakt dieselben Lizenz- und Lease-Formate für andere Laufzeiten — Node.js, Python und Java —, sodass eine mehrsprachige Produktlinie einen Keyright-Mandanten und einen öffentlichen Schlüssel teilen kann. Kein SDK für Ihre Sprache? Rufen Sie die HTTP-API direkt auf. Diese Seite behandelt den .NET-Client.

Schritt 5 — Client initialisieren

Erzeugen Sie beim Start einen KeyrightClient mit dem Produkt-Slug aus Schritt 1, dem öffentlichen Schlüssel aus Schritt 2 und (für die Online-Aktivierung) Ihrer Service-URL. Verwenden Sie die statische Factory Initialize — sie validiert die Optionen und lädt den Schlüssel vorab:

using Keyright.Client;

static readonly KeyrightClient License = KeyrightClient.Initialize(new KeyrightOptions
{
    Product         = "acme-app",                          // muss mit dem Produkt-Slug übereinstimmen, für den Sie Schlüssel ausstellen
    PublicKeyBase64 = "MIIBIjANBgkq...",                   // der base64-kodierte öffentliche Schlüssel aus Schritt 2
    ServiceUrl      = "https://licensing.acme.example",    // IHR Keyright-Issuing-Service — siehe Hinweis unten; weglassen, wenn nur offline

    // Optional: einen alten Schlüssel während eines Rotationsfensters gültig halten (Schritt 9)
    // AdditionalPublicKeysBase64 = { "<previous public key>" },
});

ServiceUrl ist Ihr Keyright-Issuing-Service, nicht unserer — setzen Sie ihn auf die API-Basis-URL Ihres verwalteten Mandanten oder, wenn Sie Keyright selbst hosten, auf die Basis-URL Ihrer eigenen Instanz (z. B. https://licensing.acme.example). Dasselbe SDK funktioniert mit beidem; nichts ist fest auf einen Delta1-Endpunkt verdrahtet. Nur Product und PublicKeyBase64 sind erforderlich. Das SDK sucht eine Lizenz in mehreren Quellen, in Rangfolge (höchste zuerst): ein explizites LicenseString, dann ein expliziter LicenseFilePath, dann die Umgebungsvariable KEYRIGHT_LICENSE (ein Pfad zu einer Lizenzdatei), dann ConfigLicensePath, dann der App-Daten-Pfad des Betriebssystems ({LocalApplicationData}/Keyright/{product}/license.json) und schließlich der zwischengespeicherte Aktivierungs-Lease. Normalerweise setzen Sie keine davon — die Aktivierung (Schritt 7) schreibt den Lease-Cache für Sie.

Schritt 6 — Funktionen offline schützen

Rufen Sie Validate() auf. Es ermittelt die beste Lizenz aus den obigen Quellen und prüft RSA-Signatur, Produktübereinstimmung, Node-Lock, Ablauf, die optionale mitgelieferte Widerrufsliste sowie den Testversions-/Uhrmanipulationsstatus — alles offline, und es wirft nie eine Ausnahme. Bei jedem Fehler liefert es eine LicenseInfo in der Edition Free, die den Grund enthält.

LicenseInfo info = License.Validate();

if (info.IsPaid)                       // true für jede Edition oberhalb von Free
{
    // bezahlte Funktionen freischalten
}

if (info.Edition == Edition.Enterprise)
{
    // Enterprise-exklusive Funktionen freischalten
}

Schützen Sie einzelne Funktionen über Entitlements statt über die Edition, damit eine Änderung der Tier-Vorlage nicht bedeutet, neuen Code auszuliefern:

// Boolesches Flag
if (License.IsEnabled("export"))
{
    ShowExportCommand();
}

// Numerisches Limit — den fail-closed-Fallback geben Sie selbst an
long maxProjects = License.GetLimit("max-projects", fallback: 1);
if (currentProjectCount >= maxProjects)
{
    PromptToUpgrade();
}

IsEnabled und GetLimit validieren jeweils an Ort und Stelle und sind fail-closed: Ein fehlendes Flag gilt als deaktiviert, ein fehlendes oder nicht parsbares Limit liefert Ihren Fallback. Wenn Sie mehrere Entitlements auf einmal prüfen, validieren Sie einmal und verwenden Sie das Ergebnis wieder, um wiederholte Arbeit zu vermeiden:

LicenseInfo info = License.Validate();
bool canExport  = info.Entitlements.IsEnabled("export");
long maxSeats   = info.Entitlements.GetLimit("max-seats", 1);

Um herauszufinden, warum eine Prüfung fehlgeschlagen ist (für einen „Registrieren“-Dialog oder Diagnosen), lesen Sie info.Status und die für Menschen gedachte info.Message; Validate(out LicenseSourceKind source) sagt Ihnen, welche Quelle gewonnen hat.

Schritt 7 — Online mit einem Lizenzschlüssel aktivieren

Wenn ein Kunde einen Schlüssel eingibt, rufen Sie ActivateAsync auf. Es sendet den Schlüssel plus eine stabile Maschinen-ID an Ihren Service, der einen Platz belegt und einen kurzlebigen, an diese Maschine gebundenen signierten Lease zurückgibt. Das SDK prüft den Lease gegen Ihren eingebetteten öffentlichen Schlüssel und speichert ihn lokal zwischen, sodass jedes spätere Validate() ohne Netzwerk erfolgreich ist, bis die Kulanzfrist des Lease abläuft.

ActivateAsync wirft für die gewöhnlichen Fehlerpfade (ungültiger Schlüssel, Platzlimit, offline, widerrufen) keine Ausnahme — es liefert wie Validate() eine fail-closed LicenseInfo. Prüfen Sie das Ergebnis:

LicenseInfo info = await License.ActivateAsync(customerEnteredKey, ct);

if (info.IsValid && info.IsPaid)
{
    // Aktiviert. Der Lease ist zwischengespeichert; die App arbeitet jetzt offline, bis er abläuft.
    ShowLicensedUi(info.StatusBadge);           // z. B. "Enterprise" oder "Enterprise Trial"
}
else
{
    // info.Message anzeigen; die App bleibt im Modus Free.
    ShowActivationError(info.Message);          // "All seats for this license are in use." usw.
}
  • Plätze werden serverseitig durchgesetzt. Das Aktivieren von mehr Maschinen, als die Lizenz erlaubt, liefert ein Platzlimit-Ergebnis und keinen Lease. Das erneute Aktivieren einer bereits gebundenen Maschine ist idempotent — es wird kein zusätzlicher Platz belegt.
  • Offline-Kulanz. Ist der Service nicht erreichbar, greift ActivateAsync auf einen noch gültigen zwischengespeicherten Lease zurück, sodass ein kurzer Ausfall den Benutzer nicht aussperrt. Nähert sich der Lease dem Ablauf, muss die App den Server erneut erreichen, um ihn zu aktualisieren.
  • Widerruf wird bei der nächsten Aktualisierung wirksam — siehe Schritt 9.

ActivateAsync wirft nur bei Programmierfehlern eine Ausnahme: eine fehlende ServiceUrl oder ein leerer Schlüssel.

Netzwerkisolierte (air-gapped) Maschinen. Für eine Maschine, die den Service nie erreichen kann, signiert ein Operator einen Offline-Lease für deren Maschinen-ID (License file → Offline activation der Lizenz oder POST /admin/licenses/{id}/offline-lease) und liefert das JSON per Datei aus. Importieren Sie es — dies wirft eine Ausnahme, wenn der Lease ungültig ist, also behandeln Sie sie:

try
{
    LicenseInfo info = License.ImportOfflineLease(File.ReadAllText("acme.lease.json"));
}
catch (InvalidOperationException ex)
{
    // falsche Signatur / falsches Produkt / falsche Maschine oder abgelaufen
}

Schritt 8 — Lizenzschlüssel an Ihre Kunden ausgeben

Sie können Schlüssel auf drei Wegen ausgeben:

  1. Über das Dashboard. Licenses → Issue license: Wählen Sie Produkt und Edition, legen Sie Lizenznehmer, Kontakt-E-Mail, Plätze und Laufzeit fest, und Keyright erzeugt den Schlüssel und zeigt ihn einmalig an. Der Drawer hat außerdem einen Trial-Schalter, um den Schlüssel als zeitlich begrenzte Testversion zu erzeugen (siehe Schritt 9 und Kostenlose Self-Service-Testversionen), sowie einen Abschnitt Advanced für Funktionsüberschreibungen, Notizen und einen benutzerdefinierten Schlüssel.
  2. Automatisch über Ihren Zahlungsanbieter. Verbinden Sie das Fulfillment Ihres Shops mit POST /webhooks/fulfill/{slug} (HMAC-signiert). Ein „paid“-Ereignis erzeugt eine Lizenz und sendet den Schlüssel per E-Mail; ein „refund“-/„cancel“-Ereignis widerruft sie — ohne manuellen Schritt.
  3. Über die Admin-API. POST /admin/licenses (erzeugt automatisch einen Schlüssel, sofern Sie keinen übergeben). Die vollständige Request-Struktur finden Sie in der HTTP-API-Referenz.

Wie auch immer Sie ausstellen: Der Schlüssel ist das, was der Kunde in Schritt 7 für ActivateAsync in Ihre App einfügt.

Schritt 9 — Testversionen, Node-Locking, Widerruf & Schlüsselrotation

  • Testversionen. Schalten Sie Self-Service-Testversionen pro Produkt ein und lassen Sie Kunden einen Schlüssel über Ihre eigene Website anfordern; ein Testschlüssel wird über exakt denselben ActivateAsync-Pfad aktiviert wie ein bezahlter. Zeigen Sie den Zustand direkt aus LicenseInfo an — info.IsTrial, info.StatusBadge (z. B. „Enterprise Trial“), info.ExpiryUtc und info.DaysRemaining für ein Badge „noch 27 Tage“. Die Dauer einer Testversion zählt ab der ersten Aktivierung, und sie wird nahtlos abgelöst, wenn der Kunde später einen bezahlten Schlüssel aktiviert. Vollständiger Ablauf: Kostenlose Self-Service-Testversionen.
  • Node-Locking. Das SDK leitet einen stabilen Maschinen-Fingerabdruck ab, mit einer kleinen NodeLockTolerance (Standard 1), damit eine getauschte Netzwerkkarte oder Festplatte den Benutzer nicht aussperrt. Um zu steuern, was eine Maschine identifiziert, implementieren Sie IMachineComponents und setzen Sie MachineComponents in den Optionen. Die Aktivierungsanfrage sendet diese Maschinen-ID, sodass Plätze pro Gerät gezählt werden.
  • Widerruf. Widerrufen Sie einen Schlüssel mit POST /admin/licenses/{id}/revoke (oder über die Zeilenaktion im Dashboard). Der Client fällt bei der nächsten Lease-Aktualisierung auf Free zurück (Status Revoked). Sie können außerdem eine signierte Widerrufsliste mit Ihrem Build ausliefern (RevocationListJson / RevocationListPath), damit auch eine rein offline arbeitende App Widerrufe berücksichtigt.
  • Schlüsselrotation. Wenn Sie den Mandanten-Signaturschlüssel rotieren, liefern Sie einen Build mit dem neuen öffentlichen Schlüssel in PublicKeyBase64 und dem auslaufenden in AdditionalPublicKeysBase64 aus — Lizenzen und Leases, die mit einem der beiden signiert wurden, bleiben während des Übergangs gültig. Entfernen Sie den alten Schlüssel aus der Liste, sobald jeder damit signierte Lease abgelaufen ist.

Schritt 10 — Ende-zu-Ende testen

  1. Aktivieren Sie im Dashboard Testversionen für acme-app (eine kurze Dauer genügt) und stellen Sie sich selbst einen Testschlüssel aus.
  2. Starten Sie Ihre App. Vor der Aktivierung liefert Validate() Free — Ihre bezahlten Funktionen bleiben gesperrt.
  3. Rufen Sie ActivateAsync mit dem Testschlüssel auf. Beobachten Sie, wie die App in den lizenzierten Zustand wechselt und das Badge z. B. auf „Pro Trial“ umspringt. Der Lease ist jetzt auf der Festplatte zwischengespeichert.
  4. Offline testen. Trennen Sie das Netzwerk und starten Sie die App neu. Validate() liefert weiterhin die lizenzierte LicenseInfo aus dem zwischengespeicherten Lease — ohne Server-Roundtrip — bis die Kulanzfrist des Lease endet.
  5. Widerruf testen. Widerrufen Sie die Lizenz, verbinden Sie sich wieder und lassen Sie den Lease aktualisieren; die App sollte auf Free zurückfallen.

Schritt 11 — Release-Abdeckung (optional)

Wenn Sie Updates verkaufen — „ein Jahr Updates“, „jedes 2.x-Release“, ein Abonnement —, kann Keyright festhalten, welche Releases jede Lizenz abdeckt, dies signieren und Ihren Build lokal entscheiden lassen, ob diese Version abgedeckt ist: keine Reaktivierung, keine erneute Schlüsseleingabe, funktioniert offline. Der vollständige Leitfaden ist Release-Abdeckung; die Client-Seite besteht aus zwei Schritten.

Dem Build mitteilen, welches Release er ist. Das Paket Keyright.NET liefert MSBuild-Targets mit, die diese Eigenschaften lesen und in die Assembly einbetten (setzen Sie sie aus Ihrer Release-Pipeline, z. B. -p:KeyrightCoverageVersion=2.4.0):

<PropertyGroup>
  <KeyrightCoverageVersion>2.4.0</KeyrightCoverageVersion>                   <!-- die Version dieses Builds -->
  <KeyrightCoverageEntitlementDate>2026-10-01</KeyrightCoverageEntitlementDate>  <!-- das Datum, gegen das die Abdeckung beurteilt wird; ein Hotfix verwendet das Datum seines Basis-Release -->
  <KeyrightCoverageChannel>stable</KeyrightCoverageChannel>                 <!-- oder beta -->
  <KeyrightRequireCoverage>true</KeyrightRequireCoverage>                   <!-- in diesem Build durchsetzen; lässt den Build fehlschlagen (KR0001), wenn das Datum fehlt -->
</PropertyGroup>

Beim Start prüfen. Die Aktivierung liefert den signierten Abdeckungsblock bereits mit dem Lease und speichert ihn zwischen. In einem durchsetzenden Build fragen Sie einmal; das SDK entscheidet anhand des zwischengespeicherten Blocks, aktualisiert die Lizenz stillschweigend, wenn dieser „nein“ sagt, und wirft bei Netzwerkproblemen nie eine Ausnahme:

using Keyright.Coverage;

if (CoverageBuildInfo.Current.RequireCoverage)
{
    CoverageCheckResult check = await License.CheckCoverageAsync(ct: ct);   // Version + Anspruchsdatum dieses Builds
    if (!check.IsCovered)                                                   // Covered und NotConfigured bestehen beide
    {
        // check.Status: NotCovered (check.Reason = WindowLapsed → verlängern, OutsideVersionRange → upgraden)
        //               oder UnavailableOffline (nichts zwischengespeichert und kein Netzwerk → Abdeckungsdatei importieren)
        // CoverageMessaging.Build(...) liefert Ihnen den Satz und die einzelne Aktion (verlängern / upgraden / importieren).
        RunReadOnlyOrBlock(check);
    }
}

bool can30 = License.IsCovered("3.0.0");        // für Ihr eigenes Update-Banner — lokal, ohne Netzwerk
CoverageInfo cov = License.GetCoverage();       // die Bedingungen, das Support-bis-Datum, enforced / unenforced

Für netzwerkisolierte (air-gapped) Kunden importieren Sie die aus dem Dashboard exportierte Abdeckungsdatei mit License.ImportCoverageBlock(json). Ihre eigene Download-Seite stellt dieselbe Frage mit POST /v1/coverage.

Fehlerbehebung

  • Die Aktivierung meldet, der Schlüssel sei nicht erkannt worden. Die häufigste Ursache ist eine Produktabweichung: Der Schlüssel wurde für ein anderes Produkt (oder einen anderen Mandanten) ausgestellt als der Product-Slug, mit dem Ihr Client konfiguriert ist. Der Server begrenzt die Aktivierung auf das Produkt, daher aktiviert ein gültiger Schlüssel für acme-app keinen Client, der mit Product = "other-app" initialisiert wurde. Stellen Sie sicher, dass der Slug in Schritt 5 mit dem Produkt übereinstimmt, unter dem Sie den Schlüssel ausgestellt haben.
  • Alles wird als Free erkannt. Das ist Absicht — das SDK ist bei jedem Prüfproblem fail-closed, statt eine Ausnahme zu werfen. Lesen Sie info.Status (z. B. NoLicense, SignatureInvalid, Expired, MachineMismatch, Revoked) und info.Message, um zu sehen, welches Problem vorliegt. Ein SignatureInvalid bedeutet fast immer, dass der eingebettete öffentliche Schlüssel nicht zu dem Mandanten passt, der den Schlüssel signiert hat.
  • Eine zeitlich begrenzte Lizenz lässt sich plötzlich nicht mehr validieren. Wird die Systemuhr bei einer Testversion oder einem Abonnement um mehr als ClockTamperToleranceHours (Standard 24 h) zurückgestellt, wertet das SDK dies als Uhrmanipulation und liefert den Status ClockTampered. Das bleibt nicht haften — stellen Sie die korrekte Zeit ein, und die Validierung erholt sich beim nächsten Aufruf. Unbefristete Lizenzen unterliegen dieser Prüfung nie.

Siehe auch