SNBS.Licensing.ActivationKeys
1.0.0
Prefix Reserved
See the version list below for details.
dotnet add package SNBS.Licensing.ActivationKeys --version 1.0.0
NuGet\Install-Package SNBS.Licensing.ActivationKeys -Version 1.0.0
<PackageReference Include="SNBS.Licensing.ActivationKeys" Version="1.0.0" />
paket add SNBS.Licensing.ActivationKeys --version 1.0.0
#r "nuget: SNBS.Licensing.ActivationKeys, 1.0.0"
// Install SNBS.Licensing.ActivationKeys as a Cake Addin
#addin nuget:?package=SNBS.Licensing.ActivationKeys&version=1.0.0
// Install SNBS.Licensing.ActivationKeys as a Cake Tool
#tool nuget:?package=SNBS.Licensing.ActivationKeys&version=1.0.0
Licensing library from SNBSLibs
Free. Easy to use. No license files. Everything is XML-documented in the code, so IntelliSense can show you all info about any member.
If you need to know about all aspects of using this library, or you want to test it, consider the branch tests
containing the unit tests created for this library.
Installation
The easiest way to install this library is using NuGet. Right-click on your project name is Visual Studio's Solution Explorer, select option "Manage NuGet packages", find package "Licensing.ActivationKeys" and install it. Or use the Install-Package
command:
Install-Package Licensing.ActivationKeys
You can also clone this repository (or download it using the green "Code" button), compile it and add a reference to the compiled assembly in your project.
Examples of usage
Using LicensingClient
Say, we have an app that isn't completely free, and we want to sell licenses for it and activate it through activation keys.
First, we need a database to store licenses. This library supports MS SQL Server and MySQL. You may use any database hosting from Windows Azure to FreeSQLDatabase (uses MySQL 5.0.12). Not an advertisement. After creating your database will of course be empty, but this library will automatically set it up. Get a connection string and go to the next step.
Then we need to start a
LicensingClient
in the main method. It will decide whether to run the full app version or a message "Not licensed". Please note thatLicensingClient
opens a registry key in the constructor, and thus it needs admin permissions. If they aren't provided, aRegistryAccessException
will be thrown. The inaccessible registry key will be stored in the exception data under keyInaccessibleRegistryKey
.
using SNBS.Licensing;
// ...
public static void Main(string[] args) {
LicensingClient.Start(
"YourConnectionString", "YourProductName", false, null,
client => {
// Start the full version
},
(client, usability) => {
// What you do when the app isn't licensed
}
);
}
Let's analyze this code. Method
Start
is static. In the first parameter, it takes the connection string to your database. Please note that if the connection string provided is invalid, or the database structure is invalid (the valid structure is above), aDatabaseException
will be thrown. In the second parameter you pass the name of your project � it is used to store the license information in the registry (licenses for different products store in different places).The third parameter is of type
bool
. It specifies whether theLicensingClient
should try to connect to MySQL (if it'sfalse
, the client will try to connect to MS SQL Server). If it'strue
, you should also set the fourth parameter (of typeVersion?
) to the version of MySQL. If MS SQL Server is used, this parameter should benull
. If the third parameter istrue
, but the fourth one isnull
, anArgumentException
is thrown.The third parameter has type
Action<LicensingClient>
and is ran when your product has a valid license. TheLicensingClient
instance passed to it can be used to fetch the license, reactivate/deactivate your product and validate activation keys (without using them).The fourth parameter has type
Action<LicensingClient, LicenseUsability>
and is ran where there's no license or an invalid license (configured in the registry for the current product). TheLicensingClient
passed can be used for the same things as described in paragraph 4.LicenseUsability
is an enumeration describing reasons why a license is usable/not usable. Its values are:Usable
,Expired
,NotFound
,TooManyDevices
(each license can be used by a limited number of devices, set when it was created) andNoConfiguredLicense
. They should be intuitive. (The difference betweenNotFound
andNoConfiguredLicense
�NotFound
means a license is configured, but it doesn't exist in the license database.NoConfiguredLicense
means there's no license at all.) Note that the valueNoConfiguredLicense
cannot be returned by any method, exceptGetCurrentLicense()
.
This was the most common usage of the library, but there are other ways, e.g. you can create a LicensingClient
yourself (specify connection string, product name, use MySQL or not and the version of MySQL, as in the previous example):
using (var client = new LicensingClient("YourConnectionString", "YourProductName", false, null)) {
var usability = client.GetCurrentLicense().Usability;
if (usability != LicenseUsability.Usable) {
ShowMessage("Your license " +
(usability == LicenseUsability.Expired) ? "has expired" :
(usability == LicenseUsability.NotFound) ? "was canceled" :
(usability == LicenseUsability.NoConfiguredLicense) ? "configuration was corrupted" :
"was corrupted");
}
}
When you create a LicensingClient
using the constructor, it automatically connects to the licenses database. Method GetCurrentLicense()
retrieves the currently used activation key (stored in the registry) and looks up in the database to verify it. The returned type is structure LicenseInfo
. It should be obvious that it contains detailed information about one license. Its properties are:
Key
of typestring?
;Expiration
of typeDateTime?
(only date is stored,DateTime
instead ofDateOnly
was used because of the Entity Framework's mapping mechanism);Type
of typeLicenseType?
(enumeration containing valuesTrial
,General
,Professional
);Usability
of typeLicenseUsability
(all other properties will benull
if this one isn't equal toLicenseUsability.Usable
).
Applying activation keys
Let's improve the previous example. Generally, applications should ask the end user to activate them if the current license is not usable. The corresponding method of LicensingClient
is called ActivateProduct()
. It returns LicenseInfo
containing the information about the newly activated license (of course, it's activated only if it's usable).
using (var client = new LicensingClient("YourConnectionString", "YourProductName")) {
var usability = client.GetCurrentLicense().Usability;
if (usability != LicenseUsability.Usable) {
ShowMessage("Your license " +
(usability == LicenseUsability.Expired) ? "has expired" :
(usability == LicenseUsability.NotFound) ? "was canceled" :
(usability == LicenseUsability.NoConfiguredLicense) ? "configuration was corrupted" :
"was corrupted");
string key = AskUser("Enter an activation key");
var info = client.ActivateProduct(key);
if (info.Usability == LicenseUsability.Usable) {
ShowMessage("License successfully activated! Expires at " + info.Expiration.ToShortDateString());
} else {
ShowMessage("An error occurred when trying to activate. The license " +
(info.Usability == LicenseUsability.Expired) ? "has expired" :
(info.Usability == LicenseUsability.NotFound) ? "was canceled" :
(info.Usability == LicenseUsability.TooManyDevices) ? "was used by too many devices" :
"was corrupted");
}
}
}
There are other (non-common used) members documented as XML in the code. (See also the unit tests from branch tests
. They are a good documentation.)
Using LicenseValidator
LicenseValidator
can be used to retrieve information (LicenseInfo
) about a license, without trying to apply it on the current device. Its only method is ValidateLicense
(except methods of System.Object
).
The usage isn't complicated.
- Let's validate a license. I will use MySQL here, to show this feature:
using (var validator = new LicenseValidator("Server=sql7.freesqldatabase.com; Database=sql7594998; Uid=sql7594998; Pwd=l2TZZAQ5hB", true,
new Version(5, 0, 12))) {
var info = validator.ValidateLicense("AAAAA-AAAAA-AAAAA-AAAAA-AAAAA");
if (info.Usability == LicenseUsability.Usable) {
ShowMessage("This license is valid");
}
}
If you run the code above, it will connect to my own database hosted on FreeSQLDatabase. Not an advertisement. This service is used because it's free and easy to use. If you have your own database hosted there, replace values in the connection string with the values in email they will send you.
LicenseValidator
doesn't deal with registry, so admin permissions aren't needed.The constructor takes connection string to licenses database, a
bool
value telling whether to use MySQL and the version of MySQL (if it is used), just like theLicensingClient
constructor, but without specifying product name.Method
ValidateLicense
takes a license key in its only argument and returnsLicenseInfo
representing that license.
Using LicensingAdmin
It's good when we can validate and apply licenses, but a class that would perform CRUD (Create, Read, Update, Delete) operations is also needed. It is LicensingAdmin
. Its instances can be created just like LicensingClient
instances, but without specifying product name and without a Start
method.
- Let's create a license.
using (var admin = new LicensingAdmin("YourConnectionString", false, null)) {
var info = admin.CreateLicense(DateTime.Today.AddDays(20), LicenseType.Trial, 1);
ShowMessage("The newly created license is " + info.Key);
}
Analysis. Method
CreateLicense()
receives three parameters. The first one is the type of the needed license (a value of theLicenseType
enumeration). The second one is aDateTime
object representing the expiration date. The third one is the maximum number of devices (short
) that can use the license.The returned object is
LicenseInfo
representing the new license. The most common use in this case is taking the (randomly generated) key of the new license.
Of course, LicensingAdmin
can also update and delete licenses.
using (var admin = new LicensingAdmin("YourConnectionString", false, null)) {
var info = admin.UpdateLicense("AAAAA-AAAAA-AAAAA-AAAAA-AAAAA", null, LicenseType.Professional, 10);
ShowMessage("The license " + info.Key + " is now of type " + info.Type.ToString() + " and can be used by (maximum) " + info.MaxDevices.ToString() + " devices.");
}
Method UpdateLicense
receives four arguments. The first one is key of the license to update.
The second, third and fourth parameters are, correspondingly, DateTime?
(expiration), LicenseType?
(type) and short?
(maximum number of devices using the license). They are the new license parameters. If you want to leave a parameter as it was, pass null
in the corresponding argument.
The returned type is LicenseInfo
that stores updated information about the license.
Let's imagine we no longer need the updated license. It should be deleted:
using (var admin = new LicensingAdmin("YourConnectionString", false, null)) {
var info = admin.DeleteLicense("AAAAA-AAAAA-AAAAA-AAAAA-AAAAA");
ShowMessage("The license " + info.Key + " was deleted.");
}
The only argument is key of the license to delete. The returned type is LicenseInfo
storing information about the deleted license.
Casts
Classes LicensingClient
, LicenseValidator
and LicensingAdmin
deal with the same database, but offer different functions. That's why I've defined explicit casts between them:
using (var admin = new LicensingAdmin("YourConnectionString", false, null)) {
// Use it
var validator = (LicenseValidator)admin;
var info = validator.ValidateLicense("AAAAA-AAAAA-AAAAA-AAAAA-AAAAA");
}
You can convert the mentioned classes to each other however you like, but you cannot convert LicenseValidator
to LicensingClient
and LicensingAdmin
to LicensingClient
(because LicensingClient
needs product name for creation, which cannot be taken from other classes). But you can use LicensingClient
constructors for that:
var admin = new LicensingAdmin("YourConnectionString", false, null);
var client = new LicensingClient(admin, "YourProductName");
The code above will retrieve the connection string and information about usage of MySQL from the LicensingAdmin
instance (you can also pass a LicenseValidator
instance).
Disposing
It is very important to dispose LicensingClient
, LicenseValidator
and LicensingAdmin
after use because the connection to the licenses database is closed only when Dispose()
is called. As the mentioned classes implement IDisposable
, you can use the using
operator instead of calling Dispose()
yourself.
Versions
This is the first version of the library. But I'm still working on it. Everybody using my code is kindly asked to open an issue on this repository if you want a new feature or found a bug! Or fork it and improve yourself!
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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. |
-
net7.0
- Microsoft.EntityFrameworkCore (>= 7.0.2)
- Microsoft.EntityFrameworkCore.SqlServer (>= 7.0.2)
- Pomelo.EntityFrameworkCore.MySql (>= 7.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.