/// <summary>
        /// Generates search graph containing nodes matching search criteria in Solution Explorer
        /// and attaches it to correct top level node.
        /// </summary>
        private void Search(IGraphContext graphContext)
        {
            string searchParametersTypeName            = typeof(ISolutionSearchParameters).GUID.ToString();
            ISolutionSearchParameters searchParameters = graphContext.GetValue <ISolutionSearchParameters>(searchParametersTypeName);

            string searchTerm = searchParameters?.SearchQuery.SearchString?.ToLowerInvariant();

            if (searchTerm == null)
            {
                return;
            }

            var cachedDependencyToMatchingResultsMap = new Dictionary <string, HashSet <IDependency> >(StringComparer.OrdinalIgnoreCase);
            var searchResultsPerContext = new Dictionary <string, HashSet <IDependency> >(StringComparer.OrdinalIgnoreCase);

            System.Collections.Generic.IReadOnlyCollection <IDependenciesSnapshotProvider> snapshotProviders = AggregateSnapshotProvider.GetSnapshotProviders();
            foreach (IDependenciesSnapshotProvider snapshotProvider in snapshotProviders)
            {
                IDependenciesSnapshot snapshot = snapshotProvider.CurrentSnapshot;
                if (snapshot == null)
                {
                    continue;
                }

                searchResultsPerContext[snapshotProvider.ProjectFilePath] = SearchFlat(
                    searchTerm.ToLowerInvariant(),
                    snapshot);
            }

            foreach (IDependenciesSnapshotProvider snapshotProvider in snapshotProviders)
            {
                IDependenciesSnapshot snapshot = snapshotProvider.CurrentSnapshot;
                if (snapshot == null)
                {
                    continue;
                }

                IEnumerable <IDependency> allTopLevelDependencies = snapshot.GetFlatTopLevelDependencies();
                HashSet <IDependency>     matchedDependencies     = searchResultsPerContext[snapshotProvider.ProjectFilePath];

                using (var scope = new GraphTransactionScope())
                {
                    foreach (IDependency topLevelDependency in allTopLevelDependencies)
                    {
                        ITargetedDependenciesSnapshot targetedSnapshot = snapshot.Targets[topLevelDependency.TargetFramework];

                        if (!cachedDependencyToMatchingResultsMap
                            .TryGetValue(topLevelDependency.Id, out HashSet <IDependency> topLevelDependencyMatches))
                        {
                            IDependenciesGraphViewProvider viewProvider = ViewProviders
                                                                          .FirstOrDefaultValue((x, d) => x.SupportsDependency(d), topLevelDependency);

                            if (viewProvider == null)
                            {
                                continue;
                            }

                            bool processed = viewProvider.MatchSearchResults(
                                snapshotProvider.ProjectFilePath,
                                topLevelDependency,
                                searchResultsPerContext,
                                out topLevelDependencyMatches);

                            if (!processed)
                            {
                                if (matchedDependencies.Count == 0)
                                {
                                    continue;
                                }

                                topLevelDependencyMatches = GetMatchingResultsForDependency(
                                    topLevelDependency,
                                    targetedSnapshot,
                                    matchedDependencies,
                                    cachedDependencyToMatchingResultsMap);
                            }

                            cachedDependencyToMatchingResultsMap[topLevelDependency.Id] = topLevelDependencyMatches;
                        }

                        if (topLevelDependencyMatches.Count == 0)
                        {
                            continue;
                        }

                        GraphNode topLevelNode = Builder.AddTopLevelGraphNode(graphContext,
                                                                              snapshotProvider.ProjectFilePath,
                                                                              topLevelDependency.ToViewModel(targetedSnapshot));
                        foreach (IDependency matchedDependency in topLevelDependencyMatches)
                        {
                            GraphNode matchedDependencyNode = Builder.AddGraphNode(graphContext,
                                                                                   snapshotProvider.ProjectFilePath,
                                                                                   topLevelNode,
                                                                                   matchedDependency.ToViewModel(targetedSnapshot));

                            graphContext.Graph.Links.GetOrCreate(topLevelNode,
                                                                 matchedDependencyNode,
                                                                 label: null,
                                                                 GraphCommonSchema.Contains);
                        }

                        if (topLevelNode != null)
                        {
                            // 'node' is a GraphNode for top level dependency (which is part of solution explorer tree)
                            // Setting ProjectItem category (and correct GraphNodeId) ensures that search graph appears
                            // under right solution explorer hierarchy item
                            topLevelNode.AddCategory(CodeNodeCategories.ProjectItem);
                        }
                    }

                    scope.Complete();
                }
            }

            graphContext.OnCompleted();
        }