public async Task <MetricListResponse> GetMetricsAsync(string resourceUri, string filterString, CancellationToken cancellationToken)
        {
            if (resourceUri == null)
            {
                throw new System.ArgumentNullException("resourceUri");
            }

            // Generate filter strings
            MetricFilter filter = MetricFilterExpressionParser.Parse(filterString);
            string       filterStringNamesOnly = filter.DimensionFilters == null ? null
                : ShoeboxHelper.GenerateMetricDefinitionFilterString(filter.DimensionFilters.Select(df => df.Name));

            // Get definitions for requested metrics
            IList <MetricDefinition> definitions =
                (await this.Client.MetricDefinitionOperations.GetMetricDefinitionsAsync(
                     resourceUri,
                     filterStringNamesOnly,
                     cancellationToken).ConfigureAwait(false)).MetricDefinitionCollection.Value;

            // Get Metrics with definitions
            return(await this.GetMetricsAsync(resourceUri, filterString, definitions, cancellationToken));
        }
        public async Task <MetricDefinitionListResponse> GetMetricDefinitionsAsync(string resourceUri, string filterString, CancellationToken cancellationToken)
        {
            MetricDefinitionListResponse result;

            string invocationId = TracingAdapter.NextInvocationId.ToString(CultureInfo.InvariantCulture);

            this.LogStartGetMetricDefinitions(invocationId, resourceUri, filterString);

            // Remove any '/' characters from the start since these are handled by the hydra (thin) client
            // Encode segments here since they are not encoded by hydra client
            resourceUri = ShoeboxHelper.EncodeUriSegments(resourceUri.TrimStart('/'));
            IEnumerable <MetricDefinition> definitions = null;

            // If no filter string, must request all metric definitions since we don't know if we have them all
            if (string.IsNullOrWhiteSpace(filterString))
            {
                // request all definitions
                definitions = (await this.GetMetricDefinitionsInternalAsync(resourceUri, string.Empty, CancellationToken.None).ConfigureAwait(false))
                              .MetricDefinitionCollection.Value;

                // cache definitions
                if (this.Client.IsCacheEnabled)
                {
                    this.Client.Cache[resourceUri] = definitions;
                }

                // wrap and return definitions
                result = new MetricDefinitionListResponse()
                {
                    StatusCode = HttpStatusCode.OK,
                    MetricDefinitionCollection = new MetricDefinitionCollection()
                    {
                        Value = definitions.ToList()
                    }
                };

                this.LogEndGetMetricDefinitions(invocationId, result);

                return(result);
            }

            // Parse the filter and retrieve cached definitions
            IEnumerable <string> names = MetricDefinitionFilterParser.Parse(filterString);

            if (this.Client.IsCacheEnabled)
            {
                definitions = this.Client.Cache[resourceUri];
            }

            // Find the names in the filter that don't appear on any of the cached definitions
            IEnumerable <string> missing = definitions == null
                ? names
                : names.Where((n => !definitions.Any(d => string.Equals(d.Name.Value, n, StringComparison.OrdinalIgnoreCase))));

            // Request any missing definitions and update cache (if any)
            if (missing.Any())
            {
                string missingFilter = ShoeboxHelper.GenerateMetricDefinitionFilterString(missing);

                // Request missing definitions
                var missingDefinitions = (await this.GetMetricDefinitionsInternalAsync(resourceUri, missingFilter, cancellationToken).ConfigureAwait(false))
                                         .MetricDefinitionCollection.Value;

                // merge definitions
                definitions = (definitions ?? new MetricDefinition[0]).Union(missingDefinitions);

                // Store the new set of definitions
                if (this.Client.IsCacheEnabled)
                {
                    this.Client.Cache[resourceUri] = definitions;
                }
            }

            // Filter out the metrics that were cached but not requested and wrap
            result = new MetricDefinitionListResponse()
            {
                StatusCode = HttpStatusCode.OK,
                MetricDefinitionCollection = new MetricDefinitionCollection()
                {
                    Value = definitions.Where(d => names.Contains(d.Name.Value)).ToList()
                }
            };

            this.LogEndGetMetricDefinitions(invocationId, result);

            return(result);
        }