Your .NET application runs on Windows, Mac, and Linux. How do you protect it with license keys that work everywhere?
This guide shows you how to implement cross-platform licensing for .NET applications with Quick License Manager, covering Windows, macOS, Linux, iOS, and Android.
Recommended solution: Quick License Manager Enterprise - the only complete cross-platform licensing solution for .NET ($999/year).
The Cross-Platform Challenge
Platforms you need to support:
- ✅ Windows (.NET Framework, .NET 6/7/8/9/10)
- ✅ macOS (.NET 6/7/8/9/10, Xamarin.Mac)
- ✅ Linux (.NET 6/7/8/9/10)
- ✅ iOS (Xamarin, .NET MAUI)
- ✅ Android (Xamarin, .NET MAUI)
What doesn't work cross-platform:
- ❌ Windows-specific APIs (Registry, WMI)
- ❌ Platform-specific UI frameworks
- ❌ Hardware identifiers (different per OS)
- ❌ Most licensing solutions (Windows only)
What you need:
- Unified licensing API across all platforms
- Platform-specific hardware binding
- Online and offline activation
- Single license server for all platforms
Quick License Manager Enterprise: Cross-Platform Solution
QLM Enterprise supports all major platforms:
Platforms:
- ✅ Windows: .NET Framework 2.0-4.8, .NET Core, .NET 6/7/8/9/10
- ✅ macOS: .NET 6/7/8/9/10, Xamarin.Mac
- ✅ Linux: .NET 6/7/8/9/10
- ✅ iOS: Xamarin.iOS, .NET MAUI
- ✅ Android: Xamarin.Android, .NET MAUI
- ✅ Web: ASP.NET, ASP.NET Core, Blazor
Pricing: $999/year per developer/administrator (cross-platform)
Why QLM Enterprise:
- Same API across all platforms
- Single license server
- Unified customer database
- Platform-specific libraries included
- Source code provided for mobile
Pricing: QLM Pricing
Cross-Platform Architecture
Windows Implementation
using QLM.LicenseLib;
public class WindowsLicensing
{
private LicenseValidator lv;
public bool ValidateLicense()
{
lv = new LicenseValidator("settings.xml");
bool needsActivation = false;
string errorMsg = string.Empty;
// Windows: Use Computer Name binding
bool isValid = lv.ValidateLicenseAtStartup(
ELicenseBinding.ComputerName,
ref needsActivation,
ref errorMsg
);
if (needsActivation)
{
ShowActivationUI(); // QLM License Wizard
}
return isValid;
}
}
macOS/Linux Implementation
using QlmLicenseLib; // .NET Core library
public class CrossPlatformLicensing
{
private QlmLicense license;
public bool ValidateLicense()
{
license = new QlmLicense();
license.DefineProduct(
productID: 1,
majorVersion: 1,
minorVersion: 0,
licenseType: "permanent",
webServiceUrl: "https://yourserver.com/qlmservice.asmx"
);
// Read stored license key
string computerKey = ReadStoredKey();
if (string.IsNullOrEmpty(computerKey))
{
ShowActivationUI();
return false;
}
// Validate license
string computerID = GetPlatformComputerID();
bool isValid = license.ValidateLicenseAtStartup(
computerKey,
computerID
);
return isValid;
}
private string GetPlatformComputerID()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return Environment.MachineName;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return GetMacSerialNumber();
else // Linux
return GetLinuxMachineID();
}
}
Tutorial: Protect .NET Core Console App
Hardware Binding Strategies
Windows Identifiers
// Computer Name (recommended for enterprise)
string id = Environment.MachineName;
// MAC Address
string id = lv.QlmLicenseObject.GetComputerID();
// Motherboard Serial
string id = lv.QlmLicenseObject.GetMotherboardSerial();
macOS Identifiers
// Hardware UUID (recommended)
public string GetMacSerialNumber()
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "/usr/sbin/system_profiler",
Arguments = "SPHardwareDataType",
RedirectStandardOutput = true,
UseShellExecute = false
}
};
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
// Parse for "Hardware UUID"
var match = Regex.Match(output, @"Hardware UUID: (.+)");
return match.Success ? match.Groups[1].Value.Trim() : "";
}
Linux Identifiers
// Machine ID (recommended)
public string GetLinuxMachineID()
{
try
{
return File.ReadAllText("/etc/machine-id").Trim();
}
catch
{
// Fallback: hostname
return Dns.GetHostName();
}
}
Mobile Identifiers
iOS:
// Use identifierForVendor
string deviceID = UIDevice.CurrentDevice.IdentifierForVendor.AsString();
Android:
// Use Android ID
string deviceID = Android.Provider.Settings.Secure.GetString(
context.ContentResolver,
Android.Provider.Settings.Secure.AndroidId
);
Activation UI: Platform-Specific
Windows: QLM License Wizard
// Use pre-built wizard (Windows only)
public void ShowWindowsActivation()
{
string wizardPath = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"QlmLicenseWizard.exe"
);
lv.QlmLicenseObject.LaunchProcess(
wizardPath,
$"/settings \"{settingsFile}\"",
waitForExit: true,
hiddenProcess: false
);
}
macOS/Linux/Mobile: Custom UI
QLM License Wizard is Windows-only. For other platforms, create your own UI:
public class CustomActivationDialog
{
private QlmLicense license;
public bool ActivateLicense(string activationKey, string email)
{
string computerID = GetPlatformComputerID();
string computerName = GetPlatformComputerName();
string response;
bool success = license.ActivateLicense(
webServiceUrl: license.WebServiceUrl,
activationKey: activationKey,
computerID: computerID,
computerName: computerName,
qlmVersion: license.QlmVersion,
userData: email,
response: out response
);
if (success)
{
// Parse response to get Computer Key
string computerKey = ParseComputerKey(response);
// Store Computer Key securely
StoreKey(computerKey);
return true;
}
ShowError(response);
return false;
}
}
Storing License Keys: Platform-Specific
Windows
// Option 1: Registry (recommended)
using Microsoft.Win32;
public void StoreKeyWindows(string computerKey)
{
using var key = Registry.CurrentUser.CreateSubKey(@"Software\YourCompany\YourApp");
key.SetValue("LicenseKey", computerKey);
}
// Option 2: AppData folder
string path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"YourCompany", "license.dat"
);
File.WriteAllText(path, computerKey);
macOS
// Use Application Support directory
string path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"YourCompany", "license.dat"
);
File.WriteAllText(path, computerKey);
Linux
// Use ~/.config directory
string path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"yourapp", "license.dat"
);
File.WriteAllText(path, computerKey);
iOS
// Use Keychain
using Foundation;
public void StoreKeyiOS(string computerKey)
{
var record = new SecRecord(SecKind.GenericPassword)
{
Account = "LicenseKey",
Service = "YourApp",
ValueData = NSData.FromString(computerKey, NSStringEncoding.UTF8)
};
SecKeyChain.Add(record);
}
Android
// Use SharedPreferences (encrypted)
using Android.Content;
public void StoreKeyAndroid(string computerKey)
{
var prefs = context.GetSharedPreferences("license", FileCreationMode.Private);
var editor = prefs.Edit();
editor.PutString("key", computerKey);
editor.Apply();
}
Complete Cross-Platform Example
Shared Code (.NET Standard)
// YourApp.Core (shared library)
public interface IPlatformService
{
string GetComputerID();
void StoreKey(string key);
string ReadKey();
}
public class LicenseManager
{
private readonly IPlatformService platform;
private QlmLicense license;
public LicenseManager(IPlatformService platformService)
{
platform = platformService;
license = new QlmLicense();
}
public bool ValidateLicense()
{
string computerKey = platform.ReadKey();
if (string.IsNullOrEmpty(computerKey))
return false;
string computerID = platform.GetComputerID();
return license.ValidateLicenseAtStartup(computerKey, computerID);
}
public bool ActivateLicense(string activationKey)
{
string computerID = platform.GetComputerID();
string response;
bool success = license.ActivateLicense(
"https://yourserver.com/qlmservice.asmx",
activationKey,
computerID,
Environment.MachineName,
license.QlmVersion,
"",
out response
);
if (success)
{
string computerKey = ParseComputerKey(response);
platform.StoreKey(computerKey);
}
return success;
}
}
Windows Implementation
// YourApp.Windows
public class WindowsPlatformService : IPlatformService
{
public string GetComputerID() => Environment.MachineName;
public void StoreKey(string key)
{
using var regKey = Registry.CurrentUser.CreateSubKey(@"Software\YourApp");
regKey.SetValue("License", key);
}
public string ReadKey()
{
using var regKey = Registry.CurrentUser.OpenSubKey(@"Software\YourApp");
return regKey?.GetValue("License") as string;
}
}
macOS/Linux Implementation
// YourApp.Mac / YourApp.Linux
public class UnixPlatformService : IPlatformService
{
public string GetComputerID()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return GetMacHardwareUUID();
else
return File.ReadAllText("/etc/machine-id").Trim();
}
public void StoreKey(string key)
{
string path = GetLicensePath();
Directory.CreateDirectory(Path.GetDirectoryName(path));
File.WriteAllText(path, key);
}
public string ReadKey()
{
string path = GetLicensePath();
return File.Exists(path) ? File.ReadAllText(path) : null;
}
private string GetLicensePath()
{
return Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"yourapp", "license.dat"
);
}
}
Online Validation Across Platforms
public class CrossPlatformOnlineValidation
{
public async Task<bool> ValidateOnlineAsync()
{
try
{
using var client = new HttpClient();
var request = new
{
activationKey = GetStoredActivationKey(),
computerKey = GetStoredComputerKey(),
computerID = platform.GetComputerID()
};
var response = await client.PostAsJsonAsync(
"https://yourserver.com/qlmservice.asmx/ValidateLicenseOnServer",
request
);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
return result.Contains("\"result\":\"true\"");
}
return false;
}
catch
{
// Offline - allow grace period
return true;
}
}
}
Offline Activation: Cross-Platform
Challenge: QLM License Wizard is Windows-only. Other platforms need custom workflow.
Solution: Use QLM Self-Help portal + QR codes
public class OfflineActivation
{
public string GenerateActivationURL(string activationKey)
{
string computerID = platform.GetComputerID();
string baseUrl = "https://yoursite.com/qlmselfhelp/QlmWebActivation.aspx";
return $"{baseUrl}?is_avkey={activationKey}&is_pcid={computerID}";
}
public void ShowOfflineInstructions()
{
string url = GenerateActivationURL(activationKey);
// Generate QR code
var qrGenerator = new QRCodeGenerator();
var qrCode = qrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.M);
// Show to user with instructions
ShowDialog(
"Scan this QR code with your phone to activate offline",
qrCode
);
}
}
Testing Cross-Platform
[TestFixture]
public class CrossPlatformLicensingTests
{
[Test]
[Platform("Win")]
public void TestWindows()
{
var platform = new WindowsPlatformService();
var mgr = new LicenseManager(platform);
Assert.IsTrue(mgr.ActivateLicense("TEST-KEY"));
}
[Test]
[Platform("Linux")]
public void TestLinux()
{
var platform = new UnixPlatformService();
var mgr = new LicenseManager(platform);
Assert.IsTrue(mgr.ActivateLicense("TEST-KEY"));
}
[Test]
[Platform("MacOsX")]
public void TestMac()
{
var platform = new UnixPlatformService();
var mgr = new LicenseManager(platform);
Assert.IsTrue(mgr.ActivateLicense("TEST-KEY"));
}
}
Related Reading
For more advanced licensing topics, check out these articles:
On HashNode:
- Trial License Implementation Patterns in C# - Complete guide to trial licenses with time-limited keys, usage tracking, and conversion strategies
- Software Analytics & Telemetry in C# - Track installs, usage, and conversions across all platforms
Why Quick License Manager Enterprise
QLM Enterprise is the only complete cross-platform licensing solution for .NET:
✅ All platforms: Windows, Mac, Linux, iOS, Android
✅ Unified API: Same code across platforms
✅ Single license server: Manage all platforms
✅ Source code included: Mobile libraries (iOS, Android)
✅ REST API: For non-.NET platforms
✅ Proven: 20+ years, thousands of customers
Pricing: $999/year per developer/administrator
Alternative: Build your own (6-12 months development) or QLM Professional ($699/year, Windows only)
Getting Started
1. Download trial:
QLM Downloads
2. Read tutorials:
3. Contact sales:
support@soraco.co for cross-platform licensing advice
Resources
Building cross-platform .NET apps? Share your licensing challenges in the comments! 👇
Top comments (0)