From 647c11bb212eb2fdeb69005656a40796df51059a Mon Sep 17 00:00:00 2001 From: Jason Taylor Date: Tue, 21 Oct 2025 09:19:46 +1000 Subject: [PATCH 1/8] Upgrade aspnetcore packages --- src/Directory.Packages.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 7420a4033f..d50e482f68 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -17,8 +17,8 @@ - - + + From da6b0e0a2c1108ab8af81a976f725b0f9155463c Mon Sep 17 00:00:00 2001 From: Jason Taylor Date: Tue, 21 Oct 2025 10:30:51 +1000 Subject: [PATCH 2/8] Replace deprecated package --- src/Directory.Packages.props | 2 +- .../AzureQuery.cs | 38 ++++++++++--------- .../ServiceControl.Transports.ASBS.csproj | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index d50e482f68..c834c29371 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -8,7 +8,7 @@ - + diff --git a/src/ServiceControl.Transports.ASBS/AzureQuery.cs b/src/ServiceControl.Transports.ASBS/AzureQuery.cs index 041b2bc246..570ca90db2 100644 --- a/src/ServiceControl.Transports.ASBS/AzureQuery.cs +++ b/src/ServiceControl.Transports.ASBS/AzureQuery.cs @@ -12,8 +12,8 @@ namespace ServiceControl.Transports.ASBS; using Azure.Core; using Azure.Core.Pipeline; using Azure.Identity; -using Azure.Monitor.Query; -using Azure.Monitor.Query.Models; +using Azure.Monitor.Query.Metrics; +using Azure.Monitor.Query.Metrics.Models; using Azure.ResourceManager; using Azure.ResourceManager.Resources; using Azure.ResourceManager.ServiceBus; @@ -26,7 +26,7 @@ public class AzureQuery(ILogger logger, TimeProvider timeProvider, T : BrokerThroughputQuery(logger, "AzureServiceBus") { string serviceBusName = string.Empty; - MetricsQueryClient? client; + MetricsClient? client; ArmClient? armClient; string? resourceId; ArmEnvironment armEnvironment; @@ -129,8 +129,8 @@ protected override void InitializeCore(ReadOnlyDictionary settin clientCredentials = new ClientSecretCredential(tenantId, clientId, clientSecret); } - client = new MetricsQueryClient(armEnvironment.Endpoint, clientCredentials, - new MetricsQueryClientOptions + client = new MetricsClient(armEnvironment.Endpoint, clientCredentials, + new MetricsClientOptions { Audience = metricsQueryAudience, Transport = new HttpClientTransport( @@ -152,31 +152,31 @@ protected override void InitializeCore(ReadOnlyDictionary settin return; - (ArmEnvironment armEnvironment, MetricsQueryAudience metricsQueryAudience) GetEnvironment() + (ArmEnvironment armEnvironment, MetricsClientAudience metricsQueryAudience) GetEnvironment() { if (managementUrlParsed == null) { - return (ArmEnvironment.AzurePublicCloud, MetricsQueryAudience.AzurePublicCloud); + return (ArmEnvironment.AzurePublicCloud, MetricsClientAudience.AzurePublicCloud); } if (managementUrlParsed == ArmEnvironment.AzurePublicCloud.Endpoint) { - return (ArmEnvironment.AzurePublicCloud, MetricsQueryAudience.AzurePublicCloud); + return (ArmEnvironment.AzurePublicCloud, MetricsClientAudience.AzurePublicCloud); } if (managementUrlParsed == ArmEnvironment.AzureChina.Endpoint) { - return (ArmEnvironment.AzureChina, MetricsQueryAudience.AzureChina); + return (ArmEnvironment.AzureChina, MetricsClientAudience.AzureChina); } if (managementUrlParsed == ArmEnvironment.AzureGermany.Endpoint) { - return (ArmEnvironment.AzureGermany, MetricsQueryAudience.AzurePublicCloud); + return (ArmEnvironment.AzureGermany, MetricsClientAudience.AzurePublicCloud); } if (managementUrlParsed == ArmEnvironment.AzureGovernment.Endpoint) { - return (ArmEnvironment.AzureGovernment, MetricsQueryAudience.AzureGovernment); + return (ArmEnvironment.AzureGovernment, MetricsClientAudience.AzureGovernment); } string options = string.Join(", ", @@ -187,7 +187,7 @@ protected override void InitializeCore(ReadOnlyDictionary settin }.Select(armEnvironment => $"\"{armEnvironment.Endpoint}\"")); InitialiseErrors.Add($"Management url configuration is invalid, available options are {options}"); - return (ArmEnvironment.AzurePublicCloud, MetricsQueryAudience.AzurePublicCloud); + return (ArmEnvironment.AzurePublicCloud, MetricsClientAudience.AzurePublicCloud); } } @@ -247,20 +247,22 @@ public override async IAsyncEnumerable GetThroughputPerDay(IBro async Task> GetMetrics(string queueName, DateOnly startTime, DateOnly endTime, CancellationToken cancellationToken = default) { - var response = await client!.QueryResourceAsync(resourceId, - new[] { "CompleteMessage" }, - new MetricsQueryOptions + var response = await client!.QueryResourcesAsync( + [new ResourceIdentifier(resourceId!)], + ["CompleteMessage"], + "Microsoft.ServiceBus/namespaces", + new MetricsQueryResourcesOptions { Filter = $"EntityName eq '{queueName}'", - TimeRange = new QueryTimeRange(startTime.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc), endTime.ToDateTime(TimeOnly.MaxValue, DateTimeKind.Utc)), + TimeRange = new MetricsQueryTimeRange(startTime.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc), endTime.ToDateTime(TimeOnly.MaxValue, DateTimeKind.Utc)), Granularity = TimeSpan.FromDays(1) }, cancellationToken); var metricValues = - response.Value.Metrics.FirstOrDefault()?.TimeSeries.FirstOrDefault()?.Values ?? []; + response.Value.Values.FirstOrDefault()?.Metrics.FirstOrDefault()?.TimeSeries.FirstOrDefault()?.Values ?? []; - return metricValues; + return metricValues.AsReadOnly(); } public override async IAsyncEnumerable GetQueueNames( diff --git a/src/ServiceControl.Transports.ASBS/ServiceControl.Transports.ASBS.csproj b/src/ServiceControl.Transports.ASBS/ServiceControl.Transports.ASBS.csproj index ef7f0fd2f5..a338339ece 100644 --- a/src/ServiceControl.Transports.ASBS/ServiceControl.Transports.ASBS.csproj +++ b/src/ServiceControl.Transports.ASBS/ServiceControl.Transports.ASBS.csproj @@ -12,7 +12,7 @@ - + From d0705d694952e882e2e8af4918660c8112e08b0f Mon Sep 17 00:00:00 2001 From: Jason Taylor Date: Wed, 22 Oct 2025 11:25:18 +1000 Subject: [PATCH 3/8] Use regional metrics endpoint --- .../AzureQuery.cs | 69 ++++++++++++++----- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/src/ServiceControl.Transports.ASBS/AzureQuery.cs b/src/ServiceControl.Transports.ASBS/AzureQuery.cs index 570ca90db2..d2dc320b54 100644 --- a/src/ServiceControl.Transports.ASBS/AzureQuery.cs +++ b/src/ServiceControl.Transports.ASBS/AzureQuery.cs @@ -28,8 +28,11 @@ public class AzureQuery(ILogger logger, TimeProvider timeProvider, T string serviceBusName = string.Empty; MetricsClient? client; ArmClient? armClient; + TokenCredential? credential; + Uri? metricsEndpoint; string? resourceId; ArmEnvironment armEnvironment; + MetricsClientAudience metricsQueryAudience; protected override void InitializeCore(ReadOnlyDictionary settings) { @@ -102,7 +105,7 @@ protected override void InitializeCore(ReadOnlyDictionary settin Diagnostics.AppendLine("Client secret set"); } - (armEnvironment, var metricsQueryAudience) = GetEnvironment(); + (armEnvironment, metricsQueryAudience) = GetEnvironment(); if (managementUrl == null) { @@ -118,28 +121,17 @@ protected override void InitializeCore(ReadOnlyDictionary settin return; } - TokenCredential clientCredentials; if (connectionSettings.AuthenticationMethod is TokenCredentialAuthentication tokenCredentialAuthentication) { Diagnostics.AppendLine("Attempting to use managed identity"); - clientCredentials = tokenCredentialAuthentication.Credential; + credential = tokenCredentialAuthentication.Credential; } else { - clientCredentials = new ClientSecretCredential(tenantId, clientId, clientSecret); + credential = new ClientSecretCredential(tenantId, clientId, clientSecret); } - client = new MetricsClient(armEnvironment.Endpoint, clientCredentials, - new MetricsClientOptions - { - Audience = metricsQueryAudience, - Transport = new HttpClientTransport( - new HttpClient(new SocketsHttpHandler - { - PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2) - })) - }); - armClient = new ArmClient(clientCredentials, subscriptionId, + armClient = new ArmClient(credential, subscriptionId, new ArmClientOptions { Environment = armEnvironment, @@ -229,7 +221,6 @@ public override async IAsyncEnumerable GetThroughputPerDay(IBro while (currentDate <= endDate) { data.Add(currentDate, new QueueThroughput { TotalThroughput = 0, DateUTC = currentDate }); - currentDate = currentDate.AddDays(1); } @@ -274,12 +265,37 @@ public override async IAsyncEnumerable GetQueueNames( var namespaces = subscription.GetServiceBusNamespacesAsync(cancellationToken); - await foreach (var serviceBusNamespaceResource in namespaces.WithCancellation( - cancellationToken)) + await foreach (var serviceBusNamespaceResource in namespaces.WithCancellation(cancellationToken)) { if (validNamespaces.Contains(serviceBusNamespaceResource.Data.Name)) { resourceId = serviceBusNamespaceResource.Id; + + // Determine the region of the namespace + var regionName = serviceBusNamespaceResource.Data.Location.Name; + + // Build the regional Azure Monitor Metrics endpoint from the audience + var newEndpoint = BuildMetricsEndpointFromAudience(metricsQueryAudience, regionName); + + // Create or refresh the MetricsClient if it's missing or points to a different region + if (client is null || metricsEndpoint?.ToString() != newEndpoint.ToString()) + { + metricsEndpoint = newEndpoint; + + client = new MetricsClient( + metricsEndpoint, + credential!, + new MetricsClientOptions + { + Audience = metricsQueryAudience, + Transport = new HttpClientTransport( + new HttpClient(new SocketsHttpHandler + { + PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2) + })) + }); + } + await foreach (var queue in serviceBusNamespaceResource.GetServiceBusQueues() .WithCancellation(cancellationToken)) { @@ -303,6 +319,21 @@ public override async IAsyncEnumerable GetQueueNames( { ArmEnvironment.AzureChina, "servicebus.chinacloudapi.cn" }, }; + // Build metrics endpoint host directly from the configured audience. + Uri BuildMetricsEndpointFromAudience(MetricsClientAudience audience, string regionName) + { + var region = regionName.ToLowerInvariant(); + + var audienceUri = new Uri(audience.ToString()); + var audienceHost = audienceUri.Host; // e.g., "metrics.monitor.azure.com" + + var regionalHost = audienceHost.StartsWith("metrics.", StringComparison.OrdinalIgnoreCase) + ? audienceHost.Replace("metrics.", $"{region}.metrics.") + : $"{region}.metrics.{audienceHost}"; + + return new Uri($"https://{regionalHost}"); + } + async Task> GetValidNamespaceNames(CancellationToken cancellationToken = default) { var validNamespaces = new HashSet(StringComparer.OrdinalIgnoreCase) { serviceBusName }; @@ -374,4 +405,4 @@ public static class AzureServiceBusSettings public static readonly string ManagementUrl = "ASB/ManagementUrl"; public static readonly string ManagementUrlDescription = "Azure management URL"; } -} \ No newline at end of file +} From 2f4a1536e713ac66232547368d2566e3aaf40c98 Mon Sep 17 00:00:00 2001 From: Jason Taylor Date: Wed, 22 Oct 2025 16:27:18 +1000 Subject: [PATCH 4/8] Fix metrics client construction --- .../AzureQuery.cs | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/ServiceControl.Transports.ASBS/AzureQuery.cs b/src/ServiceControl.Transports.ASBS/AzureQuery.cs index d2dc320b54..11d7bae5d6 100644 --- a/src/ServiceControl.Transports.ASBS/AzureQuery.cs +++ b/src/ServiceControl.Transports.ASBS/AzureQuery.cs @@ -29,7 +29,6 @@ public class AzureQuery(ILogger logger, TimeProvider timeProvider, T MetricsClient? client; ArmClient? armClient; TokenCredential? credential; - Uri? metricsEndpoint; string? resourceId; ArmEnvironment armEnvironment; MetricsClientAudience metricsQueryAudience; @@ -275,26 +274,21 @@ public override async IAsyncEnumerable GetQueueNames( var regionName = serviceBusNamespaceResource.Data.Location.Name; // Build the regional Azure Monitor Metrics endpoint from the audience - var newEndpoint = BuildMetricsEndpointFromAudience(metricsQueryAudience, regionName); + var metricsEndpoint = BuildMetricsEndpointFromAudience(metricsQueryAudience, regionName); - // Create or refresh the MetricsClient if it's missing or points to a different region - if (client is null || metricsEndpoint?.ToString() != newEndpoint.ToString()) - { - metricsEndpoint = newEndpoint; - - client = new MetricsClient( - metricsEndpoint, - credential!, - new MetricsClientOptions - { - Audience = metricsQueryAudience, - Transport = new HttpClientTransport( - new HttpClient(new SocketsHttpHandler - { - PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2) - })) - }); - } + // CreateNewOnMetadataUpdateAttribute the MetricsClient for this namespace + client = new MetricsClient( + metricsEndpoint, + credential!, + new MetricsClientOptions + { + Audience = metricsQueryAudience, + Transport = new HttpClientTransport( + new HttpClient(new SocketsHttpHandler + { + PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2) + })) + }); await foreach (var queue in serviceBusNamespaceResource.GetServiceBusQueues() .WithCancellation(cancellationToken)) From cfafbe80d9b2c1c889661e293261ac1d067756a8 Mon Sep 17 00:00:00 2001 From: Jason Taylor <1988321+jasontaylordev@users.noreply.github.com> Date: Thu, 23 Oct 2025 08:37:50 +1000 Subject: [PATCH 5/8] Update src/ServiceControl.Transports.ASBS/AzureQuery.cs Co-authored-by: John Simons --- src/ServiceControl.Transports.ASBS/AzureQuery.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/ServiceControl.Transports.ASBS/AzureQuery.cs b/src/ServiceControl.Transports.ASBS/AzureQuery.cs index 11d7bae5d6..463a39c7f8 100644 --- a/src/ServiceControl.Transports.ASBS/AzureQuery.cs +++ b/src/ServiceControl.Transports.ASBS/AzureQuery.cs @@ -317,15 +317,9 @@ public override async IAsyncEnumerable GetQueueNames( Uri BuildMetricsEndpointFromAudience(MetricsClientAudience audience, string regionName) { var region = regionName.ToLowerInvariant(); - - var audienceUri = new Uri(audience.ToString()); - var audienceHost = audienceUri.Host; // e.g., "metrics.monitor.azure.com" - - var regionalHost = audienceHost.StartsWith("metrics.", StringComparison.OrdinalIgnoreCase) - ? audienceHost.Replace("metrics.", $"{region}.metrics.") - : $"{region}.metrics.{audienceHost}"; - - return new Uri($"https://{regionalHost}"); + var builder = new UriBuilder(audience.ToString()); + builder.Host = $"{region}.{builder.Host}"; + return builder.Uri; } async Task> GetValidNamespaceNames(CancellationToken cancellationToken = default) From 5d19bd31fd04ac241b0421c91abf7b4421023733 Mon Sep 17 00:00:00 2001 From: Jason Taylor Date: Thu, 23 Oct 2025 10:15:11 +1000 Subject: [PATCH 6/8] Lazy initialization of metrics client --- .../AzureQuery.cs | 76 ++++++++++++------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/src/ServiceControl.Transports.ASBS/AzureQuery.cs b/src/ServiceControl.Transports.ASBS/AzureQuery.cs index 463a39c7f8..82ad611dea 100644 --- a/src/ServiceControl.Transports.ASBS/AzureQuery.cs +++ b/src/ServiceControl.Transports.ASBS/AzureQuery.cs @@ -26,12 +26,12 @@ public class AzureQuery(ILogger logger, TimeProvider timeProvider, T : BrokerThroughputQuery(logger, "AzureServiceBus") { string serviceBusName = string.Empty; - MetricsClient? client; ArmClient? armClient; TokenCredential? credential; - string? resourceId; + ResourceIdentifier? resourceId; ArmEnvironment armEnvironment; - MetricsClientAudience metricsQueryAudience; + MetricsClientAudience metricsClientAudience; + MetricsClient? metricsClient; protected override void InitializeCore(ReadOnlyDictionary settings) { @@ -104,7 +104,7 @@ protected override void InitializeCore(ReadOnlyDictionary settin Diagnostics.AppendLine("Client secret set"); } - (armEnvironment, metricsQueryAudience) = GetEnvironment(); + (armEnvironment, metricsClientAudience) = GetEnvironment(); if (managementUrl == null) { @@ -143,7 +143,7 @@ protected override void InitializeCore(ReadOnlyDictionary settin return; - (ArmEnvironment armEnvironment, MetricsClientAudience metricsQueryAudience) GetEnvironment() + (ArmEnvironment armEnvironment, MetricsClientAudience metricsClientAudience) GetEnvironment() { if (managementUrlParsed == null) { @@ -234,10 +234,51 @@ public override async IAsyncEnumerable GetThroughputPerDay(IBro } } + async Task InitializeMetricsClient(CancellationToken cancellationToken = default) + { + if (resourceId is null || armClient is null || credential is null) + { + throw new InvalidOperationException("AzureQuery has not been initialized correctly."); + } + + var serviceBusNamespaceResource = await armClient + .GetServiceBusNamespaceResource(resourceId).GetAsync(cancellationToken) + ?? throw new Exception($"Could not find ServiceBus with resource Id: \"{resourceId}\""); + + // Determine the region of the namespace + var regionName = serviceBusNamespaceResource.Value.Data.Location.Name; + + // Build the regional Azure Monitor Metrics endpoint from the audience + var metricsEndpoint = BuildMetricsEndpoint(metricsClientAudience, regionName); + + // CreateNewOnMetadataUpdateAttribute the MetricsClient for this namespace + return new MetricsClient( + metricsEndpoint, + credential!, + new MetricsClientOptions + { + Audience = metricsClientAudience, + Transport = new HttpClientTransport( + new HttpClient(new SocketsHttpHandler + { + PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2) + })) + }); + } + + static Uri BuildMetricsEndpoint(MetricsClientAudience audience, string regionName) + { + var builder = new UriBuilder(audience.ToString()); + builder.Host = $"{regionName.ToLowerInvariant()}.{builder.Host}"; + return builder.Uri; + } + async Task> GetMetrics(string queueName, DateOnly startTime, DateOnly endTime, CancellationToken cancellationToken = default) { - var response = await client!.QueryResourcesAsync( + metricsClient ??= await InitializeMetricsClient(cancellationToken); + + var response = await metricsClient.QueryResourcesAsync( [new ResourceIdentifier(resourceId!)], ["CompleteMessage"], "Microsoft.ServiceBus/namespaces", @@ -261,8 +302,7 @@ public override async IAsyncEnumerable GetQueueNames( var validNamespaces = await GetValidNamespaceNames(cancellationToken); SubscriptionResource? subscription = await armClient!.GetDefaultSubscriptionAsync(cancellationToken); - var namespaces = - subscription.GetServiceBusNamespacesAsync(cancellationToken); + var namespaces = subscription.GetServiceBusNamespacesAsync(cancellationToken); await foreach (var serviceBusNamespaceResource in namespaces.WithCancellation(cancellationToken)) { @@ -270,26 +310,6 @@ public override async IAsyncEnumerable GetQueueNames( { resourceId = serviceBusNamespaceResource.Id; - // Determine the region of the namespace - var regionName = serviceBusNamespaceResource.Data.Location.Name; - - // Build the regional Azure Monitor Metrics endpoint from the audience - var metricsEndpoint = BuildMetricsEndpointFromAudience(metricsQueryAudience, regionName); - - // CreateNewOnMetadataUpdateAttribute the MetricsClient for this namespace - client = new MetricsClient( - metricsEndpoint, - credential!, - new MetricsClientOptions - { - Audience = metricsQueryAudience, - Transport = new HttpClientTransport( - new HttpClient(new SocketsHttpHandler - { - PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2) - })) - }); - await foreach (var queue in serviceBusNamespaceResource.GetServiceBusQueues() .WithCancellation(cancellationToken)) { From 351ac5c826cce7efb85c58e5c602524eb768fdb9 Mon Sep 17 00:00:00 2001 From: Jason Taylor Date: Thu, 23 Oct 2025 10:37:00 +1000 Subject: [PATCH 7/8] Refactor metrics endpoint construction Updated the `BuildMetricsEndpoint` method to ensure the region is consistently formatted in lowercase when constructing the URI. Removed the unused `BuildMetricsEndpointFromAudience` method. --- src/ServiceControl.Transports.ASBS/AzureQuery.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/ServiceControl.Transports.ASBS/AzureQuery.cs b/src/ServiceControl.Transports.ASBS/AzureQuery.cs index 82ad611dea..b8ce369f4b 100644 --- a/src/ServiceControl.Transports.ASBS/AzureQuery.cs +++ b/src/ServiceControl.Transports.ASBS/AzureQuery.cs @@ -268,8 +268,9 @@ async Task InitializeMetricsClient(CancellationToken cancellation static Uri BuildMetricsEndpoint(MetricsClientAudience audience, string regionName) { + var region = regionName.ToLowerInvariant(); var builder = new UriBuilder(audience.ToString()); - builder.Host = $"{regionName.ToLowerInvariant()}.{builder.Host}"; + builder.Host = $"{region}.{builder.Host}"; return builder.Uri; } @@ -333,15 +334,6 @@ public override async IAsyncEnumerable GetQueueNames( { ArmEnvironment.AzureChina, "servicebus.chinacloudapi.cn" }, }; - // Build metrics endpoint host directly from the configured audience. - Uri BuildMetricsEndpointFromAudience(MetricsClientAudience audience, string regionName) - { - var region = regionName.ToLowerInvariant(); - var builder = new UriBuilder(audience.ToString()); - builder.Host = $"{region}.{builder.Host}"; - return builder.Uri; - } - async Task> GetValidNamespaceNames(CancellationToken cancellationToken = default) { var validNamespaces = new HashSet(StringComparer.OrdinalIgnoreCase) { serviceBusName }; From 2185c6496675dbf1815ae38317c9b3bf1c60f6e7 Mon Sep 17 00:00:00 2001 From: Jason Taylor Date: Thu, 23 Oct 2025 14:33:25 +1000 Subject: [PATCH 8/8] Refactor resourceId parameter handling --- src/ServiceControl.Transports.ASBS/AzureQuery.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceControl.Transports.ASBS/AzureQuery.cs b/src/ServiceControl.Transports.ASBS/AzureQuery.cs index b8ce369f4b..3007ed7374 100644 --- a/src/ServiceControl.Transports.ASBS/AzureQuery.cs +++ b/src/ServiceControl.Transports.ASBS/AzureQuery.cs @@ -280,7 +280,7 @@ async Task> GetMetrics(string queueName, DateOnly sta metricsClient ??= await InitializeMetricsClient(cancellationToken); var response = await metricsClient.QueryResourcesAsync( - [new ResourceIdentifier(resourceId!)], + [resourceId!], ["CompleteMessage"], "Microsoft.ServiceBus/namespaces", new MetricsQueryResourcesOptions