Files
wc-licensed-product/docs/client-examples/csharp-client.cs
magdev d3830e24b9 Implement version 0.0.9 features
- Add API client examples for PHP, Python, JavaScript, curl, and C#
- Create comprehensive REST API documentation in docs/client-examples/
- All examples include rate limit handling (HTTP 429)
- Examples cover validate, status, and activate endpoints

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 21:23:21 +01:00

353 lines
11 KiB
C#

/**
* WC Licensed Product API Client for C#
*
* A C# client for interacting with the WC Licensed Product REST API.
*
* Requirements:
* - .NET 6.0+ or .NET Framework 4.7.2+
* - System.Net.Http
* - System.Text.Json (or Newtonsoft.Json)
*
* Usage:
* var client = new WcLicensedProductClient("https://your-site.com");
* var result = await client.ValidateAsync("XXXX-XXXX-XXXX-XXXX", "example.com");
*/
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace WcLicensedProduct
{
/// <summary>
/// License status response data
/// </summary>
public class LicenseStatus
{
[JsonPropertyName("valid")]
public bool Valid { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("domain")]
public string Domain { get; set; }
[JsonPropertyName("expires_at")]
public string ExpiresAt { get; set; }
[JsonPropertyName("activations_count")]
public int ActivationsCount { get; set; }
[JsonPropertyName("max_activations")]
public int MaxActivations { get; set; }
}
/// <summary>
/// Validation response data
/// </summary>
public class ValidationResult
{
[JsonPropertyName("valid")]
public bool Valid { get; set; }
[JsonPropertyName("error")]
public string Error { get; set; }
[JsonPropertyName("message")]
public string Message { get; set; }
[JsonPropertyName("license")]
public LicenseInfo License { get; set; }
}
/// <summary>
/// License information in validation response
/// </summary>
public class LicenseInfo
{
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("domain")]
public string Domain { get; set; }
[JsonPropertyName("expires_at")]
public string ExpiresAt { get; set; }
[JsonPropertyName("product_id")]
public int ProductId { get; set; }
}
/// <summary>
/// Activation response data
/// </summary>
public class ActivationResult
{
[JsonPropertyName("success")]
public bool Success { get; set; }
[JsonPropertyName("error")]
public string Error { get; set; }
[JsonPropertyName("message")]
public string Message { get; set; }
}
/// <summary>
/// Exception for API errors
/// </summary>
public class WcLicensedProductException : Exception
{
public string ErrorCode { get; }
public int HttpCode { get; }
public WcLicensedProductException(string message, string errorCode = null, int httpCode = 0)
: base(message)
{
ErrorCode = errorCode;
HttpCode = httpCode;
}
}
/// <summary>
/// Exception for rate limit errors
/// </summary>
public class RateLimitException : WcLicensedProductException
{
public int RetryAfter { get; }
public RateLimitException(int retryAfter)
: base($"Rate limit exceeded. Retry after {retryAfter} seconds.")
{
RetryAfter = retryAfter;
}
}
/// <summary>
/// Client for the WC Licensed Product REST API
/// </summary>
public class WcLicensedProductClient : IDisposable
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl;
private readonly JsonSerializerOptions _jsonOptions;
/// <summary>
/// Initialize the client
/// </summary>
/// <param name="siteUrl">Your WordPress site URL (e.g., "https://example.com")</param>
/// <param name="timeout">Request timeout (default: 30 seconds)</param>
public WcLicensedProductClient(string siteUrl, TimeSpan? timeout = null)
{
_baseUrl = siteUrl.TrimEnd('/') + "/wp-json/wc-licensed-product/v1";
_httpClient = new HttpClient
{
Timeout = timeout ?? TimeSpan.FromSeconds(30)
};
_httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
_jsonOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
}
/// <summary>
/// Validate a license key for a specific domain
/// </summary>
/// <param name="licenseKey">The license key to validate</param>
/// <param name="domain">The domain to validate against</param>
/// <returns>Validation result</returns>
public async Task<ValidationResult> ValidateAsync(string licenseKey, string domain)
{
var data = new { license_key = licenseKey, domain = domain };
return await RequestAsync<ValidationResult>("/validate", data);
}
/// <summary>
/// Get the status of a license
/// </summary>
/// <param name="licenseKey">The license key to check</param>
/// <returns>License status</returns>
public async Task<LicenseStatus> StatusAsync(string licenseKey)
{
var data = new { license_key = licenseKey };
return await RequestAsync<LicenseStatus>("/status", data);
}
/// <summary>
/// Activate a license on a domain
/// </summary>
/// <param name="licenseKey">The license key to activate</param>
/// <param name="domain">The domain to activate on</param>
/// <returns>Activation result</returns>
public async Task<ActivationResult> ActivateAsync(string licenseKey, string domain)
{
var data = new { license_key = licenseKey, domain = domain };
return await RequestAsync<ActivationResult>("/activate", data);
}
/// <summary>
/// Make an API request
/// </summary>
private async Task<T> RequestAsync<T>(string endpoint, object data)
{
var url = _baseUrl + endpoint;
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage response;
try
{
response = await _httpClient.PostAsync(url, content);
}
catch (TaskCanceledException)
{
throw new WcLicensedProductException("Request timeout");
}
catch (HttpRequestException ex)
{
throw new WcLicensedProductException($"Request failed: {ex.Message}");
}
// Handle rate limiting
if ((int)response.StatusCode == 429)
{
var retryAfter = 60;
if (response.Headers.TryGetValues("Retry-After", out var values))
{
int.TryParse(string.Join("", values), out retryAfter);
}
throw new RateLimitException(retryAfter);
}
var responseBody = await response.Content.ReadAsStringAsync();
T result;
try
{
result = JsonSerializer.Deserialize<T>(responseBody, _jsonOptions);
}
catch (JsonException)
{
throw new WcLicensedProductException("Invalid JSON response");
}
// Check for API errors (for error responses)
if (!response.IsSuccessStatusCode)
{
var errorResult = JsonSerializer.Deserialize<ValidationResult>(responseBody, _jsonOptions);
if (errorResult?.Error != null)
{
throw new WcLicensedProductException(
errorResult.Message ?? "Unknown error",
errorResult.Error,
(int)response.StatusCode
);
}
}
return result;
}
public void Dispose()
{
_httpClient?.Dispose();
}
}
// =========================================================================
// Usage Examples
// =========================================================================
public class Program
{
public static async Task Main(string[] args)
{
using var client = new WcLicensedProductClient("https://your-wordpress-site.com");
// Example 1: Validate a license
Console.WriteLine("=== Validate License ===");
try
{
var result = await client.ValidateAsync("XXXX-XXXX-XXXX-XXXX", "myapp.example.com");
if (result.Valid)
{
Console.WriteLine("License is valid!");
Console.WriteLine($"Status: {result.License?.Status ?? "active"}");
Console.WriteLine($"Expires: {result.License?.ExpiresAt ?? "Never"}");
}
else
{
Console.WriteLine($"License is not valid: {result.Message ?? "Unknown error"}");
}
}
catch (RateLimitException ex)
{
Console.WriteLine($"Rate limited. Retry after {ex.RetryAfter} seconds.");
}
catch (WcLicensedProductException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
Console.WriteLine();
// Example 2: Check license status
Console.WriteLine("=== Check License Status ===");
try
{
var status = await client.StatusAsync("XXXX-XXXX-XXXX-XXXX");
Console.WriteLine($"Valid: {(status.Valid ? "Yes" : "No")}");
Console.WriteLine($"Status: {status.Status ?? "unknown"}");
Console.WriteLine($"Domain: {status.Domain ?? "None"}");
Console.WriteLine($"Expires: {status.ExpiresAt ?? "Never"}");
Console.WriteLine($"Activations: {status.ActivationsCount}/{status.MaxActivations}");
}
catch (RateLimitException ex)
{
Console.WriteLine($"Rate limited. Retry after {ex.RetryAfter} seconds.");
}
catch (WcLicensedProductException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
Console.WriteLine();
// Example 3: Activate license on a domain
Console.WriteLine("=== Activate License ===");
try
{
var result = await client.ActivateAsync("XXXX-XXXX-XXXX-XXXX", "newsite.example.com");
if (result.Success)
{
Console.WriteLine("License activated successfully!");
}
else
{
Console.WriteLine($"Activation failed: {result.Message ?? "Unknown error"}");
}
}
catch (RateLimitException ex)
{
Console.WriteLine($"Rate limited. Retry after {ex.RetryAfter} seconds.");
}
catch (WcLicensedProductException ex)
{
Console.WriteLine($"Error ({ex.ErrorCode}): {ex.Message}");
}
}
}
}