Dot-Net

DI 在桌面應用程序中有意義嗎?

  • March 22, 2016

我即將創建一個桌面應用程序(使用 .NET windows 窗體)

本質上,我想創建一個 n 層應用程序,但我也想要層之間的鬆散耦合。但是,我不太確定這是否是 Windows 窗體的好方法

現在我只是想知道使用任何 IoC(StructureMap、Ninject、Spring.Net)是否真的是一個明智的選擇,我以前曾將它們用於 Asp.Net Web 應用程序,但現在讓我懷疑的是使用當我瀏覽選項卡時,Windows 表單我的業務實體將持續存在,這與 Web 表單或 mvc 應用程序不同,在這些應用程序中,每次執行的新請求都需要注入我的業務實體,我的意思是因為Asp.Net 頁面生命週期在哪裡執行初始化和控制實例化。

這是一個長期的開發項目,它結合了維護跟踪、庫存、工單和管理報告。我目前正在為其架構提出建議。

也許我誤解了使用 IoC 的意義,所以請告訴我你認為什麼是更好的選擇?

任何觀點都將不勝感激。

在您的情況下使用 DI / IoC 仍然有意義,因為這完全是為了放棄對依賴項來自何處、誰管理它們的生命週期等的控制。

從這個意義上說,該原理Inversion of Control幾乎與平台無關,它在ASP.NET和之間的連接方面可能略有不同WinForms,但原理是相同的。

因此,雖然在 ASP.NET 中,控制反轉通常是通過並且主要通過Dependency Injection建構子注入到控制器等來實現的,但這並不意味著您必須在 Windows 窗體中遵循相同的模式 - 例如,您可以只創建一個全域您的 IoC 容器的實例可用於所有表單,並讓它們通過類似的方式獲取它們的依賴關係

var SomeBusinessObject = container.Get<SomeBOType>(); //Ninject style.

在這種情況下,它仍然是 IoC(表單不直接創建依賴項,它不知道容器是給它一個全新的實例,還是一個全域共享的單個靜態實例,它不知道什麼時候會銷毀等),但嚴格來說它不是依賴注入- 但是您可以獲得由 IoC 框架為您管理的複雜依賴圖的所有好處。

另請記住,您始終可以處理使用者切換選項卡的事件,並將其視為全新的“請求”,然後丟棄並重新獲取您的依賴項,如果出於某種原因這對於如何該應用程序應該可以工作。

你的問題很奇怪。您的問題意味著您將以與 Web 應用程序不同的方式為 Winforms 應用程序編寫業務層,但如果您正確應用分層,則業務層應該完全獨立於所使用的技術。因此,從這個意義上說,如果您要將依賴注入模式應用到 Web 應用程序的業務層中,那麼您也應該將其應用到桌面應用程序的業務層中。

我目前正在自己​​開發一個 Winforms 項目,並廣泛使用依賴注入模式(和一個 IoC 容器)。對我來說,是否應該使用 DI 沒有問題。它自然地來自應用SOLID原則。然而,您是否應該使用 IoC 容器是一個完全不同的問題,儘管對於我編寫的應用程序類型和我使用的架構類型,我無法想像沒有它的生活。

儘管桌面應用程序在本質上與 Web 應用程序有很大不同,但我在這兩種類型的應用程序上使用了相同的模式。例如,我在我的 Windows 窗體類中使用建構子注入,這些窗體主要依賴於一些通用介面,即:

  • IRepository<TEntity>(儲存庫模式)用於載入實體。
  • IQueryHandler<TQuery, TResult>用於執行各種複雜或自定義查詢。
  • ICommandHandler<TCommand>用於執行案例(處理使用者操作)。

我在我建構的 Web 應用程序中使用相同的抽象。

幾個月前,這些介面幫助我將此桌面應用程序從 2 層應用程序(所有業務邏輯都在桌面應用程序中執行)更改為 3 層應用程序(所有業務邏輯現在都移至 WCF 服務)。我們能夠做到這一點,而無需更改表單中的任何程式碼。

在 2 層模型中,我們沒有ICommandHandler<TCommand>直接注入實現,而是注入了一個(單例)代理類,該類在每次呼叫時都會創建一個新的實現。例如,當表單呼叫注入ICommandHandler<ProcessOrder>時,實際CommandHandlerProxy<ProcessOrder>將啟動生命週期範圍(一種模仿 Web 應用程序的每個請求生活方式的生活方式)並創建ProcessOrderCommandHandler執行實際邏輯的真實類。通過這樣做,我們確保了一個單一的工作單元(DbContext在我們的例子中是實體框架)將被注入到這個“請求”中的所有類中。當然,依賴注入一直到呼叫圖。

在新的 3 層模型中,表單被注入了一個WcfProxyCommandHandler<TCommand>將給定命令序列化為 JSON 並將其發送到 WCF 服務,WCF 服務將接收它、反序列化命令、創建ProcessOrderCommandHandler並執行命令。

但請記住,此模型可能與您可能習慣使用的模型大不相同。例如:

  • 真正的實體隱藏在 WCF 服務後面。桌面應用程序對它們一無所知。
  • 相反,當通過抽象請求數據時,WCF 服務會返回DTO 。IQueryHandler<TQuery, TResult>
  • 我們使用 Entity Framework 5(帶有 T4 和設計器的 POCO 類)。
  • 這些 DTO(主要)用於閱讀;它們不會被發送回伺服器進行更新。
  • 任何更改狀態的請求(執行案例)都是通過向伺服器發送命令消息(通過ICommandHandler<TCommand>抽象)來完成的。
  • 一個案例被封裝在實現ICommandHandler<TCommand>介面的單個類中。

正如我所說,它一直是依賴注入,這個和所描述的設計給了我們很大的靈活性。例如:

  • 我們發現添加新功能非常容易。
  • 我們發現添加新的橫切關注點非常容易。
  • 降低心理障礙;它使應用程序更易於維護,並且不太可能以意想不到的方式中斷。

然而,我在這個過程中發現了一件事:

  • winforms 中的綁定經過優化,可以與 DataSet 一起使用。如果您嘗試其他任何東西(Poco’s、Entity Framework 實體等),您會遇到一些非常令人沮喪的時刻,您會發現除了 DataSets 之外對其他任何東西的支持都很少。很明顯,微軟沒有在這個領域投資,也不會再投資這個領域。為了解決這些限制,我們編寫了自己的BindingList<T>實現,但發現很難創建一個可以正確處理排序和過濾的實現(尤其是因為我們的 DTO 沒有實現INotifyPropertyChanged)。我們還編寫了自己的基礎架構來為 Winforms 添加 DataAnnotations 驗證支持。

如果您想了解更多關於我使用的設計的資訊,請閱讀以下文章:

  1. 同時……在我的架構的指揮方面
  2. 同時……在我的架構的查詢方面
  3. 編寫高度可維護的 WCF 服務

引用自:https://stackoverflow.com/questions/19937187