private Tuple <ITargetBlock <Assembly>, Task <DiscoveredParts> > CreateAssemblyDiscoveryBlockChain(IProgress <DiscoveryProgress> progress, CancellationToken cancellationToken) { var progressFilter = new ProgressFilter(progress); var tuple = this.CreateDiscoveryBlockChain(false, progressFilter, cancellationToken); var exceptions = new List <PartDiscoveryException>(); var assemblyBlock = new TransformManyBlock <Assembly, Type>( a => { IReadOnlyCollection <Type> types; try { // Fully realize any enumerable now so that we can catch the exception rather than // leave it to dataflow to catch it. types = this.GetTypes(a).ToList(); } catch (ReflectionTypeLoadException ex) { var partDiscoveryException = new PartDiscoveryException(string.Format(CultureInfo.CurrentCulture, Strings.ReflectionTypeLoadExceptionWhileEnumeratingTypes, a.Location), ex) { AssemblyPath = a.Location }; lock (exceptions) { exceptions.Add(partDiscoveryException); } types = ex.Types.Where(t => t != null).ToList(); } catch (Exception ex) { var partDiscoveryException = new PartDiscoveryException(string.Format(CultureInfo.CurrentCulture, Strings.UnableToEnumerateTypes, a.Location), ex) { AssemblyPath = a.Location }; lock (exceptions) { exceptions.Add(partDiscoveryException); } return(Enumerable.Empty <Type>()); } progressFilter.OnDiscoveredMoreTypes(types.Count); return(types); }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = Debugger.IsAttached ? 1 : Environment.ProcessorCount, CancellationToken = cancellationToken, }); assemblyBlock.LinkTo(tuple.Item1, new DataflowLinkOptions { PropagateCompletion = true }); var tcs = new TaskCompletionSource <DiscoveredParts>(); Task.Run(async delegate { try { var parts = await tuple.Item2.ConfigureAwait(false); tcs.SetResult(parts.Merge(new DiscoveredParts(Enumerable.Empty <ComposablePartDefinition>(), exceptions))); } catch (Exception ex) { tcs.SetException(ex); } }); return(Tuple.Create <ITargetBlock <Assembly>, Task <DiscoveredParts> >(assemblyBlock, tcs.Task)); }