此章節來自msdn。
一、一般調試方法
在 Managed Extensibility Framework (MEF) 中調試問題可能非常困難,因為潛在問題與標準應用程式中的潛在問題不同。 本主題提供了特定於 MEF 的問題診斷技巧,並且提供了這些問題的一些可能原因。
發現 MEF 問題
解決 MEF 問題的第一步是在應用程式的 MEF 部分中定位問題。 下表列出了特定於 MEF 的問題。
問題 |
可能的原因 |
組合期間引發 ImportCardinalityMismatchException 異常。 |
由於組件缺失或被拒絕,無法使用匹配的匯出填充匯入。 - 或 - 預期單個匯出的匯入發現多個匹配項。 |
具有 ImportManyAttribute 特性的集合缺少預期內容。 |
預期組件缺失或被拒絕。 |
DefaultValueAttribute 特性設定為 true 的匯入意外未填充。 |
預期的匹配項缺失或被拒絕。 |
處理異常和 DisableSilentRejection
MEF 旨在可靠地適應各種配置。 預設情況下,它忽略具有缺少必需的依賴項的部分。 但是,當您調試應用程式時,這種可靠性會使尋找問題原因更困難。 您可以採用這些步驟更輕鬆地跟蹤問題:
引發異常時,請配置 Visual Studio 調試器中斷。
配置您的 CompositionContainer 對象禁用拒絕。
通常,如果應用程式引發異常,則 Visual Studio 調試器將中斷執行僅當該異常不隨後處理。 但是,您可能會發現,當引發異常時,立即停止並調試您的 MEF 應用程式會很有協助,因為您的應用程式會以某些方式處理異常,而不會將其體現在調試器中。 若要在引發異常時配置 Visual Studio 調試器,在功能表列上,選擇“調試”、“異常”。 確保選擇了所有異常的“引發”框,您想要將調試器設定為遇到這些異常時中斷。 (有關 MEF,這些是在 System.ComponentModel.Composition 下的異常。這些異常此時將顯示在調試器中,即使您的應用程式處理了這些異常。
預設情況下,MEF 使用叫做拒絕的處理確定將用於執行個體化調用哪些組件具有相關性。 組合引擎檢查新組件的添加是否將導致組合失敗。 如果它們可能會導致失敗,則從容器中隱藏那些組件,但不引發異常。 在面對部署配置時此行為會使應用程式更穩定,但可能使調試更難。 若要每當組件被拒絕時關閉拒絕,並確保 MEF 引發異常,將 DisableSilentRejection 值設定傳遞到 CompositionContainer 或 ExportProvider 對象。 以下代碼對此進行了說明:
程式碼片段
var catalog = new DirectoryCatalog("Extensions");var container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection);
MEF 失敗通常是級聯的,即組合一個組件失敗會導致組合第二個組件失敗以此類推,直到觀測到的失敗點在異常的長列表中丟失。 為協助診斷此屬性的問題,CompositionException 異常提供 RootCauses 屬性。 您可以檢查在調試器中的此屬性以尋找是組合中每個錯誤的根本原因的異常。
跟蹤
從開始 .NET Framework 4.5,MEF 支援跟蹤。 運行時,以 Visual Studio 的偵錯模式,組合故障和異常將寫入“IntelliTrace”視窗。 檢查這些結果有助於診斷組合失敗。 有關使用 IntelliTrace 的更多資訊。
檢查可用組件
若要確定哪些組件可用於目錄,可以在調試器中檢查目錄的 Parts 屬性,在代碼中逐一查看該屬性。
如果希望看到的組件不存在,則表示未發現或者已拒絕這些組件。
如果可以看到一個組件,但是它與您希望它填充的匯入不匹配,則表示出現了某種類型的不匹配。
匯出/匯入不匹配
為了使匯出與特定匯入匹配,必須滿足以下所有條件。 如果未出現預期匹配,但是您已確認匯出存在於目錄中,請仔細檢查這些條件。 手動構造協定以匹配特定匯出時,這些條件也適用。
屬性 |
匹配的條件 |
協定名稱 |
必須完全符合並且區分大小寫。 如果協定名稱是從類型推斷得出的(例如,在沒有任何參數的情況下應用 ExportAttribute 特性時),則唯一可能的匹配項是從同一類型推斷得出的另一名稱。 |
協定類型 |
必須完全符合。 不支援多態匹配。 即使提供了匹配的協定名稱,協定類型也必須匹配。 |
必需的中繼資料 |
匯入通過其中繼資料視圖的屬性要求的所有中繼資料必須由匯出通過 ExportMetadataAttribute 特性或自訂中繼資料特性提供。 中繼資料鍵(中繼資料視圖中屬性的名稱)和中繼資料值的類型必須匹配。 |
建立策略 |
匯出和匯入不能指定不同的建立策略。 有關更多資訊,請參見 CreationPolicy。 |
發現問題
如果組件未顯示在目錄中或者使用組合分析工具 (Mefx) 時未顯示,則表示目錄未發現該組件。 這裡是導致此故障的一些可能原因:
該組件是抽象類別型。 抽象類別型不能用作組件。 使類型成為非抽象類別型,或者建立非抽象子類型。
ImportingConstructorAttribute 特性缺失。 對於具有多個建構函式或者僅具有接受參數的建構函式的組件,必須指定一個建構函式,以便 MEF 使用 ImportingConstructorAttribute 特性。
該組件具有 PartNotDiscoverableAttribute 特性。 此特性阻止組件被發現。
該組件是開放式泛型型別。 MEF 不支援開放泛型。 請使用類型的封閉式子類,或者匯出單個屬性。
您使用 DirectoryCatalog 對象時可能出現其他故障:
該組件位於 .exe 檔中。 預設 DirectoryCatalog 僅從 DLL 檔案讀取。 通過使用相應搜尋模式建立,可以使用 DirectoryCatalog 對象從其他檔案讀取。
組件的程式集具有缺失的引用。 使用的程式集不能從搜尋路徑(通常從它們自己的目錄或者從全域組件快取)載入其引用。
該組件的程式集面向其他 CPU 類型。 MEF 不會載入面向錯誤 CPU 類型的程式集。
二、組合分析工具(Mefx)
組合分析工具 (Mefx) 是分析包含 Managed Extensibility Framework (MEF) 組件的庫 (.dll) 和應用程式 (.exe) 檔案的命令列應用程式。 Mefx 的主要目的是向開發人員提供一種方式,以允許他們無需嚮應用程式本身添加繁瑣的跟蹤代碼即可診斷 MEF 應用程式中的組合故障。 它還可用於協助瞭解第三方提供的庫中的組件。 本主題描述如何使用 Mefx 並且提供了文法參考。
本主題包括下列各節。
擷取 Mefx
可在 Codeplex 的 Managed Extensibility Framework 上擷取 Mefx。 下載和解壓縮該工具即可。
基本文法
Mefx 從命令列使用以下格式調用:
mefx [files and directories] [action] [options]
第一組參數指定從中載入組件進行分析的檔案和目錄。 使用 /file: 開關指定檔案,使用 /directory: 開關指定目錄。 可以指定多個檔案或目錄,如下面的樣本所示:
mefx /file:MyAddIn.dll /directory:Program\AddIns [action...]
說明 |
每個 .dll 或 .exe 應僅載入一次。 如果多次載入一個檔案,該工具可能會返回不正確的資訊。 |
在檔案和目錄列表後面,必須指定命令以及該命令的任何選項。
列出可用組件
使用 /parts 操作可列出在載入的檔案中聲明的所有組件。 結果為簡單的組件名稱列表。
mefx /file:MyAddIn.dll /parts
MyAddIn.AddIn
MyAddIn.MemberPart
若要擷取有關組件的更多資訊,請使用 /verbose 選項。 這將輸出所有可用組件的更多資訊。 若要擷取有關單個組件的更多資訊,請使用 /type 操作而不是 /parts。
mefx /file:MyAddIn.dll /type:MyAddIn.AddIn /verbose
[Part] MyAddIn.MemberPart from: AssemblyCatalog (Assembly=" MyAddIn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
[Export] MyAddIn.MemberPart (ContractName=" MyAddIn.MemberPart")
列出匯入和匯出
/imports 和 /exports 操作將分別列出所有匯入的組件和所有匯出的組件。 還可以使用 /importers 或 /exporters 操作列出匯入或匯出特定類型的組件。
mefx /file:MyAddIn.dll /importers:MyAddin.MemberPart
MyAddin.AddIn
還可以對這些操作應用 /verbose 選項。
尋找拒絕的組件
載入可用的組件後,Mefx 使用 MEF 組合引擎組合它們。 不能成功組合的組件稱為“拒絕的組件”。 若要列出所有拒絕的組件,請使用 /rejected 操作。
可以將 /verbose 選項與 /rejected 操作結合使用,以輸出有關拒絕的組件的詳細資料。 在下面的樣本中,ClassLibrary1 DLL 包含 AddIn 組件,它匯入 MemberPart 和 ChainOne 組件。 ChainOne 匯入 ChainTwo,但是 ChainTwo 不存在。 這意味著 ChainOne 被拒絕,這將導致 AddIn 被拒絕。
mefx /file:ClassLibrary1.dll /rejected /verbose
下面顯示了前面的命令的完整輸出:
[Part] ClassLibrary1.AddIn from: AssemblyCatalog (Assembly="ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
[Export] ClassLibrary1.AddIn (ContractName="ClassLibrary1.AddIn")
[Import] ClassLibrary1.AddIn.memberPart (ContractName="ClassLibrary1.MemberPart")
[SatisfiedBy] ClassLibrary1.MemberPart (ContractName="ClassLibrary1.MemberPart") from: ClassLibrary1.MemberPart from: AssemblyCatalog (Assembly="ClassLibrar
y1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
[Import] ClassLibrary1.AddIn.chain (ContractName="ClassLibrary1.ChainOne")
[Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No valid exports were found that match the constraint '((exportDefinition.ContractName == "ClassLibrary1.ChainOne") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "ClassLibrary1.ChainOne".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))', invalid exports may have been rejected.
at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
at Microsoft.ComponentModel.Composition.Diagnostics.CompositionInfo.AnalyzeImportDefinition(ExportProvider host, IEnumerable`1 availableParts, ImportDefinition id)
[Unsuitable] ClassLibrary1.ChainOne (ContractName="ClassLibrary1.ChainOne")
from: ClassLibrary1.ChainOne from: AssemblyCatalog (Assembly="ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
[Because] PartDefinitionIsRejected, The part providing the export is rejected because of other issues.
[Part] ClassLibrary1.ChainOne from: AssemblyCatalog (Assembly="ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
[Primary Rejection]
[Export] ClassLibrary1.ChainOne (ContractName="ClassLibrary1.ChainOne")
[Import] ClassLibrary1.ChainOne.chain (ContractName="ClassLibrary1.ChainTwo")
[Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No valid exports were found that match the constraint '((exportDefinition.ContractName == "ClassLibrary1.ChainTwo") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "ClassLibrary1.ChainTwo".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))', invalid exports may have been rejected.
at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
at Microsoft.ComponentModel.Composition.Diagnostics.CompositionInfo.AnalyzeImportDefinition(ExportProvider host, IEnumerable`1 availableParts, ImportDefinition id)
需要關注的資訊包含在 [Exception] 和 [Unsuitable] 結果中。 [Exception] 結果提供有關組件為什麼被拒絕的資訊。 [Unsuitable] 結果指明以其他方式匹配的組件為什麼無法用於填充匯入;在本例中,因為該組件本身因缺失匯入被拒絕。
分析主要原因
如果一些組件連結在較長的依賴關係鏈中,則問題涉及的組件靠近底部時可能會導致整個鏈被拒絕。 診斷這些問題可能非常困難,因為故障的根本原因並不總是非常明顯。 為了協助診斷問題,可以使用 /causes 操作,它嘗試尋找所有級聯拒絕的根本原因。
對前面的樣本使用 /causes 操作僅列出 ChainOne 的資訊,它未填充匯入是拒絕 AddIn 的根本原因。 /causes 操作可以在正常和 /verbose 選項中使用。
說明 |
在大多數情況下,Mefx 能夠診斷出級聯故障的根本原因。 然而,對於組件以編程方式添加到容器的情況、涉及分層容器的情況或者涉及自訂 ExportProvider 實現的情況,Mefx 將無法診斷出原因。 通常,應儘可能避免前面所述的情況,因為故障通常很難診斷。 |
白名單
/whitelist 選項允許您指定一個文字檔,其中列出應該被拒絕的組件。 然後,將標記意外拒絕。 分析不完整的庫或者缺少一些依賴項的子庫時,這可能非常有用。 /whitelist 選項可應用於 /rejected 或 /causes 操作。
請考慮一個名為 test.txt 的檔案,它包含文本“ClassLibrary1.ChainOne”。 如果對前面的樣本運行帶有 /whitelist 選項的 /rejected 操作,則將產生以下輸出:
mefx /file:ClassLibrary1.dll /rejected /whitelist:test.txt
[Unexpected] ClassLibrary1.AddIn
ClassLibrary1.ChainOne