///<summary> /// Compute ActivityAssemblyItem dependencies /// </summary> /// <param name="client"></param> /// <param name="assemblies"></param> /// <returns></returns> public static List<ActivityAssemblyItem> ComputeDependencies(IWorkflowsQueryService client, List<ActivityAssemblyItem> assemblies) { List<ActivityLibraryDC> assembliesOnServer; var dependencies = new MultiMap<int, int>(); var neededIDs = new HashSet<int>(); try { assembliesOnServer = client.GetAllActivityLibraries(new GetAllActivityLibrariesRequestDC().SetIncaller()).List; } catch (FaultException<ServiceFault> ex) { throw new CommunicationException(ex.Detail.ErrorMessage); } catch (FaultException<ValidationFault> ex) { throw new BusinessValidationException(ex.Detail.ErrorMessage); } catch (Exception ex) { throw new CommunicationException(ex.Message); } // get dependencies for each assembly foreach (var assembly in assemblies) { var dependenciesByID = client.StoreActivityLibraryDependenciesTreeGet(DataContractTranslator.ActivityAssemblyItemToStoreActivityLibrariesDependenciesDC(assembly)); // for some reason, QueryService sends back list of lists instead of flattened list foreach (var dependencyContainer in dependenciesByID) { foreach (var dependency in dependencyContainer.StoreDependenciesDependentActiveLibraryList) { // If A needs B, then A is the "parent" according to the data contract var needs = dependency.activityLibraryParentId; var needed = dependency.activityLibraryDependentId; dependencies.AddValue(needs, needed); neededIDs.Add(needed); } } } var lookupById = new Dictionary<int, AssemblyName>(); foreach (var serverAssembly in assembliesOnServer) { // determine the version number (can be nullable) Version serverAssemblyVersion = Version.TryParse(serverAssembly.VersionNumber, out serverAssemblyVersion) ? serverAssemblyVersion : null; // Don't use assembliesOnServer.ToDictionary() because test code can have key conflicts, e.g. all Id = 0 for some tests // that don't care about dependencies. lookupById[serverAssembly.Id] = new AssemblyName { Name = serverAssembly.Name, Version = serverAssemblyVersion }; } var assembliesAndDependencies = new List<ActivityAssemblyItem>( from dbAsm in assembliesOnServer where neededIDs.Contains(dbAsm.Id) let cached = ActivityAssemblyItems.FirstOrDefault( cached => string.Equals(cached.Name, dbAsm.Name) && string.Equals(cached.Version, dbAsm.VersionNumber) ) // prefer cached version over DB version to prevent re-download select cached ?? DataContractTranslator.ActivityLibraryDCToActivityAssemblyItem(dbAsm, from depId in dependencies.GetValues(dbAsm.Id).Distinct() let dependency = lookupById[depId] orderby dependency.Name, dependency.Version select dependency) ); return assembliesAndDependencies; // pull it out into a separate variable for debuggability, vs. returning immediately }