本文章是由機器翻譯。

Microsoft .NET Framework

移轉舊版 .NET 程式庫以新型平台為目標

Josh Lane

Microsoft.NET 框架的儘管如此強項之一是各種各樣的協力廠商開放源碼和商業庫的目標平臺。它是.NET 開發生態系統,你不僅是偉大的 Api 的.NET 框架本身,從選擇的成熟的證明但也數以千計的非 Microsoft 庫,用於繪圖網格在桌面應用程式中,在中間存儲結構化的資料的檔案系統,和一切的 HTTP 要求提供服務。事實上,最受歡迎的.NET 代碼庫快速審閱顯示超過 32,000 專案對 CodePlex,超過 5,000 的代碼樣本上 code.msdn.microsoft.com 和 NuGet 畫廊上的超過 10,000 獨特包 !

新的軟體平臺的出現如 Windows Phone 8 和 Windows 8 有可能以新的生命注入這些嘗試-和-真正的基本代碼。.NET 庫,能為你們服務以及為在桌面和伺服器上的年同樣可以證明 (和有時更) 在這些新的環境中非常有用 — — 只要你願意花費精力遷移需要針對這些新的平臺。傳統上這類任務可以既困難又費事,但Visual Studio2012年雖然仍然需要護理和明確的規劃,確保成功,有幾個功能,儘量減少可能出現的困難和跨平臺,最大限度地重用的機會。

在這篇文章中,我將探討在真實世界的開放原始碼英鎊 NoSQL 物件-向前遷移過程中發現的挑戰­面向的資料庫 (物件導向資料庫) 專案。我會走你通過圖書館的簡要概述,共用遇到的遷移障礙和解決方案來克服這些困難,然後考慮一些模式和最佳做法建議您可以利用您自己庫遷移努力中的換行。

英鎊是什麼?

英鎊是羽量級的 NoSQL 資料存儲庫,它提供快速、 索引檢索的.NET 類實例。此外支援更新、 刪除、 備份和還原、 截斷和類似,儘管像它不會提供一般-其他 NoSQL 技術­宗旨,SQL 語言基礎的查詢設施。相反,"查詢"的概念由一組不同的、 有序操作組成:

  • 第一,檢索的預定義的鍵或索引映射到懶載入的類實例的集合。
  • 下一步要做初始快速篩選可能整個結果集的鍵的集合索引。
  • 最後,使用標準LINQto 針對現在篩選鍵-值對的物件查詢來進一步優化結果。

清楚地使用模型為英鎊 (和類似的 NoSQL 資料庫) 從一個傳統的關係資料庫,像SQL Server所提供的不同。缺乏正式的不同的查詢語言似乎對新人特別奇怪。事實上,這是由 NoSQL 作為強度,考慮到潛在的複雜性和開銷與映射的投入和產出之間的查詢世界和世界的代碼相關聯的擁護者提出的。在像英鎊 NoSQL 解決方案中,沒有映射,因為查詢和代碼是一樣的。

英鎊的前前後後充分治療是超出了本文的範圍 (見Jeremy Likness' 條,"英鎊為孤立存儲在 Windows Phone 7," msdn.microsoft.com/magazine/hh205658 進一步的詳細資訊),但我會突出一些關鍵優勢和權衡,要牢記:

  • 它具有占地面積小 (大約在磁片上的 150 K) 和非常適合在進程駐留。
  • 它工作的--預置與可序列化的.NET 類型的標準範圍。
  • 一套觀念所需的基本功能是小 ; 您可以啟動並運行與英鎊為五條線的 C# 代碼中。
  • 傳統的資料庫功能,如精確的安全,串聯更新和刪除操作,可配置鎖定語義原子性、 一致性、 隔離持續性 (ACID) 擔保、 和英鎊中不支援等。如果你需要這些功能,您應該考慮一個完整的關係像SQL Server引擎。

英鎊的建立者 (我的 Wintellect 同事Jeremy Likness) 打算從一開始它面向多個平臺 ; 他為.NET 框架 4、 Silverlight 4 和 5 和 Windows Phone 7 創建二進位檔案。所以在考慮時要更新英鎊,目標.NET 框架 4.5、 Windows Phone 8 和 Windows 應用商店的應用程式所需的工作,就知道該體系結構可以借給本身,這種努力,但我不知道到底該專案會引起。

我在這篇文章中概述的意見是我經驗更新英鎊目標.NET 框架 4.5、 Windows Phone 8 和 Windows 應用商店的應用程式的直接結果。雖然我的旅程的詳細資訊的一些特定于英鎊專案,還有很多有關的範圍廣泛的專案和微軟生態系統中的移植工作。

挑戰和解決方案

作為我移植到新的目標平臺,英鎊,我面臨的障礙反映了幾個大類下,我可以出現了兩個腫塊我所遇到的問題和提供更一般性的指導,對任何人進行此類專案。

容納不同的設計哲學潛在問題的第一套是有點哲學性質的雖然它對你就會花費的整體遷移工作產生真正的影響。問問自己:"到何種程度上不會的體系結構和設計的我想要遷移的庫與對齊的常見模式和新目標平臺的使用模型?"

這不是一個容易的問題要解決,和整潔、 一刀切的答案是可望而不可及。你聰明、 自訂的 Windows 表單的佈局管理器可能很難或無法向Windows Presentation Foundation(WPF) 埠。Api 是肯定不同的但它是非常不同的核心設計理念和控制管理的概念,這些都可能在長期絆倒你的兩個世界的定位。作為另一個例子,很好的經典的鍵盤和滑鼠輸入樣式的自訂 UI 輸入的控制項可能會產生為基於觸摸的環境,如 Windows Phone 或 Windows 8 的可憐 UX。遷移代碼庫向前的僅僅是願望還不夠 ; 必須有基礎的設計相容性之間舊的和新的平臺,再加上願意調和無論確實存在的細微差別。在英鎊,我有幾個這種困境,通過開展工作。

最突出的設計問題是同步英鎊資料更新 API 和這種行為,目標 Windows Phone 8 和 Windows 應用商店的應用程式庫中的預期非同步性質之間的不匹配。英鎊是幾年前設計在一個地方的非同步 Api 是罕見的和的工具和技術來創建他們簡陋在最好的世界。

這裡是典型的保存在遷移前英鎊的方法簽名:

object Save<T>(T instance) where T : class, new()

什麼是重要的是要注意在這裡是此方法同步 ; 執行 也就是說,無論怎麼長時間保存的實例參數,調用方被阻止,等待的方法來完成。 這可以導致執行緒阻塞問題的通常陣列中:沒有回應的使用者介面,大大減少了伺服器的可伸縮性等等。

在過去的幾年 ; 回應軟體設計的使用者期望有急劇增加 我們都不想要忍受了幾秒,同時保存在等待凍結 UI 操作完成。 作為回應,為新的平臺 API 設計準則喜歡 Windows Phone 8 和公共庫的方法如保存的 Windows 8 任務是非同步、 非阻塞的操作。 值得慶倖的是,功能像基於.NET 任務非同步模式 (TAP) 程式設計模型和 C# 非同步和等待關鍵字使這更容易的現在。 這裡是為更新的簽名保存:

Task<object> SaveAsync<T>(T instance) where T : class, new()

現在保存立即返回,並且調用方具有一個 awaitable 物件 (任務) 使用,最終收穫的結果 (在本例中的唯一鍵的新保存的實例)。 調用方不會阻塞從做其他工作,同時保存在後臺完成操作。

要弄清楚,我在這裡給的都是方法簽名 ; 從同步到引擎蓋下的非同步執行的轉換所需的額外的重構和切換到的非同步檔 Api 為每個目標平臺。 例如,同步執行保存用 BinaryWriter 來寫入到檔案系統:

using ( BinaryWriter instanceFile = _fileHelper.GetWriter( instancePath ) )
{
  instanceFile.Write( bytes );
}

但因為 BinaryWriter 不支援非同步語義,我已經重新改寫此項可使用適合於每個目標平臺的非同步 Api。 例如, 圖 1 顯示 SaveAsync 英鎊的 Windows Azure 表存儲驅動程式的外觀。

圖 1 SaveAsync 英鎊 Windows Azure 表存儲驅動程式的外觀

using ( var stream = new MemoryStream() )
{
  using ( var writer = new BinaryWriter( stream ) )
  {
    action( writer );
  }
  stream.Position = 0;
  var entity = new DynamicTableEntity( partitionKey, rowKey )
  {
    Properties = new Dictionary<string, EntityProperty>
    {
      { "blob", new EntityProperty( stream.GetBuffer() ) }
    }
  };
  var operation = TableOperation.InsertOrReplace( entity );
  await Task<TableResult>.Factory.FromAsync(
    table.BeginExecute, table.EndExecute, operation, null );
}

我仍然使用 BinaryWriter 將離散值寫入到記憶體中的資料流程,但然後使用的 Windows Azure DynamicTableEntity 和 CloudTable.BeginExecute 和。EndExecute 以非同步方式在 Windows Azure 表存儲服務中存儲的流的位元組陣列內容。有幾個其他的類似變化實現英鎊的非同步資料更新行為所必需。關鍵點:表面級 API 重構可能只有幾個步驟實現這樣的遷移重新設計目標所必需的第一。因此,計畫你的工作任務和工作量估算和現實對這種改變是否甚至一個合理的目標放在第一位。

事實上,我的經驗與英鎊浮出水面只是這種不切實際的目標。核心設計英鎊的特點是所有的存儲操作工作針對強型別的資料,使用標準的.NET 資料約定序列化的 Api 和擴展。這非常適合於 Windows Phone 和.NET 4.5 用戶端,以及 C#-基於 Windows 應用商店的應用程式。然而,沒有在 Windows 存儲 HTML5 和 JavaScript 用戶端的世界中,強型別的概念。經過研究和討論與 Likness,我確定有沒有容易的方式以使英鎊可用於這些用戶端,所以我選擇忽略他們作為支援的選項。這種潛在的不匹配當然必須考慮的個案,但知道他們可以產生與現實有關您的選項。

共用代碼跨目標平臺我所面臨的下一個大的挑戰是一個我們遇到一次或另一種:如何跨多個專案共用公用代碼?

查明和在專案之間共用公用代碼為儘量減少對市場的時間和下游維修頭痛是經過驗證的策略。我們這樣做多年來在.NET 中 ; 一個典型的模式是定義一個共同的程式集和引用,從多個消費專案。另一種最喜歡技術是Visual Studio,授予共用多個專案中,表明在單個主原始檔案的能力中的"添加為連結"功能圖 2


圖 2Visual Studio2012年將作為連結功能添加

即使在今天,這些選項工作好如果所有的消費專案目標相同的基礎平臺。然而,當您想要公開常用功能跨多個平臺 (如我案與英鎊),創建此類代碼的單個常見程式集中成為一個重要的發展負擔。創建和維護多個生成目標變得危急情況,增加了專案的配置和生成過程的複雜性。使用的預處理器指令 (#if、 #endif 等等),有條件地包括特定于平臺的行為,為某些組建組態是虛擬的必要性,使代碼更難閱讀、 導航和有關的原因。能源浪費在這種配置負擔轉移注意力從解決實際問題通過代碼的主要目標。

高興的是,Microsoft 預期更容易跨平臺發展的需要,並開始在.NET Framework 4 中,添加一項稱為可擕式類庫 (PCLs) 的新功能。PCLs 允許您有選擇地針對多個版本的.NET 框架,Silverlight 和 Windows Phone 以及 Windows 存儲區和 Xbox 360,所有從單一的Visual Studio的.NET 專案。當您選擇 PCL 專案範本時,Visual Studio會自動確保您的代碼使用僅存在的庫,每個挑選的目標平臺上。這消除了笨拙的預處理器指令和多個生成目標的需要。另一方面,它不會放在哪些 Api 可以調用您的庫 ; 從一些限制 我會解釋更多關於如何解決這種限制在一個時刻。請參閱"跨平臺開發與.NET 框架"(msdn.microsoft.com/library/gg597391) 為進一步細節在 PCL 的功能和使用。

PCLs 是適合我的跨平臺目標與英鎊。我就能超過 90%的英鎊成單一的共同 PCL 可用而無需從.NET 框架 4.5,Windows Phone 8 和 Windows 8 的修改基本代碼的重構。這是一個巨大的優勢,為該專案的長期生存能力。

關於單元測試專案的簡短說明:從今天起,沒有為單元測試代碼的 PCL 等效。創建一個的主要障礙是缺乏跨多個平臺工作,單個統一的單元測試框架。鑒於這一現實,英鎊單元測試為.NET 4.5、 Windows Phone 8 和 Windows 8 ; 定義單獨的測試專案 .NET 4.5 專案包含的唯一副本的測試代碼,而其他專案共用使用前面提到的添加為連結技術的測試代碼。每個平臺的專案不會引用測試框架程式集特有的平臺 ; 幸運的是,命名空間和類型名稱是相同的在每個,因此相同的代碼編譯所有測試專案中不被修改。請參閱在 GitHub 上代碼庫的更新的英鎊 (bit.ly/YdUNRN) 為這是如何工作的例子。

利用特定于平臺的 Api PCLs 是有很大的説明,在創建統一跨平臺代碼庫,它們構成有點左右為難:您如何使用不是從 PCL 代碼調用的特定于平臺 Api?一個完美的例子是我提到的 ; 在非同步代碼重構 雖然.NET 4.5 和 Windows 應用商店的應用程式特別是有豐富的強大非同步 Api 可供選擇,但這些都不是可從 PCL 內調用。你可以有你的蛋糕和太吃它嗎?

原來你可以 — — 一點的工作。想法是定義裡面你 PCL 一個或更多的介面,模型的特定于平臺的行為你是無法直接調用,然後執行這些基於 pcl 語言代碼的介面抽象。然後,在單獨平臺特定庫中,您提供的每個介面的實現。最後,在運行時您創建類型的實例 PCL 來完成一些任務,堵在特定介面執行適當的當前目標平臺。抽象允許 PCL 代碼保持分離了,平臺的詳細資訊。

如果這一切聽起來既熟悉又陌生的它應該:我在這裡描述的模式被稱為控制反轉 (IoC),實現模組化解耦和隔離的嘗試真實軟體設計技術。你可以閱讀更多關於政府間海洋學委員會在 bit.ly/13VBTpQ

同時移植英鎊,我決定使用這種方法的幾個 API 不相容性問題。Api 的問題大部分都來自 System.Reflection 命名空間。諷刺的是雖然每個目標平臺暴露所有我需要為英鎊的反射功能,每個有它自己未成年的怪癖和細微差別,使它無法支援他們一致地在 PCLs。因此這種基於國際奧會技術的必要性。你會發現生成 C# 介面抽象定義為英鎊,要解決這些問題在 bit.ly/13FtFgO

一點一般建議

現在,我概述我的英鎊的遷移策略,我會退後一小步,考慮如何在一般情況下應用的經驗教訓。

第一次 — — 和我不能強調這一點 — — 使用 PCL 功能。PCLs 是一次巨大勝利跨平臺開發,和他們提供足夠的配置靈活性,以適應最任何需要。如果您要遷移現有庫向前 (或甚至寫一個新),它面向多個平臺,您應該使用 pcl 語言。

下一步,預計一些重構的努力,以容納更新的設計目標。換句話說,不要指望你的代碼遷移是一個簡單的機械過程,一個 API 呼叫替換另一種。它是完全可能的所做的更改你想要比表面的水準,更深入瞭解,可能需要更改一個或多個核心假設作出時的原始基本代碼寫。有實際的限制你可以強加給現有的代碼不大的下游影響 ; 總改動 你會有自己做決定的那條線在哪裡,並時,如果越過它。一個人的遷移是另一種的來原始程式碼叉到完全新的專案。

最後,不要放棄你現有的工具箱中的模式和設計技術。我已經演示了如何我用國際奧會原則和依賴關係注入英鎊,以利用特定于平臺的 Api。其他的類似的方法無疑會好好服侍你。經典軟體設計模式,如戰略 (bit.ly/Hhms),配接器 (bit.ly/xRM3i),範本方法 (bit.ly/OrfyT) 和外立面 (bit.ly/gYAK9) 為新的目的重構現有代碼時可能非常有用。

勇敢的新世界

我的最終結果是工作的功能齊全的英鎊 NoSQL 實現三個目標平臺上的.NET 框架 4.5、 Windows 8 和 Windows Phone 8。它很高興看到英鎊在像我表面的平板電腦和我的諾基亞 Lumia 920 手機最新的基於 Windows 的設備上運行。

斯特林專案承載 Wintellect GitHub 網站上 (bit.ly/X5jmUh) 和包含的全部遷移的原始程式碼以及單元測試和樣品為每個平臺的專案。它還包括所使用的 Windows Azure 表存儲的英鎊驅動程式模型的實現。我邀請你要克隆的 GitHub 存儲庫和探索的模式和設計選擇我概述在這篇文章 ; 我希望它們作為您自己的類似努力有用的起點。

記住,別扔出去......,舊的代碼遷移它 !

Josh Lane 是亞特蘭大 Wintellect llc 公司的高級顧問。他花了 15 年規劃、 設計和構建軟體在 Microsoft 平臺上,並成功地提供了範圍廣泛的技術解決方案,從話務中心網站自訂 JavaScript 編譯器和許多其他在之間。他喜歡挑戰的派生軟體通過有意義的業務價值。聯繫到他在 jlane@wintellect.com

由於以下的技術專家對本文的審閱:Jeremy Likness() Wintellect