Skip to content

Commit c1c9666

Browse files
authored
Fix EventHubs GetNamespaceFromSettings (#7393)
We were calling RandomNumberGenerator.GetHexString and not using the result. The original intention was to use a random container name if we couldn't see ".servicebus" in the host name. Instead of using a random name, just sanitize the host name and use it, so it is deterministc. Fix #4886
1 parent 4e1a0f2 commit c1c9666

File tree

4 files changed

+58
-14
lines changed

4 files changed

+58
-14
lines changed

src/Components/Aspire.Azure.Messaging.EventHubs/EventHubsComponent.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.Security.Cryptography;
54
using Aspire.Azure.Common;
65
using Aspire.Azure.Messaging.EventHubs;
76
using Azure.Core;
@@ -56,15 +55,15 @@ protected static string GetNamespaceFromSettings(AzureMessagingEventHubsSettings
5655
: new Uri(settings.FullyQualifiedNamespace).Host;
5756

5857
// This is likely to be similar to {yournamespace}.servicebus.windows.net or {yournamespace}.servicebus.chinacloudapi.cn
59-
if (ns.Contains(".servicebus", StringComparison.OrdinalIgnoreCase))
58+
var serviceBusIndex = ns.IndexOf(".servicebus", StringComparison.OrdinalIgnoreCase);
59+
if (serviceBusIndex != -1)
6060
{
61-
ns = ns[..ns.IndexOf(".servicebus")];
61+
ns = ns[..serviceBusIndex];
6262
}
6363
else
6464
{
65-
// Use a random prefix if no meaningful name is found e.g., "localhost", "127.0.0.1".
66-
// This is used to create blob containers names that are unique in the referenced storage account.
67-
RandomNumberGenerator.GetHexString(12, true);
65+
// sanitize the namespace if it's not a servicebus namespace
66+
ns = ns.Replace(".", "-");
6867
}
6968
}
7069
catch (Exception ex) when (ex is FormatException or IndexOutOfRangeException)

src/Components/Aspire.Azure.Messaging.EventHubs/EventProcessorClientComponent.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,14 @@ private static BlobContainerClient GetBlobContainerClient(
9797
// name specified in the settings.
9898
bool shouldTryCreateIfNotExists = false;
9999

100+
// Do we have a container name provided in the settings?
100101
if (string.IsNullOrWhiteSpace(settings.BlobContainerName))
101102
{
103+
// If not, we'll create a container name based on the namespace, event hub name and consumer group
102104
var ns = GetNamespaceFromSettings(settings);
103105

104-
// Do we have a container name provided in the settings?
105-
if (string.IsNullOrWhiteSpace(settings.BlobContainerName))
106-
{
107-
// If not, we'll create a container name based on the namespace, event hub name and consumer group
108-
settings.BlobContainerName = $"{ns}-{settings.EventHubName}-{consumerGroup}";
109-
shouldTryCreateIfNotExists = true;
110-
}
106+
settings.BlobContainerName = $"{ns}-{settings.EventHubName}-{consumerGroup}";
107+
shouldTryCreateIfNotExists = true;
111108
}
112109

113110
var containerClient = blobClient.GetBlobContainerClient(settings.BlobContainerName);

tests/Aspire.Azure.Messaging.EventHubs.Tests/Aspire.Azure.Messaging.EventHubs.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
<ProjectReference Include="..\..\src\Components\Aspire.Azure.Storage.Blobs\Aspire.Azure.Storage.Blobs.csproj" />
1313
<ProjectReference Include="..\Aspire.Components.Common.Tests\Aspire.Components.Common.Tests.csproj" />
14+
15+
<Compile Include="..\Aspire.Azure.Security.KeyVault.Tests\MockTransport.cs" />
1416
</ItemGroup>
1517

1618
</Project>

tests/Aspire.Azure.Messaging.EventHubs.Tests/AspireEventHubsExtensionsTests.cs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Text;
5+
using Azure.Core;
46
using Azure.Identity;
57
using Azure.Messaging.EventHubs;
68
using Azure.Messaging.EventHubs.Consumer;
@@ -476,7 +478,7 @@ private static void AssertFullyQualifiedNamespace(string expectedNamespace, obje
476478
EventHubConsumerClient consumer => consumer.FullyQualifiedNamespace,
477479
EventProcessorClient processor => processor.FullyQualifiedNamespace,
478480
PartitionReceiver receiver => receiver.FullyQualifiedNamespace,
479-
EventHubBufferedProducerClient producer => producer.FullyQualifiedNamespace,
481+
EventHubBufferedProducerClient producer => producer.FullyQualifiedNamespace,
480482
_ => throw new InvalidOperationException()
481483
});
482484
}
@@ -580,4 +582,48 @@ public void CanAddMultipleKeyedServices(int clientIndex)
580582

581583
public static string CreateConfigKey(string prefix, string? key, string suffix)
582584
=> string.IsNullOrEmpty(key) ? $"{prefix}:{suffix}" : $"{prefix}:{key}:{suffix}";
585+
586+
/// <summary>
587+
/// Tests that the BlobContainerName defaults correctly when the connection string doesn't contain ".servicebus" and
588+
/// contains invalid container name characters.
589+
/// </summary>
590+
[Fact]
591+
public void ProcessorBlobContainerNameDefaultsCorrectly()
592+
{
593+
var builder = Host.CreateEmptyApplicationBuilder(null);
594+
builder.Configuration.AddInMemoryCollection([
595+
new KeyValuePair<string, string?>("ConnectionStrings:eh1", "Endpoint=sb://127.0.0.1:53589;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;"),
596+
new KeyValuePair<string, string?>("Aspire:Azure:Messaging:EventHubs:EventProcessorClient:EventHubName", "MyHub"),
597+
]);
598+
599+
var mockTransport = new MockTransport(
600+
CreateResponse("""{}"""));
601+
var blobClient = new BlobServiceClient(new Uri(BlobsConnectionString), new BlobClientOptions() { Transport = mockTransport });
602+
builder.Services.AddSingleton(blobClient);
603+
604+
builder.AddAzureEventProcessorClient("eh1");
605+
606+
using var host = builder.Build();
607+
608+
var client = host.Services.GetRequiredService<EventProcessorClient>();
609+
Assert.NotNull(client);
610+
611+
Assert.Single(mockTransport.Requests);
612+
// the container name should be based on the Endpoint, EventHubName, and ConsumerGroup
613+
Assert.Equal("https://fake.blob.core.windows.net/127-0-0-1-MyHub-default?restype=container", mockTransport.Requests[0].Uri.ToString());
614+
}
615+
616+
private static MockResponse CreateResponse(string content)
617+
{
618+
var buffer = Encoding.UTF8.GetBytes(content);
619+
var response = new MockResponse(201)
620+
{
621+
ClientRequestId = Guid.NewGuid().ToString(),
622+
ContentStream = new MemoryStream(buffer),
623+
};
624+
625+
response.AddHeader(new HttpHeader("Content-Type", "application/json; charset=utf-8"));
626+
627+
return response;
628+
}
583629
}

0 commit comments

Comments
 (0)