2009年8月18日 星期二

在應用程式中動態的載入Assembly完成自動更新佈署1-2

RunPC 128期:利用.NET技術實現零接觸佈署(二)

晚期繫結(Late Binding)
System.Reflection命名空間除了可以讓我們在執行期間取得型別資訊外,而另一個功能也是本篇文章的重點所在,利用反射機制達成晚期繫結的功能,使您可以在執行期間才去動態載入組件,解析型別與其成員是否存在,然後就可以動態地叫用其方法,讀寫屬性值和維護您的欄位。
談到晚期繫結它有一關鍵類別System.Activator類別,而它的核心方法即是Activator.CreateInstance方法,它可以在執行時期替某個型別建立一個執行個體,程式碼如下:

Dim PType As Type = Asm.GetType("DynamicAssembly.Person")
Dim objPerson As Object = Activator.CreateInstance(PType, New Object() {"ML", "Chen"})

Activator.CreateInstance第一個參數即是執行時期替PType型別(即Person類別)建立一個執行個體,而Person類別建構式有兩個參數First、Last,您可以在Activator.CreateInstance方法的第二個參數中以物件陣列的方式輸入,即可在記憶體中建立一PType的執行個體,再將它指給objType變數。
於記憶體中建立一個執行個體後,接下來讓我們看看該如何呼叫該型別提供的方法,程式碼如下:

Dim miShowName As MethodInfo = PType.GetMethod("ShowName")
miShowName.Invoke(objPerson, Nothing)

如先前的說明,我們可經由型別的GetMethod方法,取出各別的方法給MethodInfo;再透過其Invoke方法來叫用型別的方法,而Invoke方法的第一個參數即在記憶體中建立的執行個體變數,第二個變數為該呼叫方法輸入的參數,可如前建構式方式輸入參數值,此範例的ShowName方法無參數則是Nothing傳入。

了解如何呼叫方法後,接下來為各位介紹如何讀取、改變設定欄位成員值,Person類別內有二個欄位成員:FirstName與LastName,於建構式中我們已分別指定為"ML", "Chen"字串,下面程式碼分別列出二欄位成員改變前與改變後的值:

Console.WriteLine("FirstName成員改變之前內容值:{0}", PType.InvokeMember("FirstName", BindingFlags.GetField, Nothing, objPerson, Nothing))
PType.InvokeMember("FirstName", BindingFlags.SetField, Nothing, objPerson, New Object() {"Good"})
Console.WriteLine("FirstName成員改變之後內容值:{0}", PType.InvokeMember("FirstName", BindingFlags.GetField, Nothing, objPerson, Nothing))
Console.WriteLine("LastName成員改變之前內容值:{0}", PType.InvokeMember("LastName", BindingFlags.GetField, Nothing, objPerson, Nothing))
PType.InvokeMember("LastName", BindingFlags.SetField, Nothing, objPerson, New Object() {"Man"})
Console.WriteLine("LastName成員改變之後內容值:{0}", PType.InvokeMember("LastName", BindingFlags.GetField, Nothing, objPerson, Nothing))

此處用到最主要的為Type的InvokeMember方法,它的作用是使用指定的繫結條件約束並符合指定的引數清單,來叫用指定的成員。此方法有三種多載,我們針對我們該範例使用到的InvokeMember方法多載加以介紹,其餘二個多載請參考MSDN說明,結構如下:

Overloads Public Function InvokeMember( _
ByVal name As String, _
ByVal invokeAttr As BindingFlags, _
ByVal binder As Binder, _
ByVal target As Object, _
ByVal args() As Object _
) As Object

參數:
Name:為要叫用的建構函式、方法、屬性或欄位成員的名稱。
invokeAttr:可由多個 BindingFlags 組成,BindingFlags分類如下:

下列 BindingFlags 篩選旗標可用來定義要包含在搜尋中的成員:



下列 BindingFlags 修飾詞旗標可用來變更搜尋作業的方式:



下列 BindingFlags 引動過程旗標可用來表示要對成員採取哪種動作:


binder:該範例我們傳入Nothing即可,除非您有多載方法的選擇、引數型別的轉換…等需求。
Targer:要叫用指定成員的 Object。
Args:包含引數的陣列,這個引數要傳遞到要叫用的成員中。
上面的程式碼是針對欄位成員加以維護,是故我們用到BindingFlags的GetField與SetField成員,若要讀取Person類別的Name成員則請用BindingFlags的GetProperty成員即可,此處就不再加以說明。

動態載入組件
列舉類別的成員的範例中我們使用Assembly.Load靜態方法傳入組件名稱而傳回一Assembly的實體物件,而我們在此又為各位介紹兩個Assembly載入組件的方法,一為Assembly.LoadFile方法其傳入參數為該組件的絕對路徑,此種做法只適用VS.NET 2003或.NET Framework 1.1環境;二為Assembly.LoadFrom方法其傳入的參數為該組件的位置,除可同為Assembly.LoadFile的絕對路徑外亦可為相對路徑或URL路徑、Ftp檔案路徑…等,且不限於VS.NET 2003或.NET Framework 1.1環境,故接下來的實作範例我們會以Assembly.LoadFrom方法來當動態載入的範本。
Assembly.Load方法:

Asm = System.Reflection.Assembly.Load("DynamicAsm ") ‘只可為組件名稱

Assembly. LoadFrom方法:

Asm = System.Reflection.Assembly.LoadFrom("C:\inetpub\wwwroot\ DynamicAsm.exe") ‘絕對路徑(○)
Asm = System.Reflection.Assembly.LoadFrom("DynamicAsm.exe ") ‘相對路徑(○)
Asm = System.Reflection.Assembly.LoadFrom("http://192.168.1.1/ DynamicAsm.exe") ‘URL路徑(○)
Asm = System.Reflection.Assembly.LoadFrom("ftp:// 192.168.1.1/mlftp/DynamicAsm.exe")‘Ftp路徑(○)

Assembly.LoadFile方法:

Asm = System.Reflection.Assembly.LoadFile("C:\inetpub\wwwroot\ DynamicAsm.exe ") ‘絕對路徑(○)
Asm = System.Reflection.Assembly.LoadFile("DynamicAsm.exe") ‘相對路徑(〤)
Asm = System.Reflection.Assembly.LoadFile("http:// 192.168.1.1/DynamicAsm.exe ") ‘URL路徑(〤)
Asm = System.Reflection.Assembly.LoadFile("ftp:// 192.168.1.1/mlftp/DynamicAsm.exe")‘Ftp路徑(〤)

當我們了解Load、LoadForm、LoadFile三種方法的差異處後,與它們各自的運用時機,最後讓我們建立一個以最友善的動態載入組件方法LoadForm為主自動更新佈署範例。

LoadForm實現自動更新佈署範例

Imports System.Reflection
Imports System.Net
Imports System.io

Public Class Form1
Inherits System.Windows.Forms.Form

#Region " Windows Form 設計工具產生的程式碼 "

#End Region

Private Sub btnShowForm_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnShowForm.Click
Dim strUrlFile, strMsg, strOldFile, strNewFile As String
strUrlFile = "http://192.168.1.1/Com/Version.dll"
strMsg = ""
strNewFile = "Temp.dll"
strOldFile = "Version.dll"

Dim bolContinue As Boolean = True
Dim myRequest As HttpWebRequest
Try
myRequest = CType(WebRequest.Create(strUrlFile), HttpWebRequest)
Catch ex1 As NotSupportedException
strMsg = "NotSupportedException" & ex1.Message
bolContinue = False
Catch ex2 As ArgumentException
strMsg = "ArgumentException" & ex2.Message
bolContinue = False
Catch ex3 As UriFormatException
strMsg = "UriFormatException" & ex3.Message
bolContinue = False
Catch ex As Exception
strMsg = "Exception" & ex.Message
bolContinue = False
End Try
If bolContinue = True Then
MessageBox.Show("發生內部錯誤:" & strMsg)
Exit Sub
End If

Dim myResponse As HttpWebResponse
Try
myresponse = CType(myRequest.GetResponse, HttpWebResponse)
Catch ex1 As WebException
strMsg = "未找到該檔或連線失敗:" & ex1.Message
If File.Exists(strOldFile) Then
strMsg &= "載入現有檔案."
MessageBox.Show(strMsg)
LoadMeDLL(strOldFile)
Else
strMsg &= "不存在檔案: " & strOldFile
strMsg &= "請檢查…."
MessageBox.Show(strMsg)
End If
Catch ex As Exception
strMsg = "Exception" & ex.Message
MessageBox.Show(strMsg)
End Try

Dim receiveStream As Stream = myresponse.GetResponseStream
Dim ofStream As FileStream = New FileStream(strNewFile, FileMode.Create)

Dim streamBytes As Byte()
Dim iLength As Int32 = CType(myresponse.ContentLength, Int32)

If receiveStream.CanRead Then
receiveStream.Read(streamBytes, 0, iLength)
ofStream.Write(streamBytes, 0, iLength)
Else
MessageBox.Show("串流讀取失敗。")
End If
ofStream.Close()
myresponse.Close()

Try
If File.Exists(strOldFile) Then
File.Delete(strOldFile)
End If
File.Move(strNewFile, strOldFile)
Catch ex As Exception
MessageBox.Show(ex.ToString())
File.Delete(strNewFile)
End Try
LoadMeDLL(strOldFile)
End Sub
Public Sub LoadMeDLL(ByVal strFile As String)
Dim simpAsm As [Assembly] = System.Reflection.Assembly.LoadFrom(strFile)
Dim frmTemp As Form = CType(simpAsm.CreateInstance("Version.F01"), Form)
frmTemp.Show()
End Sub

此範例是個簡易的Sample,說明每次執行時會從Web站台上下載最新版本的Version.dll暫儲存為Temp.dll,再將覆蓋成本機端的Version.dll檔案,最後呼叫LoadMeDLL方法,載入該組件與建立一Version.F01型別的表單實體,再將其呈現;當Version.dll組件版本改變後,下次再執行時版本即會自動完成更新佈署,請參考(圖五)。

(圖五)範例示範圖

而筆者實務上也使用該機制建立一『Simple Smart Platform(SSP)』系統,除俱備No-Touch Deployment (NTD)功能外也結合Single Sign On (SSO:單一登錄)功能,使該系統達成On Demand Software Services,讓使用軟體似使用水電服務般的方便即時,架構圖如(圖六),而操作畫面的簡圖如(圖七)。

(圖六) Simple Smart Platform架構圖


(圖七) Simple Smart Platform操作簡圖


結語:
本篇文章筆者一一為各位介紹了,基本核心的System.Type、System.Reflection反射機制,也透過該機制逐一列舉出組件類別內的成員;除此之外,我們也為各位介紹本章的重點所在『動態載入組件』的方法以及晚期繫結(Late Binding),Invoke、InvokeMember來呼叫動態載入組件的方法與相關的成員設定;而我們以一個簡易的範例達成系統自動更新佈署介紹;最後,也為各位簡略介紹筆者實務上建立的SSP系統。在NTD這一系列的文章中已為各位介紹以網址的方式來實現零接觸佈署和本篇的.NET如何動態的載入Assembly,接下來幾篇會為各位介紹BITS、.NET Application Updater與VS.NET 2005重要新增功能之Click Once。

2009年8月12日 星期三

在應用程式中動態的載入Assembly完成自動更新佈署1-1

RunPC 128期:利用.NET技術實現零接觸佈署(二)

利用.NET技術實現零接觸佈署的第一篇文章中,我們說明了如何利用.NET的NTD技術和如何設定程式碼存取安全(Code Access Security,CAS)以及它在.NET安全性上扮演的角色,我們也舉了二個例子加以說明,其一經由URL執行.NET應用程式,利用Download Cache機制佈署、更新程式,讓.NET的NTD應用系統俱備了Web (Thin Clinet)與Windows (Rich Client)應用程式的優點;其二建立一個相似於早期ActiveX Document的NTD應用程式內嵌於Internet Explorer中,並使用Client Script與該.NET控制項互動。
接下來我們會為各位介紹.NET的動態載入組件(Assembly)完成自動更新與佈署作法,此種作法與上篇之差異在於,上篇中針對一應用程式來作更新且完全依賴.NET提供的機制來完成,而本篇可細分至針對Assembly來作更新,甚可加入系統權限角色功能等相關判來完成本身自訂的特殊需求;該篇文章依序會為各位介紹:定義在System命名空間(namespace)下的Type類別、定義於System.Reflection命名空間下的反射機制(Reflection)服務、用來作晚期繫結(Late Binding)的Activator類別…等相關技術來完成動態載入組件自動更新的功能。

System.Type類別
Type代表型別的宣告,它提供了許多方法成員可用來找尋項目後的細節,而許多定義在System.Reflection命名空間裡的項目都用到抽象System.Type類別;換句話說Type 是 System.Reflection 功能的根,也是存取中繼資料 (Metadata) 的主要方法,使用 Type 的成員可以很簡易的取得型別宣告的資訊,如(表一)所示,而Reflection和CLR型別系統請參考(圖一)。

(表一)Type類別成員


(圖一)Reflection和CLR型別系統

取得Type物件的方式與Type的使用
Type類別是個抽象類別,是故您不可以利用『New』關鍵字來建立Type的實體物件,以下筆者提供您三種方式取得Type物件。

1、 GetType運算子:傳回指定型別的 Type 物件。
Dim t As Type=GetType(Integer)
‘註:Integer為型別名稱
2、 靜態Type.GetType方法:取得具有指定名稱的Type物件。
Dim t As Type = Type.GetType("System.Int32")
‘注意:此處"System.Int32"字串參數大小有別。
3、 Object.GetType方法:取得目前執行個體的Type物件。
Dim str As New String("NewString")
Dim t As Type = str.GetType

除非必要否則我們並不建議您使用第三種方式來取得Type物件,因為此處您必須先建立一個物件執行個體,方能取得您所要的Type物件;當然在取得一個Type物件的參考後接下來讓我們用個很簡單的對應關係圖來說明執行時期的型別資訊。

(圖二) 執行時期的型別資訊對應關係圖


System.Reflection命名空間的探索
在探索System.Reflection命名空間首要談的就是Assembly類別,我們可以經由使用該型別動態的載入組件、在執行時期叫用(Invoke)類別成員(稱之為『晚期繫結』),和取得組件本身的屬性資訊。
列舉類別的成員
接著讓我們利用隻簡單的範例程式來瀏灠類別定義的資訊。首先,我們建立一個新的[Visual Basic Windows應用程式專案],取名為[DynamicAssembly],再於Form1程式碼視窗中輸入下面這段程式碼,用於灠瀏組件中所有成員,最後於表單載入事件中呼叫WalkAssembly函式,並傳入[DynamicAssembly]組件名稱(註1),執行後即可在輸出視窗中看見如[圖三]的內容列出本身組件的所有成員型別、名稱…等。
註1:您可於方案總管中找到該DynamicAssembly專案,點選右鍵選[屬性],即可叫出該專案的屬性頁,內有一組件名稱項目可正確找出該專案的組件名稱。

Public Sub WalkAssembly(ByVal assemblyName As String)
Dim Asm As [Assembly] = System.Reflection.Assembly.Load(assemblyName)
For Each m As [Module] In Asm.GetModules
For Each t As Type In m.GetTypes
For Each mi As MemberInfo In t.GetMembers
Console.WriteLine("{0}->{1}.{2}",mi.MemberType,t, mi.Name)
Next
Next
Next
End Sub

程式碼說明如下:
 Dim Asm As [Assembly] = System.Reflection.Assembly.Load(assemblyName)
此處我們呼叫Assembly的靜態方法Load,再傳入一組件顯示名稱(註2),則可傳回一Assembly的實體物件,再使用三個For迴圈一一找出相關的成員。
註2:組件的顯示名稱可能會包含易記名外,還可以選擇指定它的地區設定、版本號碼、公鑰值、和強式名稱…等。如:Name (,Loc=CultureInfo)(,Ver=Major.Minor.Build.Revision)(,SN=StrongName)。
 [Asm.GetModules]:透過Asm組件的GetModules方法取出在該組件內的所有模組,此範例只有一個模組名稱為『DynamicAssembly.exe』,您可使用Console.WriteLine(m.Name)來取得。
 [m.GetTypes]:透過m模組物件的GetTypes方法取出該模組內所有型別,此處亦只有一個型別名稱為『Form1』,可使用Console.WriteLine(t.Name)取得;但若您在此專案內加入圖二的Person類別,則此處會多一型別『Person』。
 [t.GetMembers]:透過t型別物件的GetTypes方法取出該型別內的所有成員。
 [mi.MemberType]:找出mi成員型態,如:Method、Property、Constructor、Event…等。
 [t]:相當於t.ToString為型別的名稱,此處為『DynamicAssembly.Form1』。
 [mi.Name]:即為成員的名稱。

(圖三)組件成員輸出列表


列舉方法的參數
在得知如何列舉類別成員後,接下來讓我們取出圖二Person類別內Save方法的參數成員,請參考下面程式碼,而輸出如圖四:

Private Sub btnListMethods_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnListMethods.Click
Dim PType As Type = Asm.GetType("DynamicAssembly.Person")
Dim saveMi As MethodInfo = PType.GetMethod("Save")
Dim savePars() As ParameterInfo = saveMi.GetParameters
Console.WriteLine("{0}方法參數成員有{1}個", saveMi.Name, savePars.Length)
Dim par As ParameterInfo
For Each par In savePars
Console.WriteLine("參數名稱:{0}的型別是{1},位於第{2}個", par.Name, par.ParameterType, par.Position)
Next
End Sub
End Class

程式碼說明如下:
 Dim PType As Type = Asm.GetType("DynamicAssembly.Person")
經由Assembly物件的GetType得到命名空間DynamicAssembly下的Person型別。
 PType.GetMethod("Save"):經由型別的GetMethod方法得到指定的方法成員。
 saveMi.GetParameters:經由MethodInfo的GetParameters方法得到參數集合。

(圖四)

至此我們了解如何使用定義在System.Reflection命名空間的核心項目,且利用它取得執行期間取得相關的資訊,若您曾使用過.NET Framework提供的工具:ILDasm.exe,我們已完成它提供的大部份瀏灠組件的功能,差別只在ILDasm.exe是顯示樹狀結構,而我們是呈現在輸出視窗中。

2009年8月8日 星期六

經由Internet Explorer以網址的方式來實現零接觸佈署1-2

RunPC 125期:利用.NET技術實現零接觸佈署(一)

實作第一隻NTD技術的.NET應用程式
在了解Web應用程式與NTD技術的優點、CAS與環境要求後,接著讓我們來實作一隻NTD技術的.NET應用程式,步驟如下:
1、 建立一Windows應用程式:
如同在VS.NET IDE內建立Windows應用程式一樣,於工具列上選『檔案』-->『新增』-->『專案』於新增專案對話盒中,選擇專案類型『Visual Basic專案』,範本選擇『Windows應用程式』,名稱內輸入『NTD_App_01』(如圖一)後按確定鈕。

(圖一)建立NTD_App_01Windows應用程式專案

接著更改表單的Text屬性為『NTD_App_01』,且在表單上建立一Label(Label1)與一Button(Button1)控制項,設定二控制項的屬性使其(如圖二)樣式:

(圖二)未修改前表單樣式

在Button1的Click事件內輸入以下的程式碼,它最主要的作用是在C:\Temp\目錄是建立一個MyTest.txt檔案,讓該NTD_App_01的Windows應用程式來操作檔案的建立、讀取、刪除…等動作,讓其每點一下後計數加一且加完的值呈現於Label1上。

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim path As String = "c:\temp\MyTest.txt"
Dim sw As StreamWriter
Dim fs As FileStream
Dim I As Int16
If File.Exists(path) = False Then
sw = File.CreateText(path)
sw.WriteLine("1")
sw.Flush()
sw.Close()
I = 1
Else
Dim sr As StreamReader = File.OpenText(path)
If sr.Peek() >= 0 Then
I = CType(sr.ReadLine(), Int16) + 1
End If
sr.Close()
File.Delete(path)
sw = File.CreateText(path)
sw.WriteLine(I)
sw.Flush()
sw.Close()
End If
Label1.Text = I.ToString
End Sub

接著請您按F5執行該程式,點選『計數』鈕可見(如圖三),開始計數…,同時可在C:\Temp目錄下找到MyTest.txt檔案,開啟該檔其內容值如Label1控制項呈現值,至此我們已完成一隻簡單的Windows應用程式開發,
2、 建立一虛擬目錄
於IIS管理工具預設的網站上按右鍵,『新增』-->『虛擬目錄』下一步,別名設為『NTD』下一步,目錄筆者設為C:\NTD資料夾內,下一步完成即可。
3、 複製Widows應用程式
將剛建立的Windows建立專案下的bin目錄找到『NTD_App_01.exe』檔案,將其複製到C:\NTD資料夾內。
4、初始化環境
刪除C:\Temp\MyTest.txt檔案。
點選:開始-->所有程式-->Microsoft Visual Studio .NET 2003-->Visual Studio .NET 工具-->開啟Visual Studio .NET 2003 命令提示字元,輸入gacutil /cdl命令(圖四)刪除所有Download Cache內的檔案(註3)。

(圖四) gacutil /cdl刪除Download Cache

註3:您也可以利用gacutil /ldl列出Download Cache 內的所有檔案;當然您也可以利用檔案總管連到C:\WINDOWS\assembly\Download資料夾下去觀看Download Cache內的檔案,因已下gacutil /cdl命令是故C:\WINDOWS\assembly\Download資料夾應用空資料夾。
5、用戶端透過IE執行該該程式
開啟IE於網址列上輸入http://172.16.70.123/NTD/ NTD_App_01.exe按Enter,會出現(如圖五),因筆者還未設定安全性原則,是故會呈現安全性資料警告,接著我們點選『計數』鈕,會出現(如圖六)例外視窗告知目前該程式並無檔案IO的權限,檢查C:\Temp資料夾,MyTest.txt並未建立。

(圖五)未設定CAS前出現的Microsoft .NET 安全性資訊警告


(圖六)無FileIO權限警告視窗

6、設定安全性原則
開啟控制項內的系統管理工具內的Microsoft .NET Framework 1.1 組態視窗,展開『.NET Framework 1.1』-->『我的電腦』-->『Runtime安全性原則』-->『電腦』-->『程式碼群組』-->『All_Code』點選右鍵新增程式碼群組-->名稱『Web123』-->選擇條件類型『URL』,URL輸入『http://172.16.70.123/NTD/*』-->指派使用權限集合給程式碼群組:我們使用現在的使用權限集合『FullTrust』-->完成後即可在程式碼群組下找到『Web123』的程式碼群組。
7、用戶端再次透過IE執行該該程式
同第五步驟,但圖已為(如圖七)且沒有安全性資料警告,點選『計數』鈕亦可正常執行;再檢查C:\Temp資料夾,MyTest.txt已被建立且內容值與Lable1控制項值相同,由此可見透過CAS的設定可加強.NET應用程式執行的安全性。接著您可以透過註3的說明由下gacutil /ldl命令(或瀏灠C:\WINDOWS\assembly\Download)即可以找出在Download Cache內的檔案,如圖八我們可以看出組件名稱、類型、版本、文化特性、程式碼基底…等資訊。
至此我們看見了NTD技術的佈署功能與如何設定程式碼存取安全,接下來讓我們看看NTD組件更新的功能。

(圖七)設定完CAS後執行視窗


(圖八)利用檔案總管觀察Download Cache內容

8、組件更新
於專案『NTD_App_01』上加入一按鈕,呈現目前總數,建立後將NTD_App_01.exe複製蓋掉C:\NTD\NTD_App_01.exe檔。如第七步驟用戶端再次透過IE執行該該程式,即可見(如圖九)程式已更新,而Download Cache的資料夾組件版本有二個(如圖十)。

(圖九)更新後表單執行視窗


(圖十) 利用檔案總管觀察Download Cache內容與多個版本

看過一個簡單的透過URL的NTD應用程式後,接著讓我們建立一個像早期VB6時ActiveX Document的NTD應用程式。

實作一個似ActiveX Document的NTD應用程式
這個主題描述如何在 Internet Explorer (IE) 中成功執行 Windows Form 控制項。在 IE 中 Windows Form 控制項不需使用者提示也不需登錄便能啟動,並能利用 Common Language Runtime (CLR) 的程式碼存取安全性。
在 Internet Explorer 中啟動 Windows Form 控制項有四個步驟:

• 建立 Windows Form 控制項。
• 建立含有 object 標記的 HTML 文件。
• 建立虛擬目錄並設定使用權限。
• 設定程式碼存取安全性。
• 執行控制項。

1、建立 Windows Form 控制項:
在專案『NTD_App_01』上加入一新專案『NTD_App_02』,專案類型請選擇『Windows控制項程式庫』,將NTD_App_01專案上的控制項與程式碼複製到NTD_App_02專案的UserControl1上,建立即可。
2、建立含有 object 標記的 HTML 文件

< html>
< script language="JScript">

function ChangeText() {
simpleControl1.LabelText = text1.value;
simpleControl1.Invalidate();
}
< /script>
< body>
< p>NTD_App_02
< br>< br>
< /body>
< object id="simpleControl1"
classid="http:NTD_App_02.dll#NTD_App_02.UserControl1"
height="300" width="300" VIEWASTEXT>
< param name="LabelText" value="0">
< /object>
< br>
< br>
< input type="text" id="text1">
< input type="button" value="Change Text" onclick="ChangeText()">
< /html>

3、建立虛擬目錄並設定使用權限
HTML 網頁必須位於您 Web 伺服器的 IIS 虛擬目錄中,並具有適當的使用權限。在這個範例中,Windows Form 控制項位於相同的目錄中,但它也可以被安裝於共用組件快取中。虛擬目錄上的執行使用權限必須設定為「指令」-- 如果執行使用權限設定為「指令與執行檔」,將無法正常啟動。
4、設定程式碼存取安全性
當您還未設定程式碼存取安全權限時,您將得到(如圖六)的警告訊息,設定方式有二步驟:
A、調整安全性:
開啟控制項內的系統管理工具內的Microsoft .NET Framework 1.1 組態視窗,展開『.NET Framework 1.1』-->『我的電腦』-->『Runtime安全性原則』點選右鍵選『調整安全性』在『安全性調整精靈』中(如圖十一)選擇『對這部電腦進行變更』下一步-->(如圖十二)調整『信任的網站』為完全信任,最後按完成。

(圖十一)安全性調整精靈


(圖十二)信任的網站調整

B、新增信任網站:
開啟Internet Explorer選『工具』-->『網際網路選項』-->於網網路選項對話盒中選取『安全性』頁纖,選擇『信任的網站』選擇『網站…』於信任網站的對話盒中加入『http://172.16.70.123/NTD』且將此區域內的所有網站需要伺服器驗證(https:)去除勾選,按確定即可。
5、 執行控制項
若要執行控制項,只需在您的虛擬目錄中將 Internet Explorer 指向 HTML 網頁。如果控制項未正常啟動,則可能需要重新啟動 Internet Explorer。若要檢視和啟動這個範例,請連結至http://172.16.70.123/NTD/NTD_App_02.html網頁。

總結:
這篇文章中我們介紹了.NET的NTD技術,且說明了如何設定程式碼存取安全,我們舉了二個例子加以說明,經由URL執行.NET應用程式,利用Download Cache機制佈署、更新程式,讓.NET的NTD應用系統俱備了Web(Thin Clinet)與Windows(Rich Client)應用程式的優點,與建立一個相似於早期ActiveX Document的NTD應用程式,再NTD這一系列的文章中的下幾篇中會為各位介紹,在應用程式中如何動態的載入Assembly、BITS、.NET Application Updater與VS.NET 2005重要新增功能之Click Once。

2009年8月4日 星期二

經由Internet Explorer以網址的方式來實現零接觸佈署1-1

RunPC 125期:利用.NET技術實現零接觸佈署(一)

相信絕大多數利用.NET開發的技術人員,一定是熟悉Web與Windows應用程式開發的兩棲人員,不再像以往僅懂ASP Web應用程式開發和VB Windows應用程式開發系統各有一定程度的門檻,踏入彼此領域皆需有一段調適期,而今在VS.NET IDE上開發系統,不僅整合Web、Windows應用程式,甚至Mobile相關(Pocket PC、Smart Phone…)的應用程式開發、Office與下一代資料庫Yunkon…等應用程式的開發,其開發環境幾乎無異,而其應用程式語言更是無異,學會VB.NET或C#…等任一種.NET程式語言,您就可以開發各平台上的應用程式;談了這麼多.NET開發應用程式的好處後,接著我們把焦點放在Web(Thin Client)與Windows(Rich Client)應用程式上;幾年前筆者剛接觸.NET不久,曾向同事斷言『瀏灠器將死』而引來一陣嘩然,或許當時太過武斷,但過了些時侯相關的文章與資料也陸續出來,當然不是很明確的指明瀏灠器將被淘汰,但也說明了Windows應用程式最難克服的佈署問題(也是WEB應用程式最為人所樂道的優點)已逐漸有解決方式,我們終於可以大聲和煩人不俱人性化的JavaScrip說NO了(註1)。
註1:筆者最近看了幾篇文章,產業都必須朝向以人本為中心的思考模式走,一些不俱人性化的事物都將被淘汰,程式設計的模式亦同。

重歸Windows應用程式(Rich Client)懷抱
在過去的幾年時間內,我們看見了軟體發展團隊從Windows開發平臺Client/Server到Web開發技術(包括HTML、ASP、JSP、PHP、ColdFusion和DHTML…等等)的大規模轉移,一下子似乎Web Solution成了唯一的解決方案,主管們似乎更順這個潮流繁事要求Web化,最大的原因莫過於佈署問題無法得到有效的解決與Dll Hell問題,而今,微軟在.NET平臺上發佈了一個名為零接觸佈署(No Touch Deployment,NTD)的新技術。這項技術會讓大批開發者又從Web開發重回Windows表單開發模式;而在開始談什麼是NTD應用程式時,我們先回顧一下Web應用程式的優點與缺點。

Web應用程式的優點與缺點
Web應用程式最大的優點莫過於安裝佈署、維護的簡易性、用戶端需求小(只要俱備瀏灠器即可)和開發平台無關等三個優點;與Windows應用程式比較起來,Web的佈署只要針對Server端的機器加以佈署更新新的應用程式即可,而不像Windows應用程式需要針對每台用戶端機器加以佈署更新,佈署上的成本顯而易見Web應用程式遠少於Windows應用程式,這也是為什麼企業主願意犧牲Windows應用程式上那麼多優點而選擇Web應用程式的主因;其二Web應用程式對用戶端的需求甚低,只要用戶端俱備瀏灠器即可在一來一回間執行Web應用程式;而最後一點隨著技術的延伸與擴充(ActiveX、XML Island…等),這個優勢也應不俱備了,除非您的Web Site全部使用純HTML來架設,否則您必須針對特定的流灠器來開發,若各位是Client Script的撰寫者,您一定痛恨一個簡單的檢查,卻需複雜判斷瀏灠器的種類接著判斷瀏灠器的版本…等。接著讓我們看看Web應用程式的優點背後它帶給我們的限制,首先不外是使用者介面的不友善性和用戶端與Web Server間一來一回效能上的遺失、無離線執行能力、無法安全、有效的利用Client端上的資源;而Web應用程式的缺點正是Windows應用程式的優點,接下來讓我們開發探討同時俱備Thin Cleint和Rich Client優點的應用程式的作法—零接觸佈署。

零接觸佈署(No Touch Deployment,NTD)
何為零接觸佈署呢?它是微軟在.NET上佈署的新技術,相似於今時Web應用程式的佈署方式,它可以在Internet上執行而使用者無需感知應用程式佈署安裝到用戶機器,即是使用者可以透過IE經由URL或一個連結連結到Web Servcer上執行.NET應用程式,而不需手動安裝它,它會自動於背景中下載,然後執行於使用者的電腦上;而NTD在更新方面就如同Web應用程式一樣簡便,只需將新版的程式蓋掉Web站台上舊的程式即可,每個用戶端再次執行時它會自動比較版本時間戳記,若有新版本一樣會自動下載執行,是故用戶端會如同Web程式一樣執行到最新的應用程式。NTD技術它俱備了Web開發的所有優點而無需犧牲用戶介面設計,也沒有Web開放所帶來的困難。當然有些了解Java的程式設計師喜歡拿Java Web Star來與NTD技術比較,雖然有些地方它們確有相似之處,但安全性方面NTD技術提供了更完整的程式碼存取安全機制(Code Access Security,CAS),這一點來說NTD技術比Java Web Star強大許多。為了充分習得NTD技術的優點,了解CAS是必然的,這是因為在網路上的應用程式要在用戶端上執行,必須要取得適當的權限。

程式碼存取安全機制(Code Access Security,CAS)
程式碼存取安全性是協助限制程式碼存取受保護的資源和作業的一項機制。系統管理者依程式碼的來源不同分別給予程式碼不同的信任等級,各等級可以存取不同的資源,在 .NET Framework 中,程式碼存取安全性會執行以下的功能:

• 定義使用權限和使用權限集合以表示存取各種系統資源的權限。
• 使管理員可以依據程式碼群組的使用權限集合來配置安全性原則。
• 使程式碼會要求執行時所需的使用權限,以及可以用來協助它執行的使用權限,並指定程式碼不能擁有的使用權限。
• 依據程式碼所要求的使用權限以及安全性原則允許的作業,授與使用權限給每一個已載入的組件。
• 使程式碼可以要求它的呼叫端具有特定使用權限。
• 使程式碼要求它的呼叫端處理數位簽章,而只允許特定組織或站台的呼叫端可以呼叫受保護的程式碼。
• 比較呼叫堆疊上每一個呼叫端授與的使用權限和呼叫端必須擁有的使用權限,來加強 Run Time 時的程式碼限制。

其應用原理不外乎是先透過安全性原則(.NET提供四種層次:企業、電腦、使用者和Application Domain)設定一組組的使用權限集合(Permission Set),再把這些權限集合授予至那些符合識別項(Evidence)註2的應用程式群組。經由權限授予後,應用程式才知道它被管理者授予了那些權限,有了權限後應用程式才得以執行某些動作與存取某些特殊的資源;即應用程式要存取某些資源時.NET Framework會循整個程式呼叫鏈來檢查每個物件的甬有權限,皆擁有存取該資源的權限時,應用程式才可以正確執行。

註2:可以當作應用程式的識別項分二大類:一、針對某個組件:(1)組件的強勢名稱(Assembly Strong Name)、(2)以某個應用程式的密碼編譯雜湊來區別。二、多個組件標識:(1)軟體供應商的簽章、(2)組件來源的區域(Internet、Intranet…等)、(3)組件來源位置(URL或UNC路徑下)。

用戶端環境需求
介紹完何謂NTD技術與CAS後,接著讓我們談談在用戶端要執行NTD的.NET應用程式的需求,既是.NET程式.NET Framework自然是不可或缺的,且至少要是.NET Framework 1.0 SP2,建議.NET Framework 1.1環境更佳;當然若要透過URL來執行請安裝Internet Explorer 5.0.1以上版本;而伺服器端只要支援HTTP的Web Server即可,當然還是建議您使用IIS 5.0以上會較佳。
加入書籤: MyShare HemiDemi Baidu Google Bookmarks Yahoo! My Web PChome Del.icio.us Digg technorati furludn bookmark 其他更多書籤

BOOKS:New and Upcoming