.NET SDK — activate a license
Activation exchanges a license key (and the device’s fingerprint) for a session — a claimed seat plus a signed, cached license the SDK can validate locally. Your application holds that session while it runs and releases it on shutdown.
Access the license
Section titled “Access the license”ILicenseSession is the single entry point. Resolve it from the request/lifetime scope
and call AccessLicenseAsync. The first call activates; subsequent calls return the
cached, still-valid license without a round trip.
public class LicenseGate(ILicenseSession session){ public async Task<bool> IsLicensedAsync() { var access = await session.AccessLicenseAsync(); return access.Value is { LicenseValidation.IsOperational: true }; }}AccessLicenseAsync returns a result. It never throws for the ordinary “not licensed”
case: when no valid license can be obtained (for example, the key is unknown or activation
was refused), IsSuccess is false and Value is null. Check the result, then
IsOperational.
When activation fails
Section titled “When activation fails”A failed result says why: a revoked or unknown key, a refused activation, a network error.
ErrorMessage is the text for a person; when the server refused, ErrorCode and
ErrorCodeName identify the refusal for your code:
var access = await session.AccessLicenseAsync();if (!access.IsSuccess){ ShowActivationError(access.ErrorMessage ?? "Unknown error");}Each call returns its own reason, so two calls running at once never overwrite each other’s.
Use it to show the user something actionable instead of a generic “not licensed”.
service.unavailable is temporary: nothing was activated, so try again shortly.
When the activation needs something from the user
Section titled “When the activation needs something from the user”When the activation was refused because something was missing, Requires says what, so
your application can ask for it and activate again. The values are in
ActivationRequirements; the error codes
page lists them all.
var access = await session.AccessLicenseAsync();if (!access.IsSuccess){ switch (access.Requires) { case ActivationRequirements.SignIn: await SignInAsync(); // then activate again as the signed-in user break; case ActivationRequirements.VerifiedEmail: AskForEmail(); // then activate again with UseActivationEmail(email) break; case ActivationRequirements.HardwareKey: ShowActivationError("Plug in your YubiKey and try again."); break; default: ShowActivationError(access.ErrorMessage ?? "Unknown error"); break; }}A user without a sign-in only ever sees SignIn or VerifiedEmail; the code name is then
license.authentication_required. See interactive-user activation
and email-verified activation for activating again.
What “operational” means
Section titled “What “operational” means”license.LicenseValidation describes the license without you having to interpret raw
dates:
| Property | Tells you |
|---|---|
IsOperational |
The license currently permits protected use (active, in trial, or within grace). Gate on this. |
LicenseStatus |
Active, GracePeriod, Expired, NotYetValid, or Invalid. NotYetValid means the license starts later: its start date is more than five minutes ahead of the device’s clock. |
LicenseModel |
Trial, Perpetual, or Subscription. |
TrialStatus |
InTrial, TrialExpired, or NotInTrial. |
LeaseStatus |
The offline-freshness signal: Fresh, Stale, StaleLockout, or Unverifiable — how long since the license was last confirmed against the server, and whether the allowed offline window has run out. |
CurrentSession |
The session id — pass it when metering consumption. |
Gate features on IsOperational rather than on LicenseStatus == Active: it already
accounts for trials and the grace window, so a brief
backend outage or a legitimate trial doesn’t lock out a paying customer.
Evaluation licenses
Section titled “Evaluation licenses”While your Oclavex account is on the Evaluation plan, the licenses your app receives are
marked as evaluation licenses and have a short lifetime (7 days); each activation or
refresh renews them. license.LicenseValidation.Property("evaluation") returns "true"
for such a license, so you can show a notice. Once you go live on a paid plan, the next
refresh drops the mark. See Evaluation licenses.
Refresh and release
Section titled “Refresh and release”The SDK checks the lease on the interval you configure (LicenseRefreshIntervalSeconds) and
renews it in the background once it goes Stale. A Fresh lease isn’t renewed, and a
perpetual license’s lease is always Fresh. To force a refresh — for instance right after
a plan change — call RefreshLicenseAsync:
var refreshed = await session.RefreshLicenseAsync();A failed refresh says why and keeps the cached license in place.
When the application shuts down, or a user signs out, release the session so the seat is freed and the final usage is flushed:
var released = await session.ReleaseSessionAsync();if (!released.IsSuccess){ // The seat is still held: retry later, or let the lease lapse on its own.}Releasing never throws into your shutdown path. When the server refuses the release or
can’t be reached, the result is failed and the session stays in place, so a retry still
finds it. In a host-based app the SDK flushes pending usage on shutdown for you; call
ReleaseSessionAsync explicitly when you end a session earlier than process exit.
When the server stops accepting the session
Section titled “When the server stops accepting the session”The server can stop accepting a session: its token no longer validates after a signing-key
change, or the session was deleted. The next session call then gets 401
license.session_token_rejected or 409 license.no_active_session. Consume, preview,
the usage reads, the usage upload, release and the C API’s check-in handle it themselves:
- The SDK activates the license again, once, and retries the call under the new token or session. The new license replaces the stored one.
- At most one re-activation runs per license per
LicenseRefreshIntervalSeconds, however many calls meet the refusal. - A license you released, or haven’t accessed in this process, is never re-activated.
- If the re-activation is refused, the error observer receives a
LicenseSessionRejectedException, and the stored license keeps serving until its own lease ends. The error observer is theILicenseErrorObserveryou set withUseErrorObserver(...)on the builder, or register as a service in a host-based app; C hosts set one withoclavex_config_set_error_callback. - Usage recorded under the old session is uploaded under the new one. If the license isn’t re-activated within an hour, that usage is dropped, and the error observer is told how many records were lost.
To recover by hand, call RefreshLicenseAsync (C API: oclavex_refresh_license).
Interactive-user activation
Section titled “Interactive-user activation”When your application has a signed-in user, you can activate against the
entitlements assigned to that user instead of distributing a license key. On the
fluent builder, call
UseInteractiveUserActivation(); the request then carries the user’s token, and
the activation code becomes optional when the user has exactly one assigned
entitlement. See authentication
for the wire contract and the
end-user portal for how users see what’s
assigned to them.
Email-verified activation
Section titled “Email-verified activation”Entitlements whose activation policy requires identity verification hold the activation
until the user confirms a link sent by email. Supply the address with
UseActivationEmail(...) on the fluent builder; the server emails a one-time confirmation
link and keeps the activation pending (HTTP 409 operation.pending) until it is clicked,
after which the same activation call succeeds. Entitlements without that policy ignore the
address.
Anonymous try activation
Section titled “Anonymous try activation”For an offer open to visitors, UseAnonymousTry(tryCode) on the fluent builder activates
without an account at all. The server answers with this device’s own short-lived
license, issuing one on first contact and returning the same one while it lasts, so a
returning visitor finds the allowance where they left it.
using Revenusion.Oclavex.HttpConnector;using Revenusion.Oclavex.Client.AspNetCore;
var client = OclavexClientFactory.Create( $"https://{tenant}.{host}", new AnonymousAuthentication());
var session = new LicenseClientBuilder() .UseAnonymousTry("your-public-try-code") .UseNodeId(StaticNodeId.Create(deviceId)) .UsePublicKey(base64PublicKey) .UseOclavexHttpClient(client) .BuildSession();A fingerprint is required — supply one with UseNodeId(...). Every builder chain also
needs the pinned provider key: without UsePublicKey(...), BuildSession() throws while
AllowUnsignedLicenses is at its default false
(the provider key is mandatory). The try code is public, so it
names the offer and never the caller; a request that identifies no device is refused. When
the offer’s issuance limits are reached the activation is refused with HTTP 429 and the
failed result carries the detail; tell the visitor to try again later
rather than to sign up.
AccessLicenseAsync is the issuance. BuildSession() builds and sends nothing; the
first AccessLicenseAsync() is the request that issues the device its license. Call
AccessLicenseAsync from the action the visitor takes to start trying — a button, a
“start” step — and not at startup or when a page renders. An application that activates on
load issues a license to every link-preview renderer, monitor and crawler that opens the
application, each renderer a new device with a license of its own, each issuance spending
the limits the offer’s real visitors share. The platform bounds issuance; it does not tell
a crawl from a visit. A bot challenge in front of the action, verified by your application
before the application calls AccessLicenseAsync, keeps the automated share out. See
Try activation.
The license behaves like any other: features, quotas and expiry are the platform’s answers.
Two things differ. The plan an offer issues try licenses on usually denies past its
allowance, so a refusal is the end of the try and the moment to invite a sign-up. And the
license carries a try claim, so an application that reads its own token can tell the two
apart. Changing plan and topping up credits both answer with an invitation to sign up.
Seats and fingerprints
Section titled “Seats and fingerprints”Each activation claims one seat against the entitlement. The SDK identifies the device
with a fingerprint; a stable fingerprint means the
same install reuses its seat across restarts instead of consuming a new one. If the
entitlement is out of seats, activation is refused and AccessLicenseAsync returns a
failed result carrying the refusal — surface that
to the user as “no seats available” rather than a generic error.