如果想开发一个模块(组件),不希望这个模块被别人随意使用,尤其是希望向使用组件的客户收取一定的费用,那么可以考虑使用许可功能。
.Net中已经包含了许可架构。该架构如下图所示:
现在我们给出一个最简单的许可代码(无许可文件)
using System;
using System.ComponentModel;
using System.Diagnostics;
namespace Hello
{
public class Program
{
static void Main()
{
// use the licensed component MyClass.
using(MyClass h2 = new MyClass())
{
Debug.Print("end");
}
}
}
// Define a component.
// 必须对需要被许可的组件添加下面的LicenseProviderAttribute特性。typeof后面跟随自定义或第三方定义的许可供应器
[LicenseProvider(typeof(MyProvider))]
public class MyClass:IDisposable
{
private License license = null;
public MyClass()
{
license = LicenseManager.Validate(typeof(MyClass), this);
}
public void Dispose()
{
Dispose(true);
}
protected void Dispose(bool disposing)
{
if(disposing)
{
if (license != null)
{
license.Dispose();
license = null;
}
}
}
}
public class MyLicense : License
{
public override string LicenseKey => "Hello World!";
public override void Dispose()
{
Debug.Print("The License ared disposed");
}
}
public class MyProvider : LicenseProvider
{
public override License GetLicense(LicenseContext context, Type type, object instance, bool allowExceptions)
{
return new MyLicense();
}
}
}
在执行LicenseManager.Validate(…)时,会自动调用MyProvicer中的GetLicense()方法。
.Net提供了一个已经定义好的LicFileLicenseProvider。它需要LIC后缀的许可文件。要求许可文件的名字必须是Namespace.ComponentName.LIC,其中Namespace是组件所在的命名空间名,比如下面这个例子就是Hello,ComponentName则是组件名,比如下面这个例子就是MyClass,因此LIC许可文件的名字必须是Hello.MyClass.LIC。
此外,这个LIC文件中必须包含一段文本字符串:
Namespace.ComponentName is a licensed component.
注意,要根据Namespace和ComponentName的不同更改相应值。下面的这个例子LIC许可文件内需如下:
Hello.MyClass is a licensed component.
最后,这个LIC文件需要在使用组件的可执行文件同一个文件夹内。
下面给出使用LicFileLicenseProvider的例子:
namespace Hello
{
public class Program
{
static void Main()
{
// use the licensed component MyClass.
using(MyClass h2 = new MyClass())
{
Debug.Print("end");
}
}
}
// Define a component.
[LicenseProvider(typeof(LicFileLicenseProvider))]
public class MyClass:IDisposable
{
private License license = null;
public MyClass()
{
license = LicenseManager.Validate(typeof(MyClass), this);
}
public void Dispose()
{
Dispose(true);
}
protected void Dispose(bool disposing)
{
if(disposing)
{
if (license != null)
{
license.Dispose();
license = null;
}
}
}
}
}
如果没有LIC文件,或者LIC文件命名不正确,或者LIC文件内不包含应当包含的字符串,那么LicenseManager.Validate(…)验证处会抛出异常,表明许可失败!
当然了, 今天给的两个例子许可非常容易被人破解,因为几乎没有任何加密措施。因此,可以修改上面的这些例子以便不容易被人盗用。
LicenseContext
现在,我们讨论下LicenseContext。
上面的例子中没有展示LicenseContext怎么传入,怎么用。
下面简单介绍一下。
LincenseContext的传入都是依赖LicenseManager类。
一种是通过设置LicenxeManager的CurrentContext属性:
[LicenseProvider(typeof(MyProvider))]
public class MyClass:IDisposable
{
private License license = null;
public MyClass()
{
LicenseManager.CurrentContext = new zkLicenseContext();
license = LicenseManager.Validate(typeof(MyClass), this);
}
public void Dispose()
{
Dispose(true);
}
protected void Dispose(bool disposing)
{
if(disposing)
{
if (license != null)
{
license.Dispose();
license = null;
}
}
}
}
另外一种, 是通过LicenseManager的CreateWithContext(…)方法,如下:
using(MyClass h2 = LicenseManager.CreateWithContext(typeof(MyClass), new zkLicenseContext()) as MyClass)
{
Debug.Print("end");
}