Documentation · SoftActivate Licensing

Quickstart: .NET (C# / VB.NET)

This quickstart takes about ten minutes. You activate a license from .NET, persist it to disk, confirm it validates with no network connection, and release the seat again. C# and VB.NET consume the same assembly - SWS.dll, imported as SWS.Licensing - and every example on this page is shown in both languages.

Before you start

From Getting started you should have your vendor id (console → Settings), a license key (issued by an order, Orders → Create, and emailed to the customer), and the NuGet package:

dotnet add package SoftActivate.Sdk

The whole program

This is a complete, runnable integration: the same loop your application runs on every start.

C#

using System;
using System.IO;
using System.Threading.Tasks;
using SWS.Licensing;

internal static class Program
{
    private static async Task<int> Main()
    {
        using var client = new LicensingClient("https://lm.sws.softactivate.com")
        {
            // your tenant coordinates - vendor id from the console (Settings),
            // license key from your order's delivery email
            VendorId = "YOUR-VENDOR-ID",
            LicenseKey = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
            TrustedDomain = "sws.softactivate.com"
        };

        // your product's Reference Id (console -> Products): a key for a
        // different product is refused - see the product binding guide
        client.SetProductId("YOUR_PRODUCT_ID");

        // after the first (online) activation, every later start validates the
        // stored license file with no network access at all
        License? existing = File.Exists("license.dat")
            ? License.Parse(File.ReadAllText("license.dat"))
            : null;

        // with no stored license this activates the device (online, once); with one
        // it verifies the chain, the device fingerprint and the dates locally -
        // and renews online only when needed
        LicenseValidationResult result = await client.ValidateLicenseAsync(existing);

        if (!result.IsValid)
        {
            // the precise status says WHY - expired, revoked, bound to another
            // machine, subscription lapsed... each deserves different UX; see the
            // statuses reference: /licensing/docs/status-codes/
            Console.Error.WriteLine($"License is not valid: {result.Status}");
            return 1;
        }

        // persist the new or renewed certificate whenever one is issued
        if (result.UpdatedLicense != null)
            File.WriteAllText("license.dat", result.UpdatedLicense.Serialize());

        License current = result.UpdatedLicense ?? existing!;
        Console.WriteLine($"License is valid until {current.ExpirationDate:u}.");
        return 0;
    }
}

VB.NET

Imports System
Imports System.IO
Imports System.Threading.Tasks
Imports SWS.Licensing

Module Program
    Function Main() As Integer
        Return MainAsync().GetAwaiter().GetResult()
    End Function

    Private Async Function MainAsync() As Task(Of Integer)
        ' your tenant coordinates - vendor id from the console (Settings),
        ' license key from your order's delivery email
        Using client As New LicensingClient("https://lm.sws.softactivate.com") With {
            .VendorId = "YOUR-VENDOR-ID",
            .LicenseKey = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
            .TrustedDomain = "sws.softactivate.com"
        }
            ' your product's Reference Id (console -> Products): a key for a
            ' different product is refused - see the product binding guide
            client.SetProductId("YOUR_PRODUCT_ID")

            ' after the first (online) activation, every later start validates the
            ' stored license file with no network access at all
            Dim existing As License = Nothing
            If File.Exists("license.dat") Then
                existing = License.Parse(File.ReadAllText("license.dat"))
            End If

            ' with no stored license this activates the device (online, once); with
            ' one it verifies the chain, the device fingerprint and the dates
            ' locally - and renews online only when needed
            Dim result As LicenseValidationResult = Await client.ValidateLicenseAsync(existing)

            If Not result.IsValid Then
                ' the precise status says WHY - expired, revoked, bound to another
                ' machine, subscription lapsed... each deserves different UX; see
                ' the statuses reference: /licensing/docs/status-codes/
                Console.Error.WriteLine($"License is not valid: {result.Status}")
                Return 1
            End If

            ' persist the new or renewed certificate whenever one is issued
            If result.UpdatedLicense IsNot Nothing Then
                File.WriteAllText("license.dat", result.UpdatedLicense.Serialize())
            End If

            Dim current As License = If(result.UpdatedLicense, existing)
            Console.WriteLine($"License is valid until {current.ExpirationDate:u}.")
            Return 0
        End Using
    End Function
End Module

Replace the vendor id and license key with yours, put deployment-root.crt next to the binary (in your real product, embed it as a resource or install it with your application), and run it.

Run it three times

  1. First run (online): no license.dat exists, so ValidateLicenseAsync activates the device with the service. The SDK receives the license and the program saves it to license.dat.
  2. Second run (disconnect the network if you like): the stored license is verified entirely on the machine, and no network access happens. This is the everyday path your customers' machines take on every start.
  3. Moving on: when you are done with this machine, release its seat so the key can activate elsewhere:
await client.DeactivateLicenseAsync();
File.Delete("license.dat"); // the local file is now meaningless
Await client.DeactivateLicenseAsync()
File.Delete("license.dat") ' the local file is now meaningless

When validation says no

A false result.IsValid can mean several different things. result.Status tells you whether the license is expired, revoked, bound to a different device (BadContext), or waiting on a lapsed subscription (PaymentRequired, with the subscription state in result.StatusMessage), and each case deserves different UX. The statuses and errors reference maps every status to a recommended action.

Next: the C++ quickstart, or the statuses and errors reference.