MEF 透過屬性導向程式模型,依目錄動態發現組件內所有可組合部件。WPF 使用 DirectoryCatalog,Silverlight 則以 DeploymentCatalog 管理目錄、下載與組合。以下示範在 Silverlight 取得目前應用程式目錄資訊:
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var assembly = catalog.Assembly;
var parts = catalog.Parts;
為提升彈性,以介面抽象目錄操作:
public interface IDeploymentService
{
void AddXap(string relativeUri, Action<AsyncCompletedEventArgs> completedAction);
}
內部使用 AggregateCatalog 聚合多個 DeploymentCatalog,並透過 CompositionHost.Initialize 啟動 MEF 容器:
[Export(typeof(IDeploymentService))]
public class DeploymentCatalogService : IDeploymentService
{
private static AggregateCatalog _aggregateCatalog;
private readonly Dictionary<string, DeploymentCatalog> _catalogs = new();
public static void Initialize()
{
_aggregateCatalog = new AggregateCatalog();
_aggregateCatalog.Catalogs.Add(new DeploymentCatalog());
CompositionHost.Initialize(_aggregateCatalog);
}
public void AddXap(string relativeUri, Action<AsyncCompletedEventArgs> completedAction)
{
if (!_catalogs.TryGetValue(relativeUri, out var catalog))
{
catalog = new DeploymentCatalog(relativeUri);
catalog.DownloadCompleted += (s, e) => completedAction?.Invoke(e) ?? DownloadCompleted(e);
catalog.DownloadAsync();
_catalogs[relativeUri] = catalog;
_aggregateCatalog.Catalogs.Add(catalog);
}
}
private void DownloadCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
throw new InvalidOperationException(e.Error.Message, e.Error);
}
}
呼叫端極簡單:
private void button1_Click(object sender, RoutedEventArgs e)
{
this.Service.AddXap("MEFTraining.MefCatalogs.Parts.xap", null);
}
後續可結合契約介面與中繼資料策略實現集中控制,詳細將於後續文章說明。