Licensing

Almost every type of software application includes some type of licensing agreement that governs the rights and uses of the software. In addition to the licensing agreement, a product key may also be required during the installation and setup for the software package. Licensing is used to govern the rights of the user with respect to the use of a product and how that product is deployed, used, and even distributed.

.NET provides a licensing system for components such as the custom controls developed in this book. The licensing system is based on the COM version of licensing providing support for both design-time and runtime licensing for a component. By licensing components, a vendor can govern the use of the component and help ensure that the user of the component has the proper licensing for development and distribution of the component.

Note

For those of you not familiar with COM, don't worry—it's not important anymore. COM is mentioned only because the current licensing system is based on COM licensing. There are plenty of texts covering every grueling aspect of COM if you feel inclined to investigate. Personally, after many years of COM-based development, I'm glad to see it go.


Types of Licensing

The type of license depends on the expected use of a component. Demo versions of a component, such as the IconButton, may be distributed free and require no license for use. Generally, the demo version has only a subset of the functionality available for use, along with the restriction that the component cannot be used in a commercial application without purchase of the component.

Another option for licensing is a one-time fee for the product such as when buying a software package. The software generally includes an EULA, or End User License Agreement. The terms and conditions of the EULA will define the rights of the user with regard to the software.

Specialized server-based products often require the purchase of a Per-CPU license, in which the license fee is based on the number of CPUs within the server hosting the software or component. This style of licensing is generally found in server applications such as databases, email systems, and Web servers.

When considering a licensing system, try to keep in mind that the licensing should be unobtrusive and effective for both parties. Creating a complicated and intrusive licensing system often turns away potential customers who view the licensing schema as an unnecessary burden.

Licensing Controls

The .NET framework provides for both simple file-based licensing and custom licensing that can be implemented as needed to fulfill the licensing requirements of the component author. In the simplest form of licensing, a small text file is used to contain a single line of text regarding the license of the component. This scheme provides no real security or means of enforcement for the license. With custom licensing, the enforcement and use of the component and licensing are governed by the implementation of the custom LicenseProvider derived class. Custom licensing is covered in the “Providing Custom Licensing section” of this chapter.

To support licensing, the .NET Framework provides the classes listed in Table 10.1

Table 10.1. Licensing Classes
Class Description
License Abstract base class of all licenses.
LicenseContext Specifies when a licensed component can be used.
DesigntimeLicenseContext Specifies a design-time licensing context.
LicenseProvider Abstract base class for all license provider classes.
LicenseProviderAttribute Attribute used to specify the LicenseProvider for the licensed component.
LicenseManager Used to add a license to a component and manage the LicenseProvider.
LicFileLicenseProvider Implementation of a LicenseProvider that is consistent with the .NET Framework licensing system.
LicenseException Exception thrown when an error is encountered when trying to validate or grant a component's license.

The .NET licensing classes provide for simple licensing or serve as a starting point for developing custom licensing schemas. The next two sections cover simple licensing using the LicFileLicenseProvider class and creating a custom-licensing schema by inheriting from LicenseProvider to implement the licensing validation.

Simple Licensing: LicFileLicenseProvider

Creating a simple licensed component requires very little effort and entails only the four following steps:

1.
Create a LIC (license) file.

2.
Use the LicenseProviderAttribute to specify the LicenseProvider for the component.

3.
Create an instance of the license.

4.
Dispose the license when the component is disposed of.

The LIC, or license file, is a simple text file containing a single text string in the following format:

"Component is a licensed component."

Here, Component is the fully qualified name of the licensed component. In addition, the LIC file should have the same name as the component. Using the IconButton control, the LIC file would be as follows:

Filename: SAMS.ToolKit.Controls.IconButton.LIC

Contents: SAMS.ToolKit.Controls.IconButton is a licensed component.

The LIC file must be located in the directory containing the assembly of the licensed control. Figure 10.1 shows the LIC file for the IconButton loaded in VS .NET.

Figure 10.1. The IconButton LIC file.


To implement the simple licensing for the IconButton, the source for the control needs to be updated to add the LicenseProviderAttribute and the creation and disposal of the license. Listing 10.1 shows the modifications to the IconButton source necessary to support basic LIC file–based licensing.

Listing 10.1. Licensed IconButton
 1: using System;
 2: using System.Windows.Forms;
 3: using System.Drawing;
 4: using System.ComponentModel;
 5:
 6:
 7: namespace SAMS.ToolKit.Controls {
 8:     /// <summary>
 9:     /// IconButton Class
10:     /// </summary>
11:     [
12:     System.ComponentModel.Description( "SAMS IconButton Control" ),
13:     System.ComponentModel.Designer( typeof( SAMS.ToolKit.Design.IconButtonDesigner ) ),
14:     System.ComponentModel.LicenseProvider( typeof( System.ComponentModel
.LicFileLicenseProvider ) )
15:     ]
16:     public class IconButton : System.Windows.Forms.Control {
17:
18:        private License    license = null;
19:
20:        public IconButton( ) {
21:
22:             //validate the license
23:             license = LicenseManager.Validate( typeof( SAMS.ToolKit.Controls
.IconButton ), this );
24:
25:             InitializeComponent(  );
26:         }
27:
28:         protected override void Dispose( bool disposing ) {
29:             if( license != null ) {
30:                 license.Dispose( );
31:                 license = null;
32:             }
33:             base.Dispose( disposing );
34:         }
35:  //rest of IconButton implementation
36: }

Rather than relisting the entire IconButton source, Listing 10.1 shows only the modifications to the IconButton needed in order to implement licensing. The first modification is the addition of the LicenseProviderAttribute on line 14. This attribute is used to specify the type of license provider to create when validating the license for the component. The .NET Framework supports simple file-based licensing by providing an implementation of the LicenseProvider abstract base class in the form of LicFileLicenseProvider.

With the attribute in place, the next step is to declare a private member of type License. The declaration of this member is found on line 18 of Listing 10.1. Remember that the License class is an abstract base class for all license types. To obtain a valid license, the LicenseManager is used to validate the license for the control. This validation can be found within the constructor for the IconButton starting on line 20. If the validation fails, the LicenseManager throws a LicenseException. When this exception is not caught, an instance of the control will not be created.

In fact, using VS .NET to create a Windows application and hosting the IconButton on a form can demonstrate this point. To make the license validation fail, remove the LIC file from the directory containing the SAMS.ToolKit.dll assembly. Next, drag the IconButton from the Toolbox onto the form. VS .NET generates a message box stating that a valid license for the control could not be created, as shown in Figure 10.2.

Figure 10.2. License validation failure.


Licenses created by a component should be disposed of when the component itself is disposed of. Line 28 of Listing 10.1 shows the Dispose method of the IconButton disposing of the contained License.

To see the results of the licensing implementation, create a new Windows application and add the IconButton to the Toolbox and then to the form. If the LIC file is in place, the IconButton will be created without any noticeable difference with respect to other test applications created to this point. However, there is a difference, and that difference is in how the licensing is enforced and used.

Every Windows application contains a license.licx file, located in the project directory. This license file contains the necessary licensing information for all licensed controls used by the application. This licx file is compiled as a binary resource and embedded within the output assembly. This allows the application to validate all licenses and does not require the various LIC files for licensed components to be distributed along with the application. Figure 10.3 shows the license.licx file for the test Windows application.

Figure 10.3. The License.licx file.


The simple file-based licensing schema does not provide much in the way of security or the enforcement of proper use of the control based on an agreed license. To provide a more robust licensing schema, it's necessary to create a custom licensing solution.

Providing Custom Licensing

To provide a custom licensing implementation, at least two classes need to be created. These two classes will represent the license and the license provider implementation. The licensing scheme is implemented by deriving from the LicenseProvider base class and implementing the GetLicense method. In addition, a custom license class needs to be created by deriving from the abstract License class and implementing the LicenseKey property and the Dispose method.

Custom Licensing implementations vary based on need. For the purpose of demonstration, a file-based custom provider will be developed. Other implementations might make use of a Web Service or some other verification means, such as registry entries or a product key entered by the developer. In development of a custom provider, there is no steadfast rule for “how”—only that the licensing system makes sense for the product.

To demonstrate a custom license provider, the IconButton will be licensed by using an xml file that contains an entry for the IconButton control along with a key value to be used as the license key. This xml file will be named sams.licensing.xml and located within the same directory as the SAMS.ToolKit.dll assembly. Listing 10.2 shows the xml file to be used as the license file.

Listing 10.2. Custom License XML File
1: <?xml version="1.0"?>
2: <sams>
3:   <control name="SAMS.ToolKit.Controls.IconButton" key="custom_key_value"/>
4: </sams>

The next step in providing a custom licensing schema is to provide the implementation for a license and license provider. Listing 10.3 shows the implementation for the CustomLicenseProvider and CustomLicense classes.

Listing 10.3. Custom License Provider Source
 1: using System;
 2: using System.ComponentModel;
 3: using System.ComponentModel.Design;
 4: using System.Xml;
 5: using System.Xml.XPath;
 6: using System.IO;
 7: using System.Reflection;
 8: using System.Diagnostics;
 9:
10: namespace SAMS.ToolKit.Licensing
11: {
12:     public class CustomLicense : System.ComponentModel.License {
13:         private string                    licenseKey = null;
14:         private CustomLicenseProvider    owner    = null;
15:
16:    public CustomLicense( CustomLicenseProvider owner, string key ) {
17:             this.owner        = owner;
18:             this.licenseKey    = key;
19:         }
20:
21:         public override string LicenseKey {
22:             get {  return licenseKey; }
23:         }
24:
25:         public override void Dispose( ) {
26:         }
27:     }
28:
29:     public class CustomLicenseProvider : LicenseProvider  {
30:
31:
32:         protected bool IsKeyValid( string key, Type type ) {
33:             return (key == null ? false : true);
34:         }
35:
36:
37:         public override License GetLicense( LicenseContext context,
38:                                                Type type,
39:                                                object instance,
40:                                                bool allowExceptions ) {
41:
42:             CustomLicense    license    = null;
43:             if( context == null ) return null;
44:
45:
46:             if( context.UsageMode == LicenseUsageMode.Runtime ) {
47:                 //See if the key is stored
48:                 string key = context.GetSavedLicenseKey( type, null );
49:                 if( key != null && IsKeyValid( key, type ) )
50:           license = new CustomLicense( this, key );
51:             }
52:
53:             if( license == null ) {
54:                 //locate sams.license.xml file
55:                 ITypeResolutionService resolver = (ITypeResolutionService)context
.GetService( typeof( ITypeResolutionService ) );
56:
57:                 string location = resolver.GetPathOfAssembly( type.Assembly.GetName( ) );
58:
59:                 string licenseFile = Path.GetDirectoryName( location ) + "  sams
.license.xml";
60:
61:                 Debug.WriteLine( string.Format("License file location : { 0} ",
 licenseFile ) );
62:
63:
64:                 try {
65:                     XmlDocument    doc = new XmlDocument( );
66:                     doc.Load( licenseFile );
67:                     string xpathExpression = string.Format( "descendant:
:control[@name='{ 0} ']", type.FullName);
68:                     XmlNode controlNode = doc.SelectSingleNode( xpathExpression );
69:                     if( controlNode != null ) {
70:                         //get the key value
71:                         string key = controlNode.Attributes.GetNamedItem( "key" ).Value;
72:          if( key != null ) {
73:                             license = new CustomLicense( this, key );
74:                             //Save the license in the current context
75:                             context.SetSavedLicenseKey( type, license.LicenseKey );
76:                         }
77:                     }
78:                 }  catch( Exception e ) {
79:                     if( allowExceptions )
80:                         throw new LicenseException( type, instance, "License not valid" );
81:                     else
82:                         return null;
83:                 }
84:             }
85:             return license;
86:         }
87:     }
88:  }

The verification of the license takes place in the GetLicense method of the CustomLicenseProvider class; this method begins on line 37. The location of the license key depends on the current LicenseContext.UsageMode. The UsageMode can be either Runtime or Designtime. During runtime, the license key should be located within the current LicenseContext object because the application's .licx file is part of the assemblies manifest. Remember that the .licx file will contain the necessary license information for validation during execution so that the component license file does not need to be distributed along with the application.

During design-time, the CustomLicenseProvider attempts to locate the custom xml-based license file located in the same directory as the control assembly. If the license key is valid, the license information is stored within the current LicenseContext object, and an instance of the CustomLicense is returned. Otherwise, the CustomLicenseProvider throws an exception of type LicenseException, if allowed; otherwise, it returns null.

Note

For the purpose of the example, a non-empty string will suffice for the licensing requirements. In addition, the license key is extracted using an XPath expression into the xml file. The subject of XML and XPath are beyond the scope of this text. However, information about XPath expressions and their usage is available from www.w3c.org.


To use the new custom licensing, the LicenseProvider attribute of the IconButton should be updated as shown in Listing 10.4.

Listing 10.4. Adding Licensing Support to the IconButton
1:     System.ComponentModel.LicenseProvider( typeof( SAMS.ToolKit.Licensing
.CustomLicenseProvider ) )
2:     ]
3:     public class IconButton : System.Windows.Forms.Control {

No other changes to the IconButton class are necessary to make use of the new custom licensing implementation.

The licensing support provided by the .NET Framework allows for custom licensing schemas to be implemented with little effort, thus allowing vendors to enforce proper use of their intellectual property.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.69.45