C# License Client
Complete C# implementation for integrating WiLicensor into .NET applications.
Installation
No external dependencies required. Uses built-in System.Net.Http.
Complete Client Class
using System;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using System.Management;
namespace YourApp.Licensing
{
public class LicenseResponse
{
public string Key { get; set; }
public string Condition { get; set; }
public string Type { get; set; }
public string MachineId { get; set; }
public string MachineName { get; set; }
public int ProductId { get; set; }
public string Email { get; set; }
public string Settings { get; set; }
public DateTime? EndAt { get; set; }
public DateTime? ActivatedAt { get; set; }
public string Error { get; set; }
public bool IsValid => Condition == "activated" || Condition == "purchased";
public bool IsExpired => Condition == "expired" || (EndAt.HasValue && EndAt.Value < DateTime.UtcNow);
}
public class LicenseClient
{
private readonly string _baseUrl;
private readonly string _productName;
private readonly HttpClient _httpClient;
public LicenseClient(string baseUrl, string productName)
{
_baseUrl = baseUrl.TrimEnd('/');
_productName = productName;
_httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
}
/// <summary>
/// Check if a license key is valid
/// </summary>
public async Task<LicenseResponse> CheckKeyAsync(string licenseKey)
{
try
{
var url = $"{_baseUrl}/api/check?term={Uri.EscapeDataString(licenseKey)}";
var response = await _httpClient.GetStringAsync(url);
return JsonSerializer.Deserialize<LicenseResponse>(response,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
catch (Exception ex)
{
return new LicenseResponse { Error = ex.Message };
}
}
/// <summary>
/// Find and activate a license with machine binding
/// </summary>
public async Task<LicenseResponse> ActivateLicenseAsync(string email)
{
try
{
var machineId = GetMachineId();
var machineName = Environment.MachineName;
var encryptedKey = EncryptKey.MakePassword(machineId, "358");
var url = $"{_baseUrl}/api/find?" +
$"key={Uri.EscapeDataString(encryptedKey)}" +
$"&email={Uri.EscapeDataString(email)}" +
$"&product={Uri.EscapeDataString(_productName)}" +
$"&machineId={Uri.EscapeDataString(machineId)}" +
$"&machineName={Uri.EscapeDataString(machineName)}";
var response = await _httpClient.GetStringAsync(url);
return JsonSerializer.Deserialize<LicenseResponse>(response,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
catch (Exception ex)
{
return new LicenseResponse { Error = ex.Message };
}
}
/// <summary>
/// Generate or retrieve a trial license
/// </summary>
public async Task<LicenseResponse> GetTrialAsync(string email)
{
try
{
var machineId = GetMachineId();
var machineName = Environment.MachineName;
var url = $"{_baseUrl}/api/gen?" +
$"product={Uri.EscapeDataString(_productName)}" +
$"&machineId={Uri.EscapeDataString(machineId)}" +
$"&machineName={Uri.EscapeDataString(machineName)}" +
$"&email={Uri.EscapeDataString(email)}";
var response = await _httpClient.GetStringAsync(url);
return JsonSerializer.Deserialize<LicenseResponse>(response,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
catch (Exception ex)
{
return new LicenseResponse { Error = ex.Message };
}
}
/// <summary>
/// Transfer license to a new machine
/// </summary>
public async Task<LicenseResponse> TransferLicenseAsync(string email, string oldMachineId)
{
try
{
var newMachineId = GetMachineId();
var machineName = Environment.MachineName;
var newEncryptedKey = EncryptKey.MakePassword(newMachineId, "358");
var url = $"{_baseUrl}/api/replace?" +
$"key={Uri.EscapeDataString(newEncryptedKey)}" +
$"&email={Uri.EscapeDataString(email)}" +
$"&product={Uri.EscapeDataString(_productName)}" +
$"&machineIdOld={Uri.EscapeDataString(oldMachineId)}" +
$"&machineIdNew={Uri.EscapeDataString(newMachineId)}" +
$"&machineName={Uri.EscapeDataString(machineName)}";
var response = await _httpClient.GetStringAsync(url);
return JsonSerializer.Deserialize<LicenseResponse>(response,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
catch (Exception ex)
{
return new LicenseResponse { Error = ex.Message };
}
}
/// <summary>
/// Get unique machine identifier
/// </summary>
public static string GetMachineId()
{
try
{
using (var searcher = new ManagementObjectSearcher("SELECT SerialNumber FROM Win32_BaseBoard"))
{
foreach (var obj in searcher.Get())
{
return obj["SerialNumber"]?.ToString() ?? "";
}
}
}
catch { }
// Fallback to volume serial
try
{
using (var searcher = new ManagementObjectSearcher("SELECT VolumeSerialNumber FROM Win32_LogicalDisk WHERE DeviceID='C:'"))
{
foreach (var obj in searcher.Get())
{
return obj["VolumeSerialNumber"]?.ToString() ?? "";
}
}
}
catch { }
return Environment.MachineName;
}
}
/// <summary>
/// Key encryption algorithm - must match server implementation
/// </summary>
public static class EncryptKey
{
public static string MakePassword(string st, string identifier)
{
if (identifier.Length != 3)
throw new ArgumentException("Identifier must be 3 characters long");
int[] num = {
int.Parse(identifier[0].ToString()),
int.Parse(identifier[1].ToString()),
int.Parse(identifier[2].ToString())
};
st = Boring(st);
st = InverseByBase(st, num[0]);
st = InverseByBase(st, num[1]);
st = InverseByBase(st, num[2]);
var sb = new System.Text.StringBuilder();
foreach (char ch in st)
{
sb.Append(ChangeChar(ch, num));
}
return sb.ToString();
}
private static string InverseByBase(string st, int moveBase)
{
if (moveBase == 0) moveBase = 1;
var sb = new System.Text.StringBuilder();
for (int i = 0; i < st.Length; i += moveBase)
{
int c = Math.Min(moveBase, st.Length - i);
sb.Append(InverseString(st.Substring(i, c)));
}
return sb.ToString();
}
private static string InverseString(string st)
{
char[] arr = st.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
private static string Boring(string st)
{
var chars = st.ToCharArray();
for (int i = 0; i < chars.Length; i++)
{
int newPlace = i * (int)chars[i];
newPlace = newPlace % chars.Length;
char ch = chars[i];
var list = new System.Collections.Generic.List<char>(chars);
list.RemoveAt(i);
list.Insert(newPlace, ch);
chars = list.ToArray();
}
return new string(chars);
}
private static char ChangeChar(char ch, int[] enCode)
{
ch = char.ToUpper(ch);
int chValue = (int)ch;
if (ch >= 'A' && ch <= 'H')
return (char)(chValue + 2 * enCode[0]);
else if (ch >= 'I' && ch <= 'P')
return (char)(chValue - enCode[2]);
else if (ch >= 'Q' && ch <= 'Z')
return (char)(chValue - enCode[1]);
else if (ch >= '0' && ch <= '4')
return (char)(chValue + 5);
else if (ch >= '5' && ch <= '9')
return (char)(chValue - 5);
else
return '0';
}
}
}
Usage Examples
Check License at Startup
var client = new LicenseClient("https://license.yourserver.com", "YourProduct");
// Check existing license
var result = await client.CheckKeyAsync(savedLicenseKey);
if (result.IsValid)
{
Console.WriteLine($"License valid until: {result.EndAt}");
}
else if (result.IsExpired)
{
Console.WriteLine("License has expired. Please renew.");
}
else
{
Console.WriteLine($"License error: {result.Error ?? result.Condition}");
}
Activate License
var client = new LicenseClient("https://license.yourserver.com", "YourProduct");
var result = await client.ActivateLicenseAsync("user@example.com");
if (result.IsValid)
{
// Save license key for future checks
SaveLicenseKey(result.Key);
Console.WriteLine($"License activated! Type: {result.Type}");
}
else
{
Console.WriteLine($"Activation failed: {result.Error}");
}
Request Trial License
var client = new LicenseClient("https://license.yourserver.com", "YourProduct");
var result = await client.GetTrialAsync("user@example.com");
if (result.IsValid)
{
Console.WriteLine($"Trial started! Expires: {result.EndAt}");
}
NinjaTrader Integration
public class MyStrategy : Strategy
{
private LicenseClient _licenseClient;
private bool _isLicensed;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Name = "MyStrategy";
}
else if (State == State.Configure)
{
_licenseClient = new LicenseClient(
"https://license.yourserver.com",
"MyStrategy"
);
}
else if (State == State.DataLoaded)
{
// Check license asynchronously
Task.Run(async () =>
{
var result = await _licenseClient.ActivateLicenseAsync("user@email.com");
_isLicensed = result.IsValid;
if (!_isLicensed)
{
Print($"License validation failed: {result.Error ?? result.Condition}");
}
}).Wait();
}
}
protected override void OnBarUpdate()
{
if (!_isLicensed)
{
return; // Skip if not licensed
}
// Your strategy logic here
}
}
Parsing Settings
The settings field contains custom key-value pairs:
public static Dictionary<string, string> ParseSettings(string settings)
{
var result = new Dictionary<string, string>();
if (string.IsNullOrEmpty(settings)) return result;
// Format: "key1": "value1", "key2": "value2"
var regex = new System.Text.RegularExpressions.Regex(
"\"([^\"]+)\"\\s*:\\s*\"([^\"]*)\""
);
foreach (System.Text.RegularExpressions.Match match in regex.Matches(settings))
{
result[match.Groups[1].Value] = match.Groups[2].Value;
}
return result;
}
// Usage
var settings = ParseSettings(result.Settings);
if (settings.TryGetValue("nextSync", out var syncDays))
{
Console.WriteLine($"Sync every {syncDays} days");
}