Protect ASP.NET application using "Unlock Key with Activation" licensing schema
Sample written in C#
Sample written in Visual Basic .NET

License protection of the ASP.NET application is quite similar to the process for desktop .NET applications if ASP.NET application is used in the Full Trust environment. In this section we suppose that your application will be executed in the Full Trust environment. If you are suppose to use your product in Medium Trust environment then we suggest you to take a look to another document: “Protect ASP.NET application with Unlock Key licensing schema in Medium Trust environment”.

We will show how the “Unlock Key with Activation” licensing schema can be used for ASP.NET application in the Full Trust environment. We also will show how the User Data encrypted to the Unlock Key can be used to limit number of the concurrent sessions. We suppose that you have read “Quick Start” and “Using of the online product activation” sections in our documentation, because this document describes differences for this approach. You can download “Protect Web-based (ASP.NET) application using ‘Unlock Key with Activation’ licensing schema” sample ASP.NET application from our site at the http://www.mancosoftware.com/licensing/download.htm in section “Samples”.

First of all you have to create your web product as regular ASP.NET application (not as a plain web-site). It means that code-behind of your application should be compiled to the regular .NET assembly.

Very often ASPNET user account (default account for ASP.NET applications) has no access to the Windows Registry. We recommend you to use “Isolated Storage” as protected storage for ASP.NET products:

License Manager - Version node for ASP.NET application

We suppose store number of the concurrent sessions allowed in the “Unlock Key” as user data. You should change Unlock Key format to allow it. Include format character U with max length of the user data (3, for example) to the format string. Correspondent format qualifier will looks like following: {U3}. You can put it at any place in the format string:

License Manager - Unlock Key format with User Data

If protected class already exists in your application then you must regenerate “ILicenseKeyProvider” code and replace it. If it is not then you have to create license protected class in your application. Take a look to the “MyAppLicense” class in our sample application. It demonstrates how this class can looks like. The main difference with desktop applications is that you should assign HttpServerUtility object to the “HttpServer” property of the license object. It is used to perform specific web-based validations. The code of the protected class constructor can looks like the following:

[C#]
/// <summary>
/// License object
/// </summary>
private static Manco.Licensing.License license = null;

/// <summary>
/// Is used to perwork web-specific validations
/// </summary>
private HttpServerUtility m_oHttpServer;

/// <summary>
/// Constructor
/// </summary>
public MyAppLicense(HttpServerUtility aoHttpServer)
{
	m_oHttpServer = aoHttpServer;

	if (license == null)
	{
		try
		{
			license = (Manco.Licensing.License)LicenseManager.Validate(typeof(MyAppLicense), this);
			license.CallingAssembly = System.Reflection.Assembly.GetCallingAssembly();
			license.LicensedAssembly = this.GetType().Assembly;
			license.HttpServer = aoHttpServer;
		}
		catch (FileNotFoundException ex)
		{
			// License file not found
			throw new Exception(String.Format("License file was not found!", ex.FileName));
		}
	}
}
    
[Visual Basic]
''' <summary>
''' License object
''' </summary>
Private Shared license As Manco.Licensing.License = Nothing

''' <summary>
''' Is used for web-specific validations
''' </summary>
Private m_oHttpServer As HttpServerUtility

''' <summary>
''' Constructor
''' </summary>
Public Sub New(ByVal aoHttpServer As HttpServerUtility)
	m_oHttpServer = aoHttpServer

	If license Is Nothing Then
		Try
			license = LicenseManager.Validate(GetType(MyAppLicense), Me)
			license.CallingAssembly = System.Reflection.Assembly.GetCallingAssembly()
			license.LicensedAssembly = Me.GetType().Assembly
			license.HttpServer = aoHttpServer
		Catch ex As IO.FileNotFoundException
			' License file not found
			Throw New Exception(String.Format("License file was not found!", ex.FileName))
		End Try
	End If
End Sub
    

We recommend you to have only one static (Shared in VB) instance of the license protected class in your application. It will decrease time necessary to load and validate license. It is reasonable to have this instance in the Global class (Global.asax.cs or Global.asax.vb) and create protected object when ASP.NET application starts (in the “Application_Start” method). The application start code in the Global class can looks like the following:

[C#]
/// <summary>
/// Number of active sessions
/// </summary>
private static int m_iSessionsCounter = 0;

/// <summary>
/// License object
/// </summary>
private static MyAppLicense m_oLicense = null;

protected void Application_Start(object sender, EventArgs e)
{
	// Clear session counter
	m_iSessionsCounter = 0;

	// Create instance of the license protected class 
	try
	{
		// Create m_oLicense object
		if (m_oLicense == null)
		{
			m_oLicense = new MyAppLicense(this.Server);

			// Set m_oLicense object to the application state 
			// to be able get it and use from other pages
			this.Application["License"] = m_oLicense;
		}

		// If m_oLicense have been expired 
		// or is in evaluation mode or isn't valid for some reasons
		// then ask user enter m_oLicense keys
		if (m_oLicense.IsExpired
			|| m_oLicense.IsEvaluation
			|| !m_oLicense.IsValid)
		{
			HttpContext.Current.Response.Redirect("ActivateLicense.aspx");
		}
	}
	catch (Exception ex)
	{
		// You can write exception to the log file 
		// or use any other technique to inform customer
		// about problem. 

		// Redirect to the page to inform about license loading problems
		HttpContext.Current.Response.Redirect("InvalidLicense.htm");
	}
}
    
[Visual Basic]
''' <summary>
''' Number of active sessions
''' </summary>
Private Shared m_iSessionsCounter As Integer = 0

''' <summary>
''' License object
''' </summary>
Private Shared m_oLicense As MyAppLicense = Nothing

Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
	' Clear session counter
	m_iSessionsCounter = 0

	' Load m_oLicense 
	Try
		' Create instance of the license protected class
		If m_oLicense Is Nothing Then
			m_oLicense = New MyAppLicense(Me.Server)

			' Set m_oLicense object to the application state 
			' to be able get it and use from other pages
			Me.Application("License") = m_oLicense
		End If

		' If m_oLicense have been expired 
		' or is in evaluation mode or isn't valid for some reasons
		' then ask user enter m_oLicense keys
		If m_oLicense.IsExpired Or m_oLicense.IsEvaluation Or Not m_oLicense.IsValid Then
			HttpContext.Current.Response.Redirect("ActivateLicense.aspx")
		End If
	Catch ex As Exception
		' You can write exception to the log file 
		' or use any other technique to inform customer
		' about problem. 

		' Redirect to the page to inform about license loading problems
		HttpContext.Current.Response.Redirect("InvalidLicense.htm")
	End Try
End Sub
    

Now you should add code that will count number of the concurrent sessions and compare it with value stored in the Unlock Key. Add new property to your protected class that will read user data encrypted to the Unlock Key and convert it to the integer value:

[C#]
/// <summary>
/// Number of the concurrent sessions allowed
/// </summary>
public int NumberOfSessionsAllowed
{
	get
	{
		if (string.IsNullOrEmpty(license.UserData))
		{
			// User data have not been included to license
			// or have not been read for some reason.
			// Number of the concurrent sessions is 1.
			return 1;
		}
		else
		{
			// Try to convert user data to integer.
			// Return 1 if it is not possible.
			return ResourceLoader.GetInteger(license.UserData.Trim(), 1);
		}
	}
}
    
[Visual Basic]
''' <summary>
''' Number of the concurrent sessions allowed
''' </summary>
Public ReadOnly Property NumberOfSessionsAllowed() As Integer
	Get
		If String.IsNullOrEmpty(license.UserData) Then
			' User data have not been included to license
			' or have not been read for some reason.
			' Number of the concurrent sessions is 1.
			Return 1
		Else
			' Try to convert user data to integer.
			' Return 1 if it is not possible.
			Return ResourceLoader.GetInteger(license.UserData.Trim(), 1)
		End If
	End Get
End Property
    

Note: pay attention, that “UserData” property of the license object contains data in case of the successful Unlock Key verification only. So the “NumberOfSessionsAllowed” property can be used after license validation only.

The best (and looks like single) place where you can count number of sessions started is session started event handler in the Global class. Don’t forget decrease number of session started in the session end event handler:

[C#]
protected void Session_Start(object sender, EventArgs e)
{
	// Check that license is valid
	if (m_oLicense.IsExpired || !m_oLicense.IsValid)
	{
		// If license have been expired or is not valid
		// Then we shouldn't allow session start
		// Throw exception
		throw new Exception("Illegal use of	this application: no valid License found");
	}

	// Check if there are enough licenses
	bool notEnoughLicensesAvailable = (m_iSessionsCounter >= m_oLicense.NumberOfSessionsAllowed);

	// Increase number of session started
	m_iSessionsCounter++;

	if (notEnoughLicensesAvailable)
	{
		// If not: redirect the user to a special page
		Session.Abandon();
		Response.Redirect("NoMoreCALs.htm");
	}
}

protected void Session_End(object sender, EventArgs e)
{
	// Decrease number of session
	m_iSessionsCounter--;
}
    
[Visual Basic]
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
	' Check that license is valid
	If m_oLicense.IsExpired Or Not m_oLicense.IsValid Then
		' If license have been expired or is not valid
		' Then we shouldn't allow session start
		' Throw exception
		Throw New Exception("Illegal use of	this application: no valid License found")
	End If

	' Check if there are enough licenses
	Dim notEnoughLicensesAvailable As Boolean = (m_iSessionsCounter > m_oLicense.NumberOfSessionsAllowed)

	' Increase number of session started
	m_iSessionsCounter += 1

	If notEnoughLicensesAvailable Then
		' If not: redirect the user to a special page
		Session.Abandon()
		Response.Redirect("NoMoreCALs.htm")
	End If
End Sub

Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
	' Decrease number of session
	m_iSessionsCounter -= 1
End Sub
    

Now you should create license type that uses “Unlock Key with Activation” licensing schema and allows entering of the customer specific User Data. This license type can look like following:

License Manager - License type with user data
  1. Is Evaluation – indicates that license works as evaluation till Activation and Unlock Key will be entered.
  2. Expiration Days – sets number of day till evaluation license expire.
  3. Unlock Key – indicates that unlock key for this product issued by License Manager should be entered to get product fully functional.
  4. Activation Key – indicates that activation key created using PC system info and unlock key (ether in automatic or manual mode) should be entered to get product fully functional. Activation Key bound license to the server hardware.
  5. User Data – indicates that user data should be included to the Unlock Key. This data will contain number of concurrent sessions allowed.
  6. Key To File – indicates that important license information (unlock and activation keys) should be stored in the license protected storage to reuse in future.

Then you should create evaluation license file using this license type. Evaluation license file shouldn’t contain any Unlock Key, Activation Key or User Data. Correspondent sale record could looks like the following:

License Manager - Evaluation sale with user data

Pay attention that both: “Unlock Key”, “Activation Key” and “User Data” fields are empty, “Write Key To File” checkbox is checked.

When customer buys your software you create new purchase under this license type, enter number of the concurrent sessions allowed to the “User Data” field, and generate Unlock Key.

License Manager - Sale window with user data

Pay attention that number “5” has been entered in the “User Data” field to specify number of the concurrent sessions allowed. User data MUST be specified BEFORE Unlock Key will be generated.


Sample written in C#
Sample written in Visual Basic .NET
Manco .NET Licensing System Home Page