/// <summary> /// Validates the list of plugins loaded by MEF. /// </summary> public void ValidatePlugins(ISplashView splashView) { _plugins.Clear(); var dict = new Dictionary <Guid, BasePlugin>(); if (_mefPlugins == null) { return; } foreach (var item in _mefPlugins) { var p = item.Value as BasePlugin; if (p == null) { Logger.Current.Warn("Invalid plugin type: plugin must inherit from BasePlugin type."); continue; } try { p.Identity = PluginIdentityHelper.GetIdentity(p.GetType(), item.Metadata); } catch (Exception ex) { throw new ApplicationException("Failed to load plugin identity from assembly.", ex); } // TODO: make sure that application plugins will have priority if duplicate GUIDs are found if (dict.ContainsKey(p.Identity.Guid)) { var p2 = dict[p.Identity.Guid]; string msg = string.Format("Plugins have duplicate GUIDs: {0} {1}", p, p2); throw new ApplicationException(msg); } splashView.ShowStatus("正在检查:" + p.Description); dict.Add(p.Identity.Guid, p); _container.RegisterInstance(p.GetType(), p); _plugins.Add(p); } #if DEBUG // I didn't caught anything by this check so far; // Perhaps better just to check for particular assemblies in Plugins folder // and display warning if they are present CheckDuplicatedAssemblies(); #endif }
private Tuple <int, List <Lazy <IPlugin, IPluginMetadata> > > SortPluginsFor( Lazy <IPlugin, IPluginMetadata> currentItem, List <Lazy <IPlugin, IPluginMetadata> > pickList, List <Lazy <IPlugin, IPluginMetadata> > resultList) { // No more items to process? if (currentItem == null) { return(Tuple.Create(-1, resultList)); } // Check if item is already processed: if (resultList.Contains(currentItem)) { return(Tuple.Create(resultList.IndexOf(currentItem), resultList)); } // Satisfy before dependents var minIndex = int.MaxValue; foreach (var beforeName in currentItem.Metadata.Before) { // Find the dependency var dependency = pickList.FirstOrDefault(i => { if (!i.Metadata.Empty) { return(i.Metadata.Name == beforeName); } else { return(PluginIdentityHelper.GetIdentity(i.Value.GetType(), i.Metadata).Name == beforeName); } }); if (dependency == null) { Logger.Current.Info($"Could not find before dependency '{beforeName}' for plugin '{currentItem.Value}'"); return(Tuple.Create(-1, resultList)); // bail out - this plugins dependencies aren't satisfied } // Get the index of the dependecy var beforeIndex = resultList.IndexOf(dependency); if (beforeIndex < 0) // not in the result list yet { // Resolve the dependency's order var sortResult = SortPluginsFor(dependency, pickList, resultList); beforeIndex = sortResult.Item1; resultList = sortResult.Item2; if (beforeIndex < 0) { Logger.Current.Info($"Could not satisfy before dependency '{beforeName}' for plugin '{currentItem.Value}'"); return(Tuple.Create(-1, resultList)); // bail out - this plugins dependencies aren't satisfied } } // Keep track of the lowest index if (minIndex > beforeIndex) { minIndex = beforeIndex; } } // Satisfy after dependencies var maxIndex = 0; foreach (var afterName in currentItem.Metadata.After) { // Find the dependency var dependency = pickList.FirstOrDefault(i => { if (!i.Metadata.Empty) { return(i.Metadata.Name == afterName); } else { return(PluginIdentityHelper.GetIdentity(i.Value.GetType(), i.Metadata).Name == afterName); } }); if (dependency == null) { Logger.Current.Info($"Could not find after dependency '{afterName}' for plugin '{currentItem.Value}'"); return(Tuple.Create(-1, resultList)); // bail out - this plugins dependencies aren't satisfied } // Get the index of the dependecy var afterIndex = resultList.IndexOf(dependency); if (afterIndex < 0) // not in the result list yet { // Resolve the dependency's order var sortResult = SortPluginsFor(dependency, pickList, resultList); afterIndex = sortResult.Item1; resultList = sortResult.Item2; if (afterIndex < 0) { Logger.Current.Info($"Could not satisfy after dependency '{afterName}' for plugin '{currentItem.Value}'"); return(Tuple.Create(-1, resultList)); // bail out - this plugins dependencies aren't satisfied } // We want it to be inserted AFTER this: afterIndex++; } // Keep track of the lowest index if (maxIndex < afterIndex) { maxIndex = afterIndex; } } // If we have restrictions in both directions, ensure we can meet them both: if (currentItem.Metadata.Before.Any() && currentItem.Metadata.After.Any() && minIndex >= maxIndex) { Logger.Current.Info($"Could not satisfy dependency restrictions for plugin '{currentItem.Value}'"); return(Tuple.Create(-1, resultList)); // bail out - this plugins dependencies aren't satisfied } // Insert item at highest possible index resultList.Insert(maxIndex, currentItem); return(Tuple.Create(maxIndex, resultList)); }