Windows phone 應用開發[6]-Managed Extensibility Framework應用程序擴展

Managed Extensibility Framework 或是簡稱MEF. 從字面意思來看 MEF是一個用來擴展.NET 應用的框架. MEF做爲.NET 4的一部分同時也支持Silverlight 4版本.開發人員能夠利用該框架在不對當前代碼產生影響的狀況下對應用程序加以擴展. 擴展方向既能夠在應用程序內重用擴展.也能夠在應用程序間重用擴展.這樣使用MEF動態編譯的.NET 應用程序轉換成爲一系列的動態組合.有助於對組件實現最大化的重用.而MEF不只使應用程序具有組件化的特性.同時增強了應用程序自身的可擴展性.sql

well.在使用MEF以前假設一個場景.在.NET 4.0中經過dynamic實現輕量級的AOP[Aspect Oriented Programming]組件.若是這些組件數量偏大. 因組件的宿主程序自身沒有感知發現組件的能力.因此一般的作法是經過一個XML配置文件來顯示註冊可用組件.在宿主程序須要接入擴展點提供接口.目的實現應用程序與宿主程序的分離造成結構關係以下:編程

而造成並創建組件與宿主程序的關係的一方面落在一個不管是最終用戶仍是開發人員都要加以維護的XML文件之上. 另一方面組件開發必須依賴於包含他們實現的接口的程序集.這樣依賴照成一個組件很難在多個應用程序加以複用的問題.安全

介紹MEF在實際項目中使用方法.架構

Managed Extensibility Framewrok 目前第二版本.MEF 2 Privew 5.能夠在http://mef.codeplex.com/下載.其實MEF框架實際上微軟官方發佈的第四個擴展新框架.雖然官方一直聲稱是第一個. 除了像第三方的Spring.NET這樣的框架.微軟本身最少還開發其餘三個.NET 運行時的擴展框架:app

.NET Runtime擴展框架:框架

[1]Unity 各位很熟悉的微軟的企業庫Unity Application Block 1.ide

[2]CLA插件模型 也就是MEF 以前早期.NET 版本引入的Managed Add-in Framework [MAF]是應用程序可以實現隔離.並管理擴展框架.工具

[3]Composite Application Libray 主要在Silverlight和WPF中使用.熟悉的Prism.組件化

 

其實這裏談到MEF.不得提到早期的Managed Add-In FrameWork[簡稱Add-in模型].Add-n模型能夠解決版本依賴,隔離和故障恢復.MEF第一個版本核心主要解決組件的搜索和組合問題.將組件靜態依賴中解放出來.並提供了將不一樣編程模型組合在一塊兒可能.測試

雖然MEF能夠構建在Add-in模型之上能夠在安全隔離和版本的穩定性獲得很多好處.但從官方介紹來看MEF並無構建在Add-in模型之上.而從頭開始編寫,並無考慮已有的技術.固然從使用者角度來Add-in出現的時機和使用難易度有很大關係.Add-in模型對於大多數開發人員來講並很差用.太過複雜.缺少必要的代碼生工具.原版本官方也放棄了維護.終究想.NET 3.5中Linq To SQl同樣慢慢消失.而在.NET 4推出第二版的MEF 2.

MEF實現原理: 

 

從最簡單一個體現實例來講MEF主要包含三個核心部分:

MEF 核心部分:

A:Import[輸入]

B: Exprot[輸出]

C: Compose[組件關係組合] 

以這個實例爲原型.每一個組件Part能夠提供一個或多個對外的Export.而且一般依賴於一個或多個外部宿主程序提供的服務或Import.而Catalog類的則是用於發現指定範圍內的擴展關係.CompositionContainer對象則是全部Part組合容器.主要用於協調創建和管理Part組件與宿主程序之間的依賴關係.該容器包含全部可能的組件並執行組合操做. 

以下則採用簡單實例方式來演示MEF使用.MEF做爲.NET 4一個重要部分.開發環境須要.NET 4版本.這裏首先採用控制檯項目.首先經過MEF的方式來顯示當前APPlication 版本信息.

建立Console Application 命名:MEFConsoleDemo.添加MEF所在System.Conpontent.Composition程序集引用.

添加引用:

  
  
  
  
  1. using System.ComponentModel;     
  2. using System.ComponentModel.Composition;     
  3. using System.ComponentModel.Composition.Hosting; 

如今實如今應用程序版本發生變化是輸出版本號信息.做爲一個變化擴展點,.採用MEF方式則須要提供兩個部分.一個用於提供版本號信息.另一個則用來使用信息.首先定義輸出信息.採用關鍵字Export 定義類ClientRealseVersion實現接口IClientVersion:

  
  
  
  
  1. public interface IClientVersion     
  2. {     
  3.      string ClientVersion { get; set; }     

 

這裏採用Export來標識ClientRealseVersion類ClientVersion屬性輸出版本信息指定契約名稱爲接口IClientVersion類型. 並向MEF公開.這時還須要定義一個對應字符串來接受使用版本信息.並用Import標識.該特性將某個對象聲明爲一個導入;也就是說,在組合對象時將由組合引擎對它進行填充,每一個導入都有一個協定,用於肯定將與之匹配的導出。 協定能夠是顯式指定的字符串,也能夠由 MEF 從給定的類型(在此例中爲 IClientVersion 接口)自動生成:

  
  
  
  
  1. public class ClientApp     
  2. {     
  3.     [Import(typeof(ExportFolder.IClientVersion))]     
  4.     public string ClientVersion { get; set; }     
  5.  } 

當運行時.MEF 會自動檢測全部被標識過Import過的屬性.而後經過搜索經過Export標識而被導出的類型列表.若是被導出的類型和被標識的屬性類型相匹配.則會建立該類型的一個實例.並將其賦給這個屬性.

如今又了輸入和輸出.在主程序中調用時則經過CompositionContainer容器進行組合關聯.並添加全部組件到該容器中.在調用Compose()方法關聯組合 :

  
  
  
  
  1. CompositionContainer mefContainer = new CompositionContainer();     
  2. CompositionBatch mefBatch = new CompositionBatch();     
  3.  
  4. ClientApp currentClientApp = new ClientApp();     
  5. mefBatch.AddPart(new MEFConsoleDemo.ExportFolder.ClientRealseVersion());     
  6. mefBatch.AddPart(currentClientApp);     
  7.  
  8. mefContainer.Compose(mefBatch);     
  9.  
  10.  //Console Client App Version Infor    
  11.  Console.WriteLine(currentClientApp.ClientVersion);    
  12.  mefContainer.Dispose(); 

運行輸出:

當調用Clientapp實例輸出當前版本信息時.這裏採用CompositionBatch對象.

其實如上演示就是一個簡單的依賴注入.着不由讓我有些困惑,這和Unity這樣的IOC框架具體有什麼區別…?

其實雖然可以解決DI的問題.但MEF的核心目的並不在於此.MEF很容易被誤用.開發者常常把它做爲一個通用的依賴注入框架或控制反轉的容器.這些角色並非MEF自己真正目的.IOC模式只是很好解決MEF自身的問題.但MEF真正關注是應用程序的擴展性.而和Unity不一樣在於.前者更注重組合.後則強調依賴注入. 而和早期的MAF版本相比.MEF則關注使用簡單的方式來支持具備靈活性的可擴展支持.而MAF則注重應用程序的物理的隔離.多版本的支持和安全平臺架構.

如上採用CompositionBatch對象處理.固然常見寫法使用採用AggregateCatalog對象制定MEF查找程序集範圍.獲取全部組件的定義.經過CompositionContainer對象建立組合容器.添加組件. 經過ComposePart()方法創建組合關係 寫法以下:

  
  
  
  
  1. //採用AggregateCatalog 組合關係     
  2.  AggregateCatalog mefCatalog = new AggregateCatalog();     
  3.  mefCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));     
  4.  
  5.  CompositionContainer mefContrainer = new CompositionContainer(mefCatalog);     
  6.  ClientVersionInfo currentClientVersion = new ClientVersionInfo();     
  7.  mefContrainer.ComposeParts(currentClientVersion);     
  8.  
  9.   Console.WriteLine(currentClientVersion.CurrentVersion); 

well.這裏小結一下這裏面一些MEF特性概念.[我的理解]:

MEF概念:

Export[數據導出]:通常針對的是須要向宿主程序提供的組件模塊或服務.它是組件向容器中其餘組件提供一個值 功能或是服務.

Import[數據導入]:Import通常定義在宿主程序中.也就是上面提到擴展點.是組件 服務等接入宿主程序的窗口.MEF中支持的導入類型包含:動態導入.延遲導入.必須導入和可選導入.四種

Catalog[容器目錄]:爲了發現可用於組合容器的組件.Catalog對象主要用來發現可用組件.MEF 2中從提供的類型,程序集或磁盤路徑建立Catalog.

Compose[組件組合]:組合是MEF操做的核心.即實現導入和導出匹配的過程.MEF首先將組件實例化.而後執行導入和導出程序之間相匹配.

Contract[契約/協定]:準確的翻譯是契約.是Export和Import一種約定/.MEF執行組合過程當中只有Contract相匹配的Import和Export才能組合.

關於協定類型Contract.用處.假定如今修改如上需求.在如今組件基礎在作一次擴展.程序運行時同時顯示最後一個測試實例運行時間日期/.添加新的接口

  
  
  
  
  1. [InheritedExport(typeof(IClientVersion))]     
  2. public interface IClientVersion     
  3. {     
  4.     string ClientVersion { get; set; }     

這裏在接口標識InherItedEXport.指使MEF任何實現該接口的類都會自動導出.實現接口數據導出:

  
  
  
  
  1. public class LastTestSampleData:IClientVersion     
  2.  {     
  3.      public string ClientVersion     
  4.      {     
  5.          get { return "Last Test Sample Data:" + DateTime.Now.ToLongDateString();  }     
  6.          set { }           
  7.      }     
  8.  } 

宿主程序中實現組件的接入接口:

  
  
  
  
  1. public  class ClientVersionInfo     
  2.     {     
  3.         [ImportMany]     
  4.         public IEnumerable<Lazy<ExportFolder.IClientVersion>> ChangeDataCol { set; get; }     
  5.       
  6.         public string ConsoleChangeData()     
  7.         {     
  8.             string inputStr = string.Empty;     
  9.             if (this.ChangeDataCol != null && this.ChangeDataCol.Count() > 0)    
  10.              {    
  11.                  foreach (ExportFolder.IClientVersion currentVersioninfor in this.ChangeDataCol)    
  12.                  {    
  13.                      inputStr += currentVersioninfor.ClientVersion+"\r\n";    
  14.                  }    
  15.              }    
  16.              return inputStr;    
  17.          }    
  18.       
  19.      } 

爲了容許訪問元數據,MEF 使用 .NET Framework 4 的一個新 API,即 System.Lazy<T>。使用該 API 可延遲實例的實例化,直至訪問 Lazy 的 Value 屬性。MEF 使用 Lazy<T,TMetadata> 進一步擴展 Lazy<T>,以容許在不實例化基礎導出的狀況下訪問導出元數據.組合代碼不變 執行 在輸出時調用ConsoleChangeDAta()方法:

當需求發生更改時.組件可以不修改原來宿主程序代碼狀況下 快速加以擴展. 這樣以絕對隔離的方式大大簡化原來組件化須要維護和修改的代價.MEF則以很是簡單的方式實現靈活的擴展性支持.

本篇主要演示MEF簡單的使用方法.MEF基於組件基元在支持強大組合功能下依然具備很好的靈活性.而基於特性的編程模型.使咱們的宿主Code更加簡潔.容許咱們使用」特性聲明+類的定義」的方式來定義一個具備組合功能的組件.固然在MEF也將在VS2011版本中適用於Windows 8 Metro的應用程序. 但MEF2版本大多數高級功能可能會被移除.只關注MEF的主要通途-暴露擴展點和加載擴展.

官方並無發佈MEF For Windows phone 版本.下篇會介紹MEF For Windows phone應用程序中使用.

參考資料:

Managed Extensibility Framework Codeplex

Introduction to Managed Extensibility Framework

Managed Extensibility FrameWork Overview

接口實現:

  
  
  
  
  1. public class ClientRealseVersion:IClientVersion     
  2.  {     
  3.      [Export(typeof(IClientVersion))]     
  4.      public string ClientVersion     
  5.      {     
  6.          get {return "Current Client Version :1.0.4 !"; }     
  7.          set { }     
  8.      }     
  9.  } 
相關文章
相關標籤/搜索