MEF的一點理解

0.我例子的工程結構

1.首先在程序啓動時拿到要動態加載dll所在的目錄。WepApplication中的Global.asax文件中:

public static DirectoryCatalog Catalog;
        protected void Application_Start(object sender, EventArgs e)
        {
            LoadProviderCatalog();
        }
        private void LoadProviderCatalog()
        {
            string assemblyPath = ConfigurationManager.AppSettings["AssemblyFolder"].ToString();
            assemblyPath = Path.Combine(HostingEnvironment.MapPath("~/"), assemblyPath);

            Catalog = new DirectoryCatalog(assemblyPath);
        }

2.在使用MEF目錄進行導出部件託管的時候,在某些需求下或許只需要其中的一個部件,這種情況可以通過遍歷部件集合得到。然而MEF也爲此提供了一種解決方案,那就是使用目錄過濾篩選功能。MEF中的ComposablePartCatalog類和INotifyComposablePartCatalogChanged接口就是專門用來實現目錄篩選的,可以如下代碼段中演示的對目錄過濾的封裝。

public sealed class FilteredCatalog : ComposablePartCatalog
    {
        private readonly ComposablePartCatalog _inner;
        private readonly INotifyComposablePartCatalogChanged _innerNotifyChange;
        private readonly IQueryable<ComposablePartDefinition> _partsQuery;

        public FilteredCatalog(
                               ComposablePartCatalog inner,
                               Expression<Func<ComposablePartDefinition, bool>> expression)
        {
            _inner = inner;
            _innerNotifyChange = inner as INotifyComposablePartCatalogChanged;
            _partsQuery = inner.Parts.Where(expression);
        }

        public override IQueryable<ComposablePartDefinition> Parts
        {
            get
            {
                return _partsQuery;
            }
        }
    }

3.MEF中提供了一個專門用於目錄過濾篩選的元數據特性PartMetadata,要進行目錄部件的篩選過濾就需要通過PartMetadata特性的標註,MEF容器才能進行正確的裝配。

public interface ILogger
    {
        string WriteLog();
    }

    [Export(typeof(ILogger))]
    [PartMetadata("AssemblyName", "TXTLogger")]
    public class TXTLogger:ILogger
    {
        public string WriteLog() 
        {
            return "TXTLogger";
        }
    }

    [Export(typeof(ILogger))]
    [PartMetadata("AssemblyName", "DebugLogger")]
    public class DebugLogger : ILogger
    {
        public string WriteLog()
        {
            return "DebugLogger";
        }
    }

4.通過上面的封裝,使用目錄過濾功能之需要傳入正確的篩選表達式就可以了,按照MEF中的約定其篩選表達式應如下格式

public static ILogger GetLoggerInstance(string assemblyName) 
        {
            var container = new CompositionContainer(Global.Catalog);
            var filteredCatalog = new FilteredCatalog(
                Global.Catalog,
                (def) => ValidateAssemblyName(def, assemblyName));
            var subContainer = new CompositionContainer(filteredCatalog, container);

            ILogger logger = subContainer.GetExportedValueOrDefault<ILogger>();
            return logger;
        }

        private static bool ValidateAssemblyName(ComposablePartDefinition def, string assemblyName)
        {
            if (def.Metadata.ContainsKey("AssemblyName"))
            {
                if (def.Metadata["AssemblyName"] != null)
                {
                    List<string> assemblyNames = new List<string>(def.Metadata["AssemblyName"].ToString().Split(','));
                    return assemblyNames.Contains(assemblyName);
                }
            }

            return false;
        }

5.下面是代碼塊演示瞭如何從目錄中篩選出元數據名稱爲"TXTLogger"以及爲"DebugLogger"的ILogger的實例

ILogger TXTLogger = Utility.GetLoggerInstance("TXTLogger");
ILogger DebugLogger = Utility.GetLoggerInstance("DebugLogger");

6.Build工程後,將dll拷貝到我們指定的文件夾地下,只需要在build event的post-build events command line中加上這樣一句話(不過需要當前的工程引用了這兩個工程纔可以):

if EXIST "$(ProjectDir)bin\AssemblyFolder" del /F /S /Q "$(ProjectDir)bin\AssemblyFolder"
          robocopy "$(ProjectDir)bin" "$(ProjectDir)bin\AssemblyFolder" "*.HostMEFPartmetadata.*.*" /mov /xf "*.HostMEFPartmetadata.dll" "*.HostMEFPartmetadata.pdb"
          set errorlevel = 0
          echo "moved provider files to $(ProjectDir)bin\AssemblyFolder"


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章