2016-07-07 33 views
1

在我的開發團隊,我們正在使用中this article描述的CQRS模式,並使用建議 DI容器:Simple Injector雙關語意)。簡單的噴油器註冊和執行內部CommandHandler

這是我們目前的項目結構:

  • 01的WebApp references => [02] [03]
  • 02合同
  • 03 BusinessLayer

項目01是客戶端(一個ASP.NET MVC應用4)在那裏我們通過簡單注射器註冊我們的應用服務(Bootstrapper)。項目03是所有命令和查詢處理程序的定義,如文章中所述。 Project 02是定義命令和查詢的地方。爲了簡單注入器註冊處理程序,客戶端直接引用業務層組件。

容器註冊commandhandlers這樣

container.Register(typeof(ICommandHandler<>), assemblies); 

現在的問題是,是,我們的開發者之一偶然忘記申報其處理程序類中的一個作爲public。因此,而不是:

​​

他寫道:

class AddCustomerCommandHandler : ICommandHandler<AddCustomerCommand> { ... } 

現在根據msdn,如果省略了訪問修飾符,內部使用:

類和結構被直接聲明在名稱空間內( ,也就是說,不嵌套在其他類或結構中)可以是公共的或內部的 。 如果未指定訪問 修飾符,則內部爲默認值。

現在內部被定義爲:

的類型或成員可以通過任何代碼在相同的組件進行訪問, 但不能從另一個組件。

嘗試執行此命令後,運行時不會引發任何錯誤並且該命令可以愉快地執行。我對此感到驚訝,因爲我希望Simple Injector發現驗證錯誤,但它不會。另外,當試圖直接實例化客戶端中的處理程序對象時,編譯器給我一個錯誤,正如預期的那樣it cannot access an internal class here!那麼爲什麼Simple Injector能夠註冊這個命令處理程序,而訪問修改器是internal

回答

2

在以前的版本中,Simple Injector的批註冊默認跳過內部類型,並且一個標誌允許您註冊內部類型。

此方法已被證明是有問題的,因爲在某些應用程序中,缺少的類型允許應用程序繼續運行,同時顯示不正確的行爲(因此失敗)。

爲了防止這種情況發生,我們改變了這種行爲,現在您總是可以看到這種類型也被註冊了。這個想法是,默默地跳過預期的類型比其他任何事情都要糟糕得多。由於大多數應用程序都以完全信任的方式運行,所以內部類型可以被構建和解析,所以從Simple Injector的角度來看,類型可以是內部的。對於其他應用程序類型,對驗證的調用將快速檢測到不可構建的類型。

同樣從應用程序的角度來看,類型應該是內部的,因爲消費者與這種類型實現的公共接口對話。

你的情況失敗的原因很可能是因爲你派遣你的處理程序並在調度過程中使用dynamic鍵入。你看到的是IMO在C#動態基礎架構中的一個怪癖。 C#嘗試使用反射來查找您的Handle方法,但Handle方法是內部方法,因爲它的周圍類型是內部的。即使類型實現了包含該方法的公共接口,它也找不到該方法。這是一個怪癖,我相信C#仍然應該找到這種方法;但事實並非如此。這就是爲什麼你的代碼失敗。

你可以做幾件事來防止將來出現這樣的問題。你可以例如定義一個單元測試來檢查所有的處理程序是否公開。或者你可以定義一個特殊的泛型和公共包裝類,其中一個處理程序作爲構造函數參數abd解析該包裝程序而不是處理程序。你可以使用該包裝器上的動態類型。或者你註冊一個你確定是公開的最外層的裝飾器。 C#反映了最外層的類型,所以這將起作用。

您也可以將檢查集成在Simple Injector中,您可以在其中有條件地註冊最外層的裝飾器,並讓謂詞在處理器內部發生異常時引發異常。

相關問題