private async Task <ModelResult> ProcessAsync(
            string dtmi, bool async, ModelDependencyResolution dependencyResolution, CancellationToken cancellationToken)
        {
            Queue <string> toProcessModels = PrepareWork(dtmi);
            var            processedModels = new Dictionary <string, string>();

            // If ModelDependencyResolution.Enabled is requested the client will first attempt to fetch
            // metadata.json content from the target repository. The metadata object includes supported features
            // of the repository.
            // If the metadata indicates expanded models are available. The client will try to fetch pre-computed model
            // dependencies using .expanded.json.
            // If the model expanded form does not exist fall back to computing model dependencies just-in-time.
            if (dependencyResolution == ModelDependencyResolution.Enabled && _metadataScheduler.ShouldFetchMetadata())
            {
                ModelsRepositoryMetadata repositoryMetadata = async
                    ? await FetchMetadataAsync(cancellationToken).ConfigureAwait(false)
                    : FetchMetadata(cancellationToken);

                if (repositoryMetadata != null &&
                    repositoryMetadata.Features != null &&
                    repositoryMetadata.Features.Expanded)
                {
                    _repositorySupportsExpanded = true;
                }
                else
                {
                    _repositorySupportsExpanded = false;
                }

                _metadataScheduler.MarkAsFetched();
            }

            // Covers case when the repository supports expanded but dependency resolution is disabled.
            bool tryFromExpanded = (dependencyResolution == ModelDependencyResolution.Enabled) && _repositorySupportsExpanded;

            while (toProcessModels.Count != 0)
            {
                cancellationToken.ThrowIfCancellationRequested();

                string targetDtmi = toProcessModels.Dequeue();
                if (processedModels.ContainsKey(targetDtmi))
                {
                    ModelsRepositoryEventSource.Instance.SkippingPreprocessedDtmi(targetDtmi);
                    continue;
                }

                ModelsRepositoryEventSource.Instance.ProcessingDtmi(targetDtmi);

                FetchModelResult result = async
                    ? await FetchModelAsync(targetDtmi, tryFromExpanded, cancellationToken).ConfigureAwait(false)
                    : FetchModel(targetDtmi, tryFromExpanded, cancellationToken);

                if (result.FromExpanded)
                {
                    Dictionary <string, string> expanded = new ModelQuery(result.Definition).ListToDict();

                    foreach (KeyValuePair <string, string> kvp in expanded)
                    {
                        if (!processedModels.ContainsKey(kvp.Key))
                        {
                            processedModels.Add(kvp.Key, kvp.Value);
                        }
                    }

                    continue;
                }

                ModelMetadata metadata = new ModelQuery(result.Definition).ParseModel();

                if (dependencyResolution >= ModelDependencyResolution.Enabled)
                {
                    IList <string> dependencies = metadata.Dependencies;

                    if (dependencies.Count > 0)
                    {
                        ModelsRepositoryEventSource.Instance.DiscoveredDependencies(string.Join("\", \"", dependencies));
                    }

                    foreach (string dep in dependencies)
                    {
                        toProcessModels.Enqueue(dep);
                    }
                }

                string parsedDtmi = metadata.Id;
                if (!parsedDtmi.Equals(targetDtmi, StringComparison.Ordinal))
                {
                    ModelsRepositoryEventSource.Instance.IncorrectDtmi(targetDtmi, parsedDtmi);
                    string formatErrorMsg =
                        $"{string.Format(CultureInfo.InvariantCulture, StandardStrings.GenericGetModelsError, targetDtmi)} " +
                        string.Format(CultureInfo.InvariantCulture, StandardStrings.IncorrectDtmi, targetDtmi, parsedDtmi);

                    throw new RequestFailedException(formatErrorMsg, new FormatException(formatErrorMsg));
                }

                processedModels.Add(targetDtmi, result.Definition);
            }

            return(new ModelResult(processedModels));
        }
        private async Task <IDictionary <string, string> > ProcessAsync(
            IEnumerable <string> dtmis, bool async, ModelDependencyResolution dependencyResolution, CancellationToken cancellationToken)
        {
            var            processedModels = new Dictionary <string, string>();
            Queue <string> toProcessModels = PrepareWork(dtmis);

            while (toProcessModels.Count != 0)
            {
                cancellationToken.ThrowIfCancellationRequested();

                string targetDtmi = toProcessModels.Dequeue();
                if (processedModels.ContainsKey(targetDtmi))
                {
                    ModelsRepositoryEventSource.Instance.SkippingPreprocessedDtmi(targetDtmi);
                    continue;
                }

                ModelsRepositoryEventSource.Instance.ProcessingDtmi(targetDtmi);

                FetchResult result = async
                    ? await FetchAsync(targetDtmi, dependencyResolution, cancellationToken).ConfigureAwait(false)
                    : Fetch(targetDtmi, dependencyResolution, cancellationToken);

                if (result.FromExpanded)
                {
                    Dictionary <string, string> expanded = new ModelQuery(result.Definition).ListToDict();

                    foreach (KeyValuePair <string, string> kvp in expanded)
                    {
                        if (!processedModels.ContainsKey(kvp.Key))
                        {
                            processedModels.Add(kvp.Key, kvp.Value);
                        }
                    }

                    continue;
                }

                ModelMetadata metadata = new ModelQuery(result.Definition).ParseModel();

                if (dependencyResolution >= ModelDependencyResolution.Enabled)
                {
                    IList <string> dependencies = metadata.Dependencies;

                    if (dependencies.Count > 0)
                    {
                        ModelsRepositoryEventSource.Instance.DiscoveredDependencies(string.Join("\", \"", dependencies));
                    }

                    foreach (string dep in dependencies)
                    {
                        toProcessModels.Enqueue(dep);
                    }
                }

                string parsedDtmi = metadata.Id;
                if (!parsedDtmi.Equals(targetDtmi, StringComparison.Ordinal))
                {
                    ModelsRepositoryEventSource.Instance.IncorrectDtmiCasing(targetDtmi, parsedDtmi);
                    string formatErrorMsg =
                        $"{string.Format(CultureInfo.InvariantCulture, StandardStrings.GenericGetModelsError, targetDtmi)} " +
                        string.Format(CultureInfo.InvariantCulture, StandardStrings.IncorrectDtmiCasing, targetDtmi, parsedDtmi);

                    throw new RequestFailedException(formatErrorMsg, new FormatException(formatErrorMsg));
                }

                processedModels.Add(targetDtmi, result.Definition);
            }

            return(processedModels);
        }