發(fā)布日期: 2006-08-22 | 更新日期: 2006-08-22
Ted Pattison下載本文的代碼:
BasicInstincts2006_08.exe (878KB)
本頁內(nèi)容
控制頁面級別的區(qū)域性設(shè)置使用配置文件跟蹤語言首選項ASP.NET 2.0 中的資源文件使用本地資源在 DLL 項目中嵌入資源顯示本地化圖像總結(jié)在上一期專欄文章中,我介紹了資源文件在 .NET 開發(fā)中的使用。我將一個 Windows® Forms 應(yīng)用程序進(jìn)行了國際化,并將其本地化以適用于使用不同語言的用戶。本月我將討論 ASP.NET 2.0 中網(wǎng)站的本地化。
我假設(shè)您熟悉區(qū)域性 UI 和區(qū)域性設(shè)置、CultureInfo 對象、資源文件、ResourceManager 類和自動生成的強(qiáng)類型化資源類。并且,我還假設(shè)您基本了解 Microsoft® .NET Framework 是從默認(rèn)程序集、還是從本地化衛(wèi)星程序集加載資源的確定機(jī)制。如果您需要更多有關(guān)這些主題的背景知識,可先讀一下我在 2006 年 5 月發(fā)表的 Basic Instincts(英文)專欄文章,然后再繼續(xù)閱讀本文。
控制頁面級別的區(qū)域性設(shè)置
利用 ASP.NET 2.0 可輕松地逐頁更改區(qū)域性設(shè)置。您只需將 UICulture 和 Culture(區(qū)域性)屬性添加到 .aspx 等類似頁面內(nèi)的 Page 指令即可。
<%@ Page UICulture="fr" Culture="fr-BE" %>
在頁面生命周期的早期,一個以這些屬性設(shè)置運(yùn)行的 .aspx 頁,將使用合適的 CultureInfo 對象初始化當(dāng)前線程的 CurrentUICulture 屬性和 CurrentCulture 屬性。在測試期間,如果將以上所示屬性添加到一個 .aspx 文件,然后再添加一個內(nèi)置的 ASP.NET Web 控件(如 Calendar(日歷)控件),您會立即看到一切運(yùn)轉(zhuǎn)正常,如圖 1 所示。左側(cè)的 Calendar(日歷)控件已呈現(xiàn)在區(qū)域性設(shè)置為 en-US 的頁面上,而右側(cè)的 Calendar(日歷)控件則呈現(xiàn)在區(qū)域性設(shè)置為 fr-BE 的頁面上。
圖 1 本地化的日歷控件
然而,在大多數(shù)生產(chǎn)網(wǎng)站中,像這樣將特定區(qū)域性設(shè)置硬編碼到頁面中是行不通的。而使用不同語言的用戶將看到同一頁面的不同的本地化內(nèi)容。如果您向 UICulture 和 Culture(區(qū)域性)屬性都分配一個“auto”值,則 ASP.NET 將基于每個請求自動為您初始化區(qū)域性設(shè)置。
<%@ Page UICulture="auto" Culture="auto" %>
ASP.NET 通過檢查瀏覽器發(fā)送的 HTTP 標(biāo)題來初始化這些設(shè)置。通過更改 Internet Options(Internet 選項)對話框中的語言首選項設(shè)置,您可以在 Internet Explorer® 中測試頁面的不同本地化版本。
通常,您會想要站點中的所有頁面都符合相同的區(qū)域性設(shè)置。您可以為 UICulture 和 Culture(區(qū)域性)屬性分配一個站點范圍的“auto”值,這樣就不必分別為每個頁面進(jìn)行分配了。只需將以下元素添加到位于站點的根處的 web.config 文件中即可:
<globalization uiCulture="auto" culture="auto" />
除了自動設(shè)置以外,您還可以為 ASP.NET 指定一個默認(rèn)區(qū)域性(如果它無法找到 HTTP 標(biāo)題來確定用戶的首選區(qū)域性):
<globalization uiCulture="auto:en" culture="auto:en-US" />
返回頁首使用配置文件跟蹤語言首選項
雖然自動設(shè)置的確會使事情變輕松,但它對于用戶來說并不總是那么方便。例如,假設(shè)某位用戶更愿意閱讀英語版的技術(shù)類網(wǎng)站和法語版的商業(yè)類網(wǎng)站。當(dāng)他在兩個站點之間來回轉(zhuǎn)換時,需要不斷地更改瀏覽器設(shè)置,他會感到非常煩惱。該用戶將非常喜歡能夠讓其選擇語言首選項的網(wǎng)站。
要了解如何生成能夠使用戶更輕松地在不同語言間來回切換的 UI 和支持性實現(xiàn),可以下載本月的代碼示例 - 一個名為 LitwareWebApp 的 ASP.NET 2.0 網(wǎng)站。它的 UI 如圖 2 所示。
圖 2a 英語版本
圖 2b 本地化版本
LitwareWebApp 站點使用 ASP.NET 2.0 中引入的新的配置文件功能,來跟蹤用戶的語言首選項。您可以添加一個名為 LanguagePreference 的基于字符串的配置文件屬性,通過將以下元素添加到站點的 web.config 文件,來支持匿名識別:
<configuration><system.web><anonymousIdentification enabled="true"/><profile><properties><add name="LanguagePreference" type="string"defaultValue="Auto" allowAnonymous="true" /></properties></profile></system.web></configuration>
LitwareWebApp 站點被設(shè)計為具有“母版頁”內(nèi)的標(biāo)準(zhǔn)布局,該“母版頁”包含一個名為 lstLanguage 的 RadioButtonList 控件。請注意,該控件不僅顯示友好的語言名稱(如美國英語和比利時法語),而且還會使用 SelectedValue 屬性跟蹤真正的區(qū)域性名稱(如 en-US 和 fr-BE)。當(dāng)用戶更改語言首選項時,lstLanguage 控件的 SelectedIndexChanged 事件會引發(fā)并執(zhí)行以下代碼來更新 LanguagePreference 配置文件屬性:
Profile.LanguagePreference = lstLanguage.SelectedValueResponse.Redirect(Me.Request.Url.AbsolutePath)
如果調(diào)用 Response.Redirect,則會強(qiáng)制發(fā)生一次從瀏覽器到 Web 服務(wù)器的新往返程,從而在使用所需的語言首選項設(shè)置了配置文件屬性后,重新啟動頁面的生命周期。
之后要處理的事情是以編程方式,于合適的時間在頁面生命周期內(nèi)調(diào)整區(qū)域性設(shè)置。在 ASP.NET 2.0 中執(zhí)行此操作的正確方法是替換名為 InitializeCulture 的 Page 類。頁面生命周期已被設(shè)計為,在頁面本身或其任何子控件使用本地化資源進(jìn)行任何工作前,始終調(diào)用 InitializeCulture。
示例站點的設(shè)計要求您向站點內(nèi)的各頁面添加一個替換的 InitializeCulture 實現(xiàn)。不幸的是,您無法在“母版頁”級別上替換 InitializeCulture 方法,因為 MasterPage 類不會從 Page 類繼承。另外,為網(wǎng)站內(nèi)的各頁面分別替換 InitializeCulture 方法非常冗長乏味。會導(dǎo)致許多重復(fù)實現(xiàn),從而引發(fā)嚴(yán)重的維護(hù)問題。
一個用于初始化區(qū)域性設(shè)置的站點范圍的更有效方法是,創(chuàng)建一個公共的 Page 派生基類,然后讓所有 .aspx 頁文件從該類繼承,我在 LitwareWebApp 示例站點中就是這么做的。我的名為 LitwarePage(請參閱
圖 3)的 Page 派生基類是在名為 LitwarePage 的源文件中定義的,并且已被添加到 App_Code 目錄,這樣一來它就可以由 ASP.NET 自動編譯并可用于當(dāng)前網(wǎng)站中的其他代碼。
創(chuàng)建了 Page 派生基類后,即可將 .aspx 頁定義更新為從該類而不是從標(biāo)準(zhǔn) Page 類派生。例如,您可以在 default.aspx.vb 內(nèi)對局部類進(jìn)行此類修改。
Partial Class _Default : Inherits LitwarePage'*** 頁面類定義位于此處End Class
此時,我擁有一個可以跟蹤用戶語言首選項并可基于每個請求初始化區(qū)域性設(shè)置的網(wǎng)站?,F(xiàn)在,我必須使用資源文件為 ASP.NET 2.0 網(wǎng)站本地化字符串文字,以便能夠滿足使用不同語言的用戶的需求。
返回頁首ASP.NET 2.0 中的資源文件
由于在默認(rèn)情況下,Visual Studio® 2005 不使用項目來管理 ASP.NET 2.0 網(wǎng)站,所以將不會存在項目級別的資源文件,就像 Windows Forms 應(yīng)用程序或類庫 DLL 中那樣。相反,您必須顯式創(chuàng)建資源文件并將其添加到您的網(wǎng)站。而且,您還必須使用隨 ASP.NET 2.0 引入的特殊文件夾:包含全局資源的資源文件應(yīng)被添加到 App_GlobalResources 文件夾,而特定于某個文件的本地資源則應(yīng)被添加到 App_LocalResources 文件夾。全局資源就是那些來自于頁面及其他文件(如站點圖)、可以在站點范圍基礎(chǔ)上使用的資源。支持本地資源的 ASP.NET 文件類型包含頁(.aspx 文件)、母版頁(.master 文件)和用戶控件(.ascx 文件)。
不同于 ASP.NET 2.0 的另一點是,您不必像在開發(fā)國際化的 Windows Forms 應(yīng)用程序時那樣提前編譯資源。相反,ASP.NET 運(yùn)行時會準(zhǔn)時將全局和本地資源文件編譯到 DLL 中,就像 .aspx 文件那樣。這是一種強(qiáng)大的功能,因為公司只需將 .resx 文件 XCOPY 到一個 Web 生產(chǎn)服務(wù)器上,即可為新語言添加本地化支持。
讓我們在使用 Visual Studio 2005 的 ASP.NET 2.0 站點中,來完成一個創(chuàng)建和使用全局資源文件的示例。您可以先選擇 Add New Item(添加新項)命令,然后再選擇 Resource File(資源文件),來創(chuàng)建一個新的全局資源文件。
當(dāng)您單擊 Add(添加)按鈕創(chuàng)建一個新的全局資源文件時,Visual Studio 2005 會用一個對話框?qū)δM(jìn)行提示,建議您將新的資源文件放置在 App_GlobalResources 目錄內(nèi)。單擊 Yes(是)。如果您將其置于他處,則 ASP.NET 便不會將資源文件自動編譯到 DLL 中。
在 ASP.NET 中使用資源文件與在 Windows Forms 應(yīng)用程序中相同。首先創(chuàng)建一個資源文件,其字符串文字已本地化為默認(rèn)區(qū)域性設(shè)置。在我們的示例網(wǎng)站中,有一個用于該目的的全局資源文件,該文件的名稱為 Litware.resx,如圖 4 所示。在您添加了所有采用默認(rèn)區(qū)域性設(shè)置的指定字符串后,即可復(fù)制該資源文件并將其重命名,例如重命名為 Litware.fr.resx 以提供法語的本地化字符串。您還可以復(fù)制該法語資源文件并將其重命名為 Litware.fr-BE.resx,以維護(hù)已局部本地化為比利時法語的字符串。
圖 4 本地化資源
在資源文件中添加和維護(hù)指定字符串非常容易,因為 Visual Studio 2005 提供了方便易用的資源編輯器,如圖 5 所示。請記住,資源文件并不僅限于本地化字符串。您可以添加其他類型的資源,如圖像文件、級聯(lián)樣式表和客戶端 JavaScript 文件。
圖 5 Visual Studio 2005 資源編輯器
現(xiàn)在,我們來創(chuàng)建從全局資源文件檢索指定字符串的頁面。這做起來非常容易,就像是在開發(fā)一個國際化的 Windows Forms 應(yīng)用程序時,無需直接對 .NET 提供的 ResourceManager 類進(jìn)行編程。因為 ASP.NET 和 Visual Studio 2005 可以在后臺為每個全局資源文件生成一個強(qiáng)類型化資源類,并通過 IntelliSense® 使其變?yōu)榭捎谩?div style="height:15px;">
可通過一個駐留在名為 Resources(資源)的頂級命名空間內(nèi)的強(qiáng)類型化類,來訪問您添加到全局資源文件中的指定字符串。它使用一行代碼,將一個本地化的字符串分配給控件的屬性值:
lblApplicationName.Text = Resources.Litware.ApplicationName
除了以編程的方式訪問外,ASP.NET 2.0 還引入聲明性語法,您可以使用它將指定的字符串綁定到頁或控件的屬性。該語法涉及使用美元符號 ($),其后緊跟資源命名空間、資源文件名和字符串名:
<%$ Resources:Litware, ApplicationName %>
例如,如果您想將名為 ApplicationName 的字符串綁定到 .aspx 頁內(nèi)一個標(biāo)簽的 Text 屬性,您可以像這樣編寫標(biāo)記:
<asp:Label ID="lblApplicationName" runat="server"Text="<%$ Resources:Litware, ApplicationName %>" />
Visual Studio 2005 還提供一個名為 Expression Builder 的方便易用的工具,如圖 6 所示。該實用程序可幫助您生成將資源文件中指定字符串綁定到控件或頁屬性時所需的語法。在您用指定的字符串添加了一個或多個全局資源文件后,即可通過將 .aspx 頁置于設(shè)計視圖,并通過 Property(屬性)表訪問 Expressions 屬性,來訪問 Expression Builder。
圖 6 Expression Builder
請注意,聲明性資源綁定表達(dá)式不僅限于 .aspx 文件、.ascx 文件和 .master 文件。也可用于本地化 Web.sitemap 文件中定義的站點圖中的字符串文字。
圖 7 顯示來自 LitwareWebApp 網(wǎng)站中站點圖的 XML,它用于本地化該站點導(dǎo)航菜單中顯示的鏈接標(biāo)題。
返回頁首使用本地資源
本地資源文件包含用于站點內(nèi)基于文件的單獨項的資源,如頁、母版頁或用戶控件。每個本地資源文件都必須正確命名并添加至 App_LocalResources 文件夾,以由 ASP.NET 進(jìn)行編譯。
本地資源文件的命名,應(yīng)與它要為之提供資源的基于文件的項一致。例如,包含用于 AddCustomer.aspx 頁的默認(rèn)區(qū)域性資源的本地資源文件,應(yīng)命名為 AddCustomer.aspx.resx。包含法語資源的本地資源文件應(yīng)命名為 AddCustomer.aspx.fr.resx。
在您將指定的字符串添加到本地資源文件后,即可通過三種方式從頁面或用戶控件內(nèi)訪問它們。第一,您可以通過編程方式進(jìn)行訪問。第二,您可以使用顯式語法,以聲明的方式綁定到其上。第三,您可以使用隱式語法,以聲明的方式綁定到其上。下面開始逐個探討這些方法。
假設(shè)您已創(chuàng)建了一個本地資源文件,來本地化頁面 AddCustomer.aspx 上顯示的所有控件標(biāo)題。要本地化該頁提交按鈕上顯示的標(biāo)題,您可以創(chuàng)建一個名為 btnSubmit.Text 的本地化字符串。在將該指定字符串添加到本地資源文件后,您即可通過以下調(diào)用 GetLocalResourceObject 方法和將返回值轉(zhuǎn)換為字符串的代碼來進(jìn)行訪問:
'*** AddCustomer.aspx.vb 內(nèi)的代碼btnSubmit.Text = _Me.GetLocalResourceObject("btnSubmit.Text").ToString()
此代碼不如以前顯示的代碼好,以前顯示的代碼是從使用強(qiáng)類型化類的全局資源訪問指定的字符串。本地資源文件沒有相關(guān)聯(lián)的強(qiáng)類型化類,所以您無法從 IntelliSense 中獲益,而且必須在調(diào)用 GetLocalResourceObject 時,顯式地轉(zhuǎn)換基于對象的返回值。
如果您要使用顯式聲明性綁定語法,則其使用方式與使用全局資源時大致相同。唯一不同的是您使用本地資源時,可以忽略資源文件的名稱:
<asp:Button ID="btnSubmit" runat="server"Text="<%$ Resources:btnSubmit.Text %>" />
隱式聲明性綁定語法是功能最強(qiáng)大的選項。首先將名為 meta:resourcekey 的特殊屬性添加到控制標(biāo)記,或添加到一個 ASP.NET 指令,如 Page、Master 或 Control。例如,如果您想通過 .aspx 文件中的 Button(按鈕)控件來使用隱式聲明性綁定語法,您可以像這樣編寫標(biāo)記:
<asp:Button ID="btnSubmit" runat="server"meta:resourcekey="btnSubmit" />
在您添加了 meta:resourcekey 屬性后,就只剩一件事需要考慮了,即確保本地資源文件中的字符串具有正確的名稱。在我的示例中,ASP.NET 會自動加載名為 btnSubmit.Text 的本地化字符串,并將其分配給名為 btnSubmit 的控件的 Text 屬性。
關(guān)鍵在于,隱式綁定的基礎(chǔ)是,創(chuàng)建的字符串應(yīng)具有與 meta:resourcekey 屬性定義的目標(biāo)和屬性的名稱相匹配的名稱。本示例中,由于 meta:resourcekey 是面向 btnSubmit 的,所以只需將更多指定的字符串添加到本地資源文件中,這樣您不僅可以綁定到 Text,而且還可以綁定到其他幾個屬性值,如圖 8 所示。
圖 8 添加指定的字符串
請注意,Visual Studio 2005 可以在設(shè)計視圖編輯器中打開頁、用戶控件或母版頁時,在 Tools(工具)菜單中提供一個名為 Generate Local Resource(生成本地資源)的方便易用的命令。該命令可自動創(chuàng)建默認(rèn)區(qū)域性的本地資源文件。還可在頁面中添加 meta:resourcekey 屬性,并在本地資源文件中創(chuàng)建相應(yīng)的字符串值,來充當(dāng) meta:resourcekey 屬性項目的目標(biāo)。
最后,請注意:有一個名為 Localize(本地化)控件的 ASP.NET 2.0 新組件,可以使您本地化 .aspx 頁上的任何元素。它提供一種不由其基類提供的設(shè)計時間功能:Literal(文字)控件;尤其是,Localize(本地化)控件提供了靜態(tài)內(nèi)容的設(shè)計時間編輯,以便您能夠在頁面設(shè)計模式下工作時查看默認(rèn)值。
返回頁首在 DLL 項目中嵌入資源
我將暫時撇開國際化和本地化主題,先討論一種在類庫 DLL 中使用嵌入資源的新 ASP.NET 技術(shù)。該技術(shù)允許您在 DLL 中嵌入圖像文件、級聯(lián)樣式表文件和 JavaScript 文件,并通過 DLL 在托管 Web 服務(wù)器上加以提供。
請注意,該技術(shù)需要使用一個面向 ASP.NET 2.0 網(wǎng)站的類庫 DLL。這一新功能是由 ASP.NET 團(tuán)隊特別添加的,目的是為服務(wù)器端的控件創(chuàng)建者提供一種更好的方式,使他們可以在分配自定義控件和 Web 部件的同時分配資源文件。不必將資源文件與 DLL 一起分配,也不必確保他們被復(fù)制到托管 Web 服務(wù)器上一個可訪問的路徑,資源文件現(xiàn)在可以在 DLL 內(nèi)自行分配,并可通過運(yùn)行時由 ASP.NET 生成的 URL 加以提供。
LitwareWebApp 網(wǎng)站包含一個名為 LitwareWebComponents 的類庫 DLL 項目,該項目演示了這一技術(shù)。在該項目內(nèi),有一個名為 LitwareSlogan.png 的圖像文件已被作為資源嵌入。您可以通過將文件的“生成操作”更改為“嵌入的資源”,將資源嵌入到一個程序集中,如圖 9 所示。
圖 9 嵌入資源
要提供對 DLL 內(nèi)一個嵌入的資源文件的基于 Web 的訪問,您必須添加一個名為 WebResource 的程序集級別的屬性。當(dāng)您添加 WebResource 屬性時,必須包含資源文件的限定名及其 MIME 類型。在 Visual Basic® 類庫 DLL 項目中,限定資源文件名包含項目名。
'*** 在 AssemblyInfo.vb 內(nèi)Imports System.Web.UI<Assembly: WebResource( _"LitwareWebComponents.LitwareSlogan.png", "image/png")>
WebResource 屬性允許您為 ASP.NET 運(yùn)行時提供所需的元數(shù)據(jù),以通過使用可在運(yùn)行時生成的 URL,從 DLL 中檢索資源文件。要從服務(wù)器端控件內(nèi)的代碼生成資源文件的 URL,您可以調(diào)用一個名為 GetWebResourceUrl 的方法,如
圖 10 所示。
這是使該技術(shù)得以運(yùn)行的后臺情況。一個對 GetWebResourceUrl 的調(diào)用生成一個指向名為 WebResource.axd 的內(nèi)置 HTTP 處理程序的 URL。這個動態(tài)生成的 URL 還包含一個查詢字符串,來識別目標(biāo) DLL 的名稱和嵌入的資源文件。通過加載一個名為 AssemblyResourceLoader 的自定義 HttpHandler 類,ASP.NET 運(yùn)行時可以響應(yīng) WebResource.axd 的請求。
當(dāng)調(diào)用 AssemblyResourceLoader 類以從 DLL 加載資源文件時,它可以讀取由 WebResource 屬性提供的元數(shù)據(jù)。AssemblyResourceLoader 類已被實現(xiàn)以從 DLL 的圖像中提取請求資源文件,并將其引流回調(diào)用程序。AssemblyResourceLoader 類甚至提供緩存算法,可在它被加載到前端 Web 宿主內(nèi)存后,在多個請求中重復(fù)使用同一資源文件。
返回頁首顯示本地化圖像
雖然使用嵌入的資源文件和 WebResource 屬性會具有強(qiáng)大的功能,但是仍然存在一些明顯的局限性。首先,您只能在面向 ASP.NET 2.0 網(wǎng)站的 DLL 項目內(nèi)使用該技術(shù)。您無法在 ASP.NET 2.0 網(wǎng)站內(nèi)直接使用該技術(shù)。第二,該技術(shù)實際上并不支持任何形式的本地化。如果您的網(wǎng)站具有諸如圖形圖像和級聯(lián)樣式表等已經(jīng)本地化的資源文件,則您將不得不采用其他方法。
LitwareWebApp 網(wǎng)站顯示一個名為 LitwareSlogan.png 的圖形圖像。該網(wǎng)站可依據(jù)當(dāng)前用戶更喜歡英語還是法語來顯示不同版本的圖像。盡管 ASP.NET 2.0 不直接支持本地化圖像文件,但它也不需要過多的自定義代碼來完成所需的效果。
您可以將本地化版本的圖像文件添加到本地化版本的全局資源文件,并以此作為開始。例如,英語版本的 LitwareSlogan.png 已被添加到名為 Litware.resx 的全局資源文件,而法語版本的 LitwareSlogan.fr.png 則已添加到 Litware.fr.resx。這兩個資源文件中的資源擁有一個相同的名稱:LitwareSlogan。
當(dāng)不同本地化版本的全局資源文件中含有本地化版本的圖像文件時,您可以使用名為 LitwareSlogan.ashx 的自定義處理程序文件,基于用戶的語言首選項來有條件地進(jìn)行加載,如
圖 11 所示。
LitwareSlogan.ashx 中定義的自定義處理程序類可使用您以前在自定義 InitializeCulture 方法中看到的類似邏輯,在從全局資源文件中檢索圖像文件以前,初始化當(dāng)前線程的 CurrentUICulture 設(shè)置。您可能會注意到,要加載正確的資源文件,您必須初始化當(dāng)前線程的 CurrentUICulture 屬性,但不必初始化 CurrentCulture 屬性。
在該自定義處理程序正確初始化了 CurrentUICulture 設(shè)置之后,它即可通過 Litware.resx 的強(qiáng)類型化資源類來訪問圖像文件。然后,便只需將圖像文件的數(shù)位編寫到 HTTP 響應(yīng)流。顯示本地化圖像的最后步驟是,將 LitwareSlogan.ashx URL 分配到站點內(nèi)任何頁面上一個圖像控件的 ImageUrl 屬性。
返回頁首總結(jié)
ASP.NET 2.0 使國際化網(wǎng)站和資源變得更加容易。通過檢查瀏覽器發(fā)送的 HTTP 標(biāo)題,可在網(wǎng)站內(nèi)輕松地初始化頁面的區(qū)域性設(shè)置。而且,還可輕松地設(shè)計更加復(fù)雜的機(jī)制,使用戶能夠通過配置所需的語言首選項來個性化其體驗。
請將您要提交給 Ted 的問題和意見發(fā)送至
instinct@microsoft.com。
Ted Pattison 身為作者兼培訓(xùn)人員的 Ted Pattison 最近成立了 Gorilla Training,該公司致力于提供有關(guān) SharePoint 技術(shù)的、極具實力的開發(fā)人員培訓(xùn)。Ted 還在為 Microsoft Press 編寫一本名為 Inside Windows SharePoint Services 3.0 的書。
本文摘自
2006 年 8 月出版的
《MSDN Magazine》。