LicenPro
Documentation.NET SDK.NET integration

.NET SDK

The LicenPro NuGet package is the supported way to validate license.bin, run activations and sessions, surface subscription expiry warnings, and perform license-aware product updates. This page reflects the public API used by the reference WinForms host and the SDK source (not legacy samples that referenced non-existent packages).

Package and runtime

Target .NET 6+ or .NET Framework 4.7.2+. Install LicenPro from NuGet (SDK assembly ships as 1.7.x — check NuGet for the latest). Namespaces you will use most: LicenPro.SDK, LicenPro.Models.Utils, LicenPro.SDK.AppHosting, LicenPro.SDK.Updates.

1. Configuration and API base URL

Almost every call goes to your LicenPro API. The base URL must be absolute and end with /api. The shared cloud host is https://licenpro.runasp.net/api. If you self-host the API, replace the host with your deployment (same /api suffix).

Settings resolution order:

  1. SdkConfiguration.Initialize(...) if you invoke it yourself.
  2. Otherwise the SDK scans the application base directory for licenpro.settings.json, then appsettings.json (either file may contain a nested LicenPro object with the same shape as SdkSettings).
  3. If nothing is found, built-in defaults apply (override for self-hosted).
dotnet add package LicenPro

using LicenPro.Models.Utils;
using LicenPro.SDK;

var settings = new SdkSettings {
    ServerBaseEndpoint = "https://licenpro.runasp.net/api"
};
SdkConfiguration.Initialize(settings);

When you construct LicenseClient, you may set LicenseClientOptions.ServerEndpoint; the client normalizes it to end with /api and calls SdkConfiguration.Initialize during validation if needed. Optional LicensingSecrets:ApiKey in the same JSON files is picked up for authenticated dashboard API calls (usage tracking, some advanced flows).

2. Desktop startup: staged updates

For WinForms, WPF, or any desktop process, call SdkBootstrap.OnApplicationStartup() once before showing UI. It touches SdkConfiguration.Settings (triggering default file load) and completes any pending product update staged on a previous run.

using LicenPro.SDK.AppHosting;

SdkBootstrap.OnApplicationStartup();

3. LicenseClient and validation

LicenseClient is the primary façade. Construct it with LicenseClientOptions: at minimum LicenseFilePath, PublicKey (Base64, no PEM headers), and LicenseKey. Call ValidateAsync() for the full online path (signature, server rules, activation, session wiring). Use ValidateOfflineAsync() when you intentionally skip live server checks after you already trust the file.

using LicenPro.SDK;
using LicenPro.SDK.Enums;

var client = new LicenseClient(new LicenseClientOptions {
    LicenseFilePath = "C:/ProgramData/MyApp/license.bin",
    PublicKey = publicKeyBase64,
    LicenseKey = "LP-XXXX-...",
    ExpectedLicenseType = LicenseType.Perpetual, // optional filter
    ProductId = "00000000-0000-0000-0000-000000000000", // optional; helps update checks if not in file
    SubscriptionExpiryWarningDays = 7,          // default; 0 disables
    IncludeTrialInExpiryWarnings = false          // set true to warn on trial expiry too
});

var result = await client.ValidateAsync();

if (result.IsValid)
{
    // result.License — strongly typed graph
    // result.ExpiryNotice — populated for subscription/trial inside warning window
    client.LicenseExpiringSoon += (_, e) => { /* UI prompt */ };
}
else
{
    // result.Status — LicenseValidationStatus enum
    // result.ErrorTitle / result.ErrorMessage — user-facing copy
}

await client.DisposeAsync();
Status model

Use result.IsValid and result.Status (LicenseValidationStatus: Valid, Expired, Revoked, SignatureMismatch, CredentialsMismatch, WrongLicenseType, DeviceBlocked, InvalidFormat, and others). Older samples that referenced LicenseStatus on the validation result are incorrect for this API surface.

4. UI-friendly failure presentation

LicenPro.SDK.AppHosting.LicenseValidationFeedback.From(result) maps a failed LicenseValidationResult into titles, body text, and ARGB colors for status strips or message boxes without pulling WinForms-specific types into your view models.

5. Offline cache and “next launch”

LicenseClient.ValidateAndCacheAsync(...) reads license.bin (including protected/encrypted payloads decrypted with the license key), validates, and on success persists credentials and bytes for fast startup. On a later run, LicenseClient.TryAutoValidateAsync(licenseKey, publicKey) reloads the cache, re-validates, and returns a CacheValidationResult with Client ready for ConnectSessionAsync if you still need online features. If the cache was written with an older encrypted format, TryAuto may return LicenseKeyRequired until the user enters the key once.

6. Subscription expiry notices

Successful validation may set result.ExpiryNotice when the subscription (or trial, if enabled) is inside the configured whole-day warning window. The client also raises LicenseExpiringSoon on the synchronization context captured in the constructor (ideal for WinForms/WPF UI threads).

7. License-aware product updates

After validation, the SDK keeps the update manager in sync with license key, hardware id, and product id (from the extended license payload or LicenseClientOptions.ProductId). Use SdkUpdateExtensions on your LicenseClient instance: EnableAutoUpdates(...) for periodic checks, CheckAndApplyUpdateAsync(...) for explicit download-and-stage, and DisableAutoUpdates() to stop timers. Eligibility rules (perpetual vs subscription vs node-locked, release pins, “all versions”) are enforced server-side; the SDK simply supplies identity and version context.

8. Sessions and telemetry

Successful online validation attempts activation and session connection inside ValidateAsync. You can still call ConnectSessionAsync later for long-running desktop apps. Subscribe to SessionDisconnected to react to heartbeat loss. Dashboard operators see the data under Sessions / Activations — see Sessions & activations.

9. Version string for updates

SdkAssemblyInfo.GetSemanticVersionString(Assembly.GetExecutingAssembly()) is a small helper so the update channel receives a semver-style string consistent with packaged releases.

10. Related reading