Skip to content
Howard van Rooijen By Howard van Rooijen Co-Founder
Endjin.Licensing - Part 4: How to implement custom validation logic

We've open sourced a lightweight licensing framework we've been using internally over the last couple of years. In a 5 part series I'm covering the motivation behind building it, how you can use it, how you can extend it for your own scenarios and how you could use it in a real world situation:

In the last part I covered off how to create and validate a license, but we didn't delve into the extensibility points provided by ILicenseValidationRule and LicenseViolationException that allow us to implement custom validation logic. These extensibility points are enabled by LicenseValidator which performs the validation by iterating over the collection of user definable rules, which implement the ILicenseValidationRule interface and calls the Validate() method, passing in the LicenseCriteria extracted from the ClientLicense object:

public void Validate(IClientLicense clientLicense, ICryptoKey publicKey, IEnumerable<ILicenseValidationRule> validationRules)
{
    if (!LicenseSignatureValidator.ValidateSignature(clientLicense, publicKey))
    {
        throw new InvalidLicenseException(clientLicense);
    }

    this.LicenseCriteria = this.licenseCriteriaParser.Parse(clientLicense);

    validationRules.ForEachFailEnd(x => x.Validate(this.LicenseCriteria));
}

Because we have not specified any hardcoded validation rules inside the ValidateMethod(), this allows us to easily create our own rules and pass them in to be evaluated. Endjin.Licensing only has a single built in validation rule – LicenseHasNotExpiredRule, which simply checks to see if the license expiry date is less than the current date. Of course on a desktop application the user could modify the machine's system clock settings, so you'd need to implement a NTP based rule which would connect to an external time server to establish the correct, untampered with date.

The Introduction to Rx.NET 2nd Edition (2024) Book, by Ian Griffiths & Lee Campbell, is now available to download for FREE.

In the example included in the Endjin.Licensing solution, we have an application that we want to license by number of processor cores. When creating the license in ServerApp, we need to specify a custom metadata entry to capture the number of processors the license supports:

var licenseCriteria = new LicenseCriteria
{
    ExpirationDate = DateTimeOffset.UtcNow.LastDayOfMonth().EndOfDay(),
    IssueDate = DateTimeOffset.UtcNow,
    Id = Guid.NewGuid(),
    MetaData = new Dictionary<string, string> { { "LicensedCores", "2" } },
    Type = "Subscription"
};

To enforce this requirement, we need to implement a custom ILicenseValidationRule which checks the number of cores allowed from the license metadata and validate it against the number of cores on the client's machine:

public class ValidNumberOfCoresLicenseRule : ILicenseValidationRule
{
    public void Validate(LicenseCriteria licenseCriteria)
    {
        int licensedCores = 0;

        if (licenseCriteria.MetaData.ContainsKey("LicensedCores"))
        {
            licensedCores = Convert.ToInt32(licenseCriteria.MetaData["LicensedCores"]);
        }

        if (Environment.ProcessorCount > licensedCores)
        {
            string message = string.Format("This license is only valid for {0} cores.", licensedCores);

            throw new LicensedCoresExceededException(message, Environment.ProcessorCount)
            {
                LicenseCriteria = licenseCriteria
            };
        }
    }
}

The diagram below shows the ILicenseValidationRule inheritance hierarchy in the solution:

validation rules

The second part of the extensibility mechanism is option to implement your own custom LicenseViolationException. For simple implementations, your custom exception can contain a user friendly message explaining in what ways the license is invalid which you can display in your user interface.

public class LicensedCoresExceededException : LicenseViolationException
{
    public LicensedCoresExceededException(int actualCoreCount)
    {
        this.ActualCoreCount = actualCoreCount;
    }

    public LicensedCoresExceededException(string message, int actualCoreCount) : base(message)
    {
        this.ActualCoreCount = actualCoreCount;
    }

    public int ActualCoreCount { get; set; }
}

The diagram below shows the LicenseViolationException inheritance hierarchy in the solution:

exceptions

Hopefully post has demonstrated how easy it is to implement custom validation rules in Endjin.Licensing. In the next post I'll be describing some real world usage scenarios of how you could use the Endjin.Licensing framework.

@HowardvRooijen

Programming C# 12 Book, by Ian Griffiths, published by O'Reilly Media, is now available to buy.

Sign up to Azure Weekly to receive Azure related news and articles direct to your inbox every Monday, or follow @azureweekly on Twitter.

Howard van Rooijen

Co-Founder

Howard van Rooijen

Howard spent 10 years as a technology consultant helping some of the UK's best known organisations work smarter, before founding endjin in 2010. He's a Microsoft ScaleUp Mentor, and a Microsoft MVP for Azure and Developer Technologies, and helps small teams achieve big things using data, AI and Microsoft Azure.