天天看點

轉載一篇ClickOnce的文章!

使用VS2005的 ClickOnce 技術實作按需下載下傳元件

預設情況下,首次運作 ClickOnce 應用程式時,會下載下傳該應用程式中包含的所有程式集。但是一些特殊的場景我們可能不希望它這麼幹,而是希望按照一定規測或者需要用到某個元件的時候再下載下傳。

比如我們可能會有下面一些應用場景的需求:

1、我開發的這個用戶端程式是要收費的。但是免費使用者也可以使用部分功能。我在技術實作上把收費使用者使用的功能封裝到了A.dll 元件了,我希望免費使用者根本無法獲得A.dll,隻有收費使用者才能獲得A.dll,并加載A.dll中的收費功能。

2、我整個應用程式非常大,我不希望我每次更新,使用者都需要把所有應用程式都下載下傳下來,使用者應該隻需要下載下傳他用到的功能元件。

下面我們就來實作一個簡單的按需下載下傳的例子,我們完全可以在這個例子基礎上,實作上述提到的應用場景1。

示範步驟:

一、建立一個 類庫 Project

定義類庫輸出應用程式名為:OnDemandAssembly,即這個類庫編譯後産生的檔案名為 OnDemandAssembly.dll

這個類庫中有如下代碼,我們用這段代碼來模拟上面提到場景中的一些需要按需加載的功能或者是收費的功能,我們将在主程式中調用這個功能:

using System;

namespace OnDemandAssembly

{

    public class DynamicClass

    {

        public string Message

        {

            get

            {

                return "郭紅俊測試ClickOnce按需加載功能。";

            }

        }

    }

}

二、建立一個 Window 應用程式

我們将在這個Window 應用程式中加載上述類庫。

為了便于我們示範這個程式,請確定這個Window程式具備以下功能:

1、有一個 textbox 控件,這個控件在 Window 的OnLoad 事件中,把應用程式的目錄顯示在這裡,友善我們去監控是否上述 OnDemandAssembly.dll 元件被加載了。

代碼如下:

private void Form1_Load(object sender, EventArgs e)

{

    this.textBox1.Text = Application.StartupPath;

}

2、由一個  Button  按鈕,點選這個按鈕後,我們把 OnDemandAssembly.dll 元件中的 Message 資訊顯示出來,代碼如下:

private void button1_Click(object sender, EventArgs e)

{

    DynamicClass o = new DynamicClass();

    MessageBox.Show(o.Message);

}

Window程式關于ClickOnce設定比較特殊的地方:

我們來配置ClickOnce釋出的一些特殊參數,確定可以按需下載下傳需要的元件

本文中沒有較長的描述ClickOnce設定的各個步驟和參數,如果你對ClickOnce不是很熟悉,建議你首先看一些ClickOnce的入門文章再來看本文。

比如:http://blog.oracle.com.cn/155011/viewspace_3603.html 這裡提供的ClickOnce 文章(這裡是提供了一個word壓縮檔案下載下傳,文章在壓縮的Word檔案中)

選擇我們的Window程式,在右鍵菜單中選擇屬性,在屬性頁中選擇釋出(Publish)标簽頁。

然後點選 Application File 按鈕,我們來設定,需要釋出的檔案。如下圖:

轉載一篇ClickOnce的文章!

上述按鈕打開的視窗如下:

我們在打開的視窗中,設定 OnDemandAssembly.dll 檔案的 釋出狀态為 Include,

并在 Download Group 中為OnDemandAssembly.dll 檔案建立的一個下載下傳組,我們這裡把這個新的下載下傳組命名為 DemandAssembly01 。

說明:

預設情況下,我們用ClickOnce 第一次安裝,或者更新程式的時候,系統隻下載下傳 Required 組的檔案,其他組的檔案系統不下載下傳,需要我們自己編碼來下載下傳。

轉載一篇ClickOnce的文章!

其他ClickOnce的設定跟我們平常使用的時候一樣來設定。本文忽略這部分。

我們這時候釋出這個程式,我們下載下傳安裝後,就會發現OnDemandAssembly.dll 檔案不在安裝目錄下,點選這個程式的按鈕,就會報異常,找不到需要的應用程式集

OnDemandAssembly.dll 元件。

下面我們來編碼實作,如果應用程式找不到 OnDemandAssembly.dll 元件,就從網上下載下傳這個元件的功能

1、視窗的構造函數中增加 AssemblyResolve 事件的處理邏輯

public Form1()

{

    InitializeComponent();

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

}

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)

{

}

說明:AppDomain.AssemblyResolve 事件 在對程式集的解析失敗時發生。

2、下面我們編碼實作 AssemblyResolve  事件的處理邏輯

using System.Reflection;

using System.Deployment.Application;

// 如果我們有多個檔案都需要按需下載下傳的話,每個檔案影射到那個下載下傳分組,就是這個實體來記錄的

Dictionary<String, String> DllMapping = new Dictionary<String, String>();

public Form1()

{

    InitializeComponent();

    DllMapping["OnDemandAssembly"] = "DemandAssembly01";

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

}

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)

{

    Assembly newAssembly = null;

    // 是 ClickOnce 部署方式

    if (ApplicationDeployment.IsNetworkDeployed)

    {

        ApplicationDeployment deploy = ApplicationDeployment.CurrentDeployment;

        // Get the DLL name from the Name argument.

        string[] nameParts = args.Name.Split(',');

        string dllName = nameParts[0];

        string downloadGroupName = DllMapping[dllName];

       // 下載下傳所需要的檔案 

  try

        {

            deploy.DownloadFileGroup(downloadGroupName);

        }

        catch (DeploymentException de)

        {

            MessageBox.Show("Downloading file group failed. Group name: " + downloadGroupName + "; DLL name: " + args.Name);

            throw (de);

        }

  // 加載元件到應用程式集

        // Load the assembly.

        // Assembly.Load() doesn't work here, as the previous failure to load the assembly

        // is cached by the CLR. LoadFrom() is not recommended. Use LoadFile() instead.

        try

        {

            newAssembly = Assembly.LoadFile(Application.StartupPath + @"/" + dllName + ".dll");

        }

        catch (Exception e)

        {

            throw (e);

        }

    }

    else

    {

        //Major error - not running under ClickOnce, but missing assembly. Don't know how to recover.

        throw (new Exception("Cannot load assemblies dynamically - application is not deployed using ClickOnce."));

    }

    return (newAssembly);

}

一些問題說明:

Q:上述代碼中,如果我們這個元件OnDemandAssembly.dll 有最新版本了,并且釋出了,但是用戶端還是一個老的版本的話,這個邏輯我們沒有處理呀?

A:問題這個問題,就是代表你對 ClickOnce 的原理還是不懂,OnDemandAssembly.dll 有最新版本,那你就必須再重新釋出一個版本的ClickOnce代碼,這時候釋出的版本号就不一樣了。用戶端下不同版本号的ClickOnce 程式是存在不同目錄下的(當然伺服器也是一樣)。

系統檢查到你的新版本程式釋出後,會為新的版本号建立目錄,這個目錄下如果你沒有用過OnDemandAssembly.dll 的功能,是不會有OnDemandAssembly.dll 元件的,繼而上述問題是可以不用考慮的。

參考資料:

MSDN:Downloading Assemblies On Demand with the ClickOnce Deployment API

使用VS2005的 ClickOnce 技術實作按需下載下傳元件

預設情況下,首次運作 ClickOnce 應用程式時,會下載下傳該應用程式中包含的所有程式集。但是一些特殊的場景我們可能不希望它這麼幹,而是希望按照一定規測或者需要用到某個元件的時候再下載下傳。

比如我們可能會有下面一些應用場景的需求:

1、我開發的這個用戶端程式是要收費的。但是免費使用者也可以使用部分功能。我在技術實作上把收費使用者使用的功能封裝到了A.dll 元件了,我希望免費使用者根本無法獲得A.dll,隻有收費使用者才能獲得A.dll,并加載A.dll中的收費功能。

2、我整個應用程式非常大,我不希望我每次更新,使用者都需要把所有應用程式都下載下傳下來,使用者應該隻需要下載下傳他用到的功能元件。

下面我們就來實作一個簡單的按需下載下傳的例子,我們完全可以在這個例子基礎上,實作上述提到的應用場景1。

示範步驟:

一、建立一個 類庫 Project

定義類庫輸出應用程式名為:OnDemandAssembly,即這個類庫編譯後産生的檔案名為 OnDemandAssembly.dll

這個類庫中有如下代碼,我們用這段代碼來模拟上面提到場景中的一些需要按需加載的功能或者是收費的功能,我們将在主程式中調用這個功能:

using System;

namespace OnDemandAssembly

{

    public class DynamicClass

    {

        public string Message

        {

            get

            {

                return "郭紅俊測試ClickOnce按需加載功能。";

            }

        }

    }

}

二、建立一個 Window 應用程式

我們将在這個Window 應用程式中加載上述類庫。

為了便于我們示範這個程式,請確定這個Window程式具備以下功能:

1、有一個 textbox 控件,這個控件在 Window 的OnLoad 事件中,把應用程式的目錄顯示在這裡,友善我們去監控是否上述 OnDemandAssembly.dll 元件被加載了。

代碼如下:

private void Form1_Load(object sender, EventArgs e)

{

    this.textBox1.Text = Application.StartupPath;

}

2、由一個  Button  按鈕,點選這個按鈕後,我們把 OnDemandAssembly.dll 元件中的 Message 資訊顯示出來,代碼如下:

private void button1_Click(object sender, EventArgs e)

{

    DynamicClass o = new DynamicClass();

    MessageBox.Show(o.Message);

}

Window程式關于ClickOnce設定比較特殊的地方:

我們來配置ClickOnce釋出的一些特殊參數,確定可以按需下載下傳需要的元件

本文中沒有較長的描述ClickOnce設定的各個步驟和參數,如果你對ClickOnce不是很熟悉,建議你首先看一些ClickOnce的入門文章再來看本文。

比如:http://blog.oracle.com.cn/155011/viewspace_3603.html 這裡提供的ClickOnce 文章(這裡是提供了一個word壓縮檔案下載下傳,文章在壓縮的Word檔案中)

選擇我們的Window程式,在右鍵菜單中選擇屬性,在屬性頁中選擇釋出(Publish)标簽頁。

然後點選 Application File 按鈕,我們來設定,需要釋出的檔案。如下圖:

轉載一篇ClickOnce的文章!

上述按鈕打開的視窗如下:

我們在打開的視窗中,設定 OnDemandAssembly.dll 檔案的 釋出狀态為 Include,

并在 Download Group 中為OnDemandAssembly.dll 檔案建立的一個下載下傳組,我們這裡把這個新的下載下傳組命名為 DemandAssembly01 。

說明:

預設情況下,我們用ClickOnce 第一次安裝,或者更新程式的時候,系統隻下載下傳 Required 組的檔案,其他組的檔案系統不下載下傳,需要我們自己編碼來下載下傳。

轉載一篇ClickOnce的文章!

其他ClickOnce的設定跟我們平常使用的時候一樣來設定。本文忽略這部分。

我們這時候釋出這個程式,我們下載下傳安裝後,就會發現OnDemandAssembly.dll 檔案不在安裝目錄下,點選這個程式的按鈕,就會報異常,找不到需要的應用程式集

OnDemandAssembly.dll 元件。

下面我們來編碼實作,如果應用程式找不到 OnDemandAssembly.dll 元件,就從網上下載下傳這個元件的功能

1、視窗的構造函數中增加 AssemblyResolve 事件的處理邏輯

public Form1()

{

    InitializeComponent();

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

}

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)

{

}

說明:AppDomain.AssemblyResolve 事件 在對程式集的解析失敗時發生。

2、下面我們編碼實作 AssemblyResolve  事件的處理邏輯

using System.Reflection;

using System.Deployment.Application;

// 如果我們有多個檔案都需要按需下載下傳的話,每個檔案影射到那個下載下傳分組,就是這個實體來記錄的

Dictionary<String, String> DllMapping = new Dictionary<String, String>();

public Form1()

{

    InitializeComponent();

    DllMapping["OnDemandAssembly"] = "DemandAssembly01";

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

}

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)

{

    Assembly newAssembly = null;

    // 是 ClickOnce 部署方式

    if (ApplicationDeployment.IsNetworkDeployed)

    {

        ApplicationDeployment deploy = ApplicationDeployment.CurrentDeployment;

        // Get the DLL name from the Name argument.

        string[] nameParts = args.Name.Split(',');

        string dllName = nameParts[0];

        string downloadGroupName = DllMapping[dllName];

       // 下載下傳所需要的檔案 

  try

        {

            deploy.DownloadFileGroup(downloadGroupName);

        }

        catch (DeploymentException de)

        {

            MessageBox.Show("Downloading file group failed. Group name: " + downloadGroupName + "; DLL name: " + args.Name);

            throw (de);

        }

  // 加載元件到應用程式集

        // Load the assembly.

        // Assembly.Load() doesn't work here, as the previous failure to load the assembly

        // is cached by the CLR. LoadFrom() is not recommended. Use LoadFile() instead.

        try

        {

            newAssembly = Assembly.LoadFile(Application.StartupPath + @"/" + dllName + ".dll");

        }

        catch (Exception e)

        {

            throw (e);

        }

    }

    else

    {

        //Major error - not running under ClickOnce, but missing assembly. Don't know how to recover.

        throw (new Exception("Cannot load assemblies dynamically - application is not deployed using ClickOnce."));

    }

    return (newAssembly);

}

一些問題說明:

Q:上述代碼中,如果我們這個元件OnDemandAssembly.dll 有最新版本了,并且釋出了,但是用戶端還是一個老的版本的話,這個邏輯我們沒有處理呀?

A:問題這個問題,就是代表你對 ClickOnce 的原理還是不懂,OnDemandAssembly.dll 有最新版本,那你就必須再重新釋出一個版本的ClickOnce代碼,這時候釋出的版本号就不一樣了。用戶端下不同版本号的ClickOnce 程式是存在不同目錄下的(當然伺服器也是一樣)。

系統檢查到你的新版本程式釋出後,會為新的版本号建立目錄,這個目錄下如果你沒有用過OnDemandAssembly.dll 的功能,是不會有OnDemandAssembly.dll 元件的,繼而上述問題是可以不用考慮的。

參考資料:

MSDN:Downloading Assemblies On Demand with the ClickOnce Deployment API

繼續閱讀