如果你是商業元件的設計師,可能會希望在元件裡面加入適當的保護,以檢查使用你的元件 的用戶是否為合法授權的用戶。.NET framework 提供了一個固定的元件授權檢查模型,只要依照此模型來設計,就能很容易為元件加入授權檢查的機制。這個模型主要是依靠兩個類別,一個是 LicenseManager,另一個是 LicenseProvider 類別。其元件模型如下圖:

.NET 元件授權模型

你在自己的元件中(通常是在建構函式裡面)呼叫 LicenseManager 的 Validate 方法,取得一個 License 物件,如果 Validate 方法傳回 null 或者丟出一個例外,就代表授權檢查失敗。而 LicenseManager 的 Validate 方法則是去呼叫 LicenseProvider 的 GetLicense 方法來取得 License 物件,因此,真正檢查元件授權的動作,是寫在 GetLicense 方法裡面。不過,LicenseProvider 是一個抽象類別,無法直接使用,你必須從這個類別繼承一個新的類別,並且改寫 GetLicense 方法,以提供檢查授權的實作程式碼。

.NET framework 提供了一個現成的 LicenseProvider 範例實作,其類別名稱是 LicFileLicenseProvider,這個類別只是供示範或測試用的,不能真的使用在實際的專案中。這裡我用一個簡單的範例,說明如何設計自己 的 LicenseProvider 類別,以提供自訂的授權檢查機制。

 

設計步驟

  1. 撰寫你自己的 LicenseProvider 類別,以提供自訂的授權檢查規則。
  2. 將 LicenseProvider attribute 套用到你想要保護的類別上,套用此 attribute 時,要傳入你自己的 LicensePovider 類別。
  3. 在你的類別裡面宣告一個私有的 License 型別的變數,用來持有授權物件。
  4. 呼叫 LicenseManager 的 Validate 方法或者 IsValid 屬性,以判斷元件的使用者是否有獲得授權。

實作步驟

(a) 建立元件

  1. New 一個 Class Library project: MyLib。
  2. 刪除既有的 Class1.cs,加入一個類別: MyTextBox.cs。
  3. 加入組件參考:System.Windows.Forms.dll。
  4. 讓 MyTextBox 類別繼承自 System.Windows.Forms.TextBox。
  5. Build 專案。

以上只是撰寫元件的一般程序,並沒有特別之處,稍後我們會再回來為這個類別加上授權檢查機制。

(b) 撰寫自己的 LicenseProvider 類別

  1. 在 MyLib 專案中加入一個類別: MyLicenseProvider.cs。
  2. 修改 MyLicenseProvider.cs,如下:
using System;
using System.ComponentModel;
using System.IO;
using System.Reflection;

namespace MyLib
{
  public class MyLicenseProvider : LicenseProvider
  {
    public MyLicenseProvider()
    {
    }

    public override License GetLicense(LicenseContext context, Type type, object instance, bool allowExceptions)
    {
      /*
       * 利用 context 參數的 UsageMode 屬性來判斷目前是在
       * 設計時期,還是在執行時期. 這裡我們只在設計時期才
       * 檢查元件的授權.
       */
      if (context.UsageMode == LicenseUsageMode.Designtime) 
      {
        // 只單純的檢查元件所在的路徑是否有一個 MyLic.txt 檔案, 
        // 有的話就表示合法授權.
        FileInfo fi = new FileInfo(Assembly.GetExecutingAssembly().FullName);
        string fname = fi.DirectoryName + @"\MyLic.txt";
        fi = new FileInfo(fname);
        if (fi.Exists) 
        {
          return new MyLicense();
        }
        else 
        {
          if (allowExceptions) 
          {
            throw new Exception("您尚未取得使用此元件的合法授權,請向 XX 公司洽詢!");
          }
          return null;
        }        
      }
      else // 不需要檢查授權
      {
        return new MyLicense();
      }
    }

  }

  // 實作你自己的 License 物件
  public class MyLicense : License
  {
    public override string LicenseKey
    {
      get
      {
        // 你應該修改這個實作,以提供應用程式唯一的授權碼
        return "123";
      }
    }

    public override void Dispose()
    {
    }
  }
}

在這個檔案裡面有兩個類別:MyLicenseProvider 和 MyLicense。檢查元件是否為合法授權的程式碼主要是放在 MyLicenseProvider 的 GetLicense 方法裡面。當 GetLicense 的檢查授權動作確認元件是合法授權使用,便會傳回一個 MyLicense 的物件實體,否則會丟出一個例外,或者傳回 null(端看參數 allowExceptions 是否為 true 而定)。在 GetLicense 裡面,首先判斷 context 參數的 UsageMode 屬性,當此屬性的值為 LicenseUsageMode.Designtime 時才進行授權檢查,也就是說,只有在設計時期才進行檢查,執行時期則不檢查。如果你需要控制檢查授權的時機,只要修改這部份的程式碼就行了。

由於我們不能直接建立 License 抽象類別的實體,因此定義了 MyLicense 類別,來建立我們自己的 License 物件。通常你會把授權的相關資訊(例如:應用程式或使用者的授權碼)保存在這個 License 物件裡面,這裡只做個簡單的示範,因此沒有做進一步的處理。根據實際需求的複雜程度,你甚至可以從 License 類別繼承下來兩個不同的類別,分別作為設計時期和執行時期的 License 物件,例如:MyDesigntimeLicense 和 MyRuntimeLicense。

(c) 為元件加上授權檢查

  1. 在 MyTextBox.cs 中加入 using System.ComponentModel;
  2. 在 MyTextBox 類別宣告前面加上 LicenseProvider attribute:
      [LicenseProvider(typeof(MyLicenseProvider))]
      public class MyTextBox : TextBox
    
  3. 在 MyTextBox 類別中加入一個私有成員變數:
      private MyLicense lic;
  4. 在 MyTextBox 建構函式中利用 LicenseManager 進行授權檢查的動作::
        public MyTextBox()
        {
          lic = (MyLicense) LicenseManager.Validate(typeof(MyTextBox), this);
        }
    
  5. 修改 MyTextBox 的 Dispose 方法,以便釋放 MyLicense 物件,如下:
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if (lic != null)
            {
              lic.Dispose();
              lic = null;
            }
          }
          base.Dispose( disposing );
        }
    
  6. Build 專案。
  7. 將元件註冊到 Toolbox。作法為:點選 Tools | Add/Remove Toolbox Items,點 Browse 鈕,然後選擇 MyLib.dll,按 OK。

(d) 建立測試專案

  1. New 一個 Windows Application 專案:MyApp。
  2. 從 Toolbox 中把 MyTextBox 拖到 form 上面,此時應該會出現錯誤 "您尚未取得使用此元件的合法授權,請向 XX 公司洽詢",而且控制項無法建立在 form 上面。
  3. 接著在 MyLib 專案的輸出路徑底下建立一個文字檔,檔名為 "MyLic.txt",內容不拘,只要有這個檔案就行了。註:因為 MyLicenseProvider 的 GetLicense 方法只判斷元件所在的目錄下是否有 MyLic.txt 這個檔案,有的話就視為合法授權使用。
  4. 再從 Toolbox 中把 MyTextBox 拖到 form 上面,此時應該可以通過授權檢查,而且控制項可以建立在 form 上面。
  5. 接著測試執行時期是否會檢查元件的授權。先 Build MyApp 專案,然後將步驟 3 所建立的 MyLic.txt 檔案刪除掉,接著利用檔案總管直接執行 MyApp.exe,應用程式應該可以正常執行。這表示執行時期並沒有檢查元件的授權,因為在 MyLicenseProvider 的 GetLicense 方法裡面,我們判斷了 context 參數的 UsageMode 屬性,只有當此屬性為 LicenseUsageMode.Designtime 時才進行授權檢查。

Ok! 大概就這樣了,只要您了解 LicenseManager 和 LicenseProvider 之間的關係,以及如何實作自己的 LicenseProvider 類別,應該很容易就能夠根據自己的需求做出不同的變化了。