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:
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:
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:
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:
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.
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.