Skip to content

Commit 9cbdf6e

Browse files
authored
Add NServiceBus 10 Azure Storage Queues sample (#7616)
* Add nsb10 sample * Fix StorageReader test for nsb 9 sample * Maybe fixing integrity tests * Removed BannedAnalyzers packages from the .csproj files
1 parent ef83cac commit 9cbdf6e

16 files changed

+374
-11
lines changed

samples/azure/storage-queues/ASQN_13/StorageReader/AzureHelper.cs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ static async Task WriteOutQueue(string queueName)
2727
{
2828
var queueClient = new QueueClient("UseDevelopmentStorage=true", queueName);
2929
PeekedMessage[] message = await queueClient.PeekMessagesAsync(1);
30-
if (message != null)
30+
if (message?.Length >= 1)
3131
{
32-
Debug.WriteLine("Message contents");
32+
Console.WriteLine("Message contents");
3333
WriteOutMessage(message[0]);
3434
return;
3535
}
@@ -41,17 +41,14 @@ static void WriteOutMessage(PeekedMessage message)
4141
{
4242
var bytes = Convert.FromBase64String(message.MessageText);
4343
var json = Encoding.UTF8.GetString(bytes);
44-
var byteOrderMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
45-
if (json.StartsWith(json))
46-
{
47-
json = json.Remove(0, byteOrderMarkUtf8.Length);
48-
}
44+
4945
dynamic parsedJson = JsonConvert.DeserializeObject(json);
50-
Debug.WriteLine("Message contents:");
51-
Debug.WriteLine(JsonConvert.SerializeObject((object) parsedJson, Formatting.Indented));
46+
Console.WriteLine("Message contents:");
47+
Console.WriteLine(JsonConvert.SerializeObject((object) parsedJson, Formatting.Indented));
48+
5249
var body = (string)parsedJson.Body;
53-
Debug.WriteLine("Deserialized message body:");
54-
Debug.WriteLine(body.Base64Decode());
50+
Console.WriteLine("Deserialized message body:");
51+
Console.WriteLine(body.Base64Decode());
5552
}
5653

5754
#endregion
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.29728.190
5+
MinimumVisualStudioVersion = 15.0.26730.12
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Endpoint2", "Endpoint2\Endpoint2.csproj", "{2FE71442-7F81-428E-B945-D564850D6564}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Endpoint1", "Endpoint1\Endpoint1.csproj", "{11641841-C7E9-4B49-9688-99E54187A7E8}"
9+
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{DD438DB2-9C03-4BC0-BA52-BB7A35098458}"
11+
EndProject
12+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StorageReader", "StorageReader\StorageReader.csproj", "{EB89C78F-A11D-43BF-9256-C81C6C0FA902}"
13+
EndProject
14+
Global
15+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
16+
Debug|Any CPU = Debug|Any CPU
17+
EndGlobalSection
18+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
19+
{2FE71442-7F81-428E-B945-D564850D6564}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20+
{2FE71442-7F81-428E-B945-D564850D6564}.Debug|Any CPU.Build.0 = Debug|Any CPU
21+
{11641841-C7E9-4B49-9688-99E54187A7E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22+
{11641841-C7E9-4B49-9688-99E54187A7E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
23+
{DD438DB2-9C03-4BC0-BA52-BB7A35098458}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24+
{DD438DB2-9C03-4BC0-BA52-BB7A35098458}.Debug|Any CPU.Build.0 = Debug|Any CPU
25+
{EB89C78F-A11D-43BF-9256-C81C6C0FA902}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26+
{EB89C78F-A11D-43BF-9256-C81C6C0FA902}.Debug|Any CPU.Build.0 = Debug|Any CPU
27+
EndGlobalSection
28+
GlobalSection(SolutionProperties) = preSolution
29+
HideSolutionNode = FALSE
30+
EndGlobalSection
31+
EndGlobal
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<LangVersion>preview</LangVersion>
5+
<TargetFramework>net10.0</TargetFramework>
6+
</PropertyGroup>
7+
<ItemGroup>
8+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.0-preview.6.25358.103" />
9+
<PackageReference Include="NServiceBus" Version="10.0.0-alpha.2" />
10+
<PackageReference Include="NServiceBus.Transport.AzureStorageQueues" Version="14.0.0-alpha.2" />
11+
<ProjectReference Include="..\Shared\Shared.csproj" />
12+
<PackageReference Include="NServiceBus.Extensions.Hosting" Version="4.0.0-alpha.2" />
13+
</ItemGroup>
14+
</Project>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.Threading.Tasks;
2+
using NServiceBus;
3+
using Microsoft.Extensions.Logging;
4+
using Shared;
5+
6+
public sealed class Endpoint2ResponseHandler(ILogger<Endpoint2ResponseHandler> logger)
7+
: IHandleMessages<MyResponse>
8+
{
9+
public Task Handle(MyResponse message, IMessageHandlerContext context)
10+
{
11+
logger.LogInformation("Received MyResponse: {Property}", message.Property);
12+
return Task.CompletedTask;
13+
}
14+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.Hosting;
4+
using NServiceBus;
5+
using Shared;
6+
7+
var host = Host.CreateDefaultBuilder(args)
8+
.UseNServiceBus(x =>
9+
{
10+
#region endpointName
11+
12+
var endpointName = "Samples.Azure.StorageQueues.Endpoint1.With.A.Very.Long.Name.And.Invalid.Characters";
13+
var endpointConfiguration = new EndpointConfiguration(endpointName);
14+
15+
#endregion
16+
17+
Console.Title = endpointName;
18+
19+
#region config
20+
21+
var transport = new AzureStorageQueueTransport("UseDevelopmentStorage=true");
22+
var routingSettings = endpointConfiguration.UseTransport(transport);
23+
routingSettings.RouteToEndpoint(typeof(MyRequest), "Samples-Azure-StorageQueues-Endpoint2");
24+
25+
#endregion
26+
27+
#region sanitization
28+
29+
transport.QueueNameSanitizer = BackwardsCompatibleQueueNameSanitizer.WithMd5Shortener;
30+
31+
#endregion
32+
33+
routingSettings.DisablePublishing();
34+
endpointConfiguration.UsePersistence<LearningPersistence>();
35+
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
36+
endpointConfiguration.EnableInstallers();
37+
38+
return endpointConfiguration;
39+
}).Build();
40+
41+
await host.StartAsync();
42+
43+
var messageSession = host.Services.GetRequiredService<IMessageSession>();
44+
45+
Console.WriteLine("Press 'enter' to send a message");
46+
while (true)
47+
{
48+
var key = Console.ReadKey();
49+
Console.WriteLine();
50+
51+
if (key.Key != ConsoleKey.Enter)
52+
{
53+
break;
54+
}
55+
56+
var message = new MyRequest("Hello from Endpoint1");
57+
58+
await messageSession.Send(message);
59+
60+
Console.WriteLine("MyRequest sent");
61+
}
62+
63+
await host.StopAsync();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<LangVersion>preview</LangVersion>
5+
<TargetFramework>net10.0</TargetFramework>
6+
</PropertyGroup>
7+
<ItemGroup>
8+
<PackageReference Include="NServiceBus" Version="10.0.0-alpha.2" />
9+
<PackageReference Include="NServiceBus.Extensions.Hosting" Version="4.0.0-alpha.2" />
10+
<PackageReference Include="NServiceBus.Transport.AzureStorageQueues" Version="14.0.0-alpha.2" />
11+
<ProjectReference Include="..\Shared\Shared.csproj" />
12+
</ItemGroup>
13+
</Project>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.Threading.Tasks;
2+
using NServiceBus;
3+
using Microsoft.Extensions.Logging;
4+
using Shared;
5+
6+
public sealed class MyRequestResponseHandler(ILogger<MyRequestResponseHandler> logger)
7+
: IHandleMessages<MyRequest>
8+
{
9+
public Task Handle(MyRequest message, IMessageHandlerContext context)
10+
{
11+
logger.LogInformation("Received MyRequest: {Property}", message.Property);
12+
var myResponse = new MyResponse("Hello from Endpoint2");
13+
return context.Reply(myResponse);
14+
}
15+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using Microsoft.Extensions.Hosting;
3+
using NServiceBus;
4+
5+
var builder = Host.CreateApplicationBuilder(args);
6+
7+
const string endpointName = "Samples-Azure-StorageQueues-Endpoint2";
8+
Console.Title = endpointName;
9+
10+
var endpointConfiguration = new EndpointConfiguration(endpointName);
11+
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
12+
endpointConfiguration.EnableInstallers();
13+
14+
var transport = new AzureStorageQueueTransport("UseDevelopmentStorage=true")
15+
{
16+
QueueNameSanitizer = BackwardsCompatibleQueueNameSanitizer.WithMd5Shortener
17+
};
18+
19+
var routingSettings = endpointConfiguration.UseTransport(transport);
20+
routingSettings.DisablePublishing();
21+
22+
endpointConfiguration.UsePersistence<LearningPersistence>();
23+
builder.UseNServiceBus(endpointConfiguration);
24+
25+
await builder.Build().RunAsync();
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System;
2+
using System.Security.Cryptography;
3+
using System.Text;
4+
using System.Text.RegularExpressions;
5+
6+
#region BackwardsCompatibleQueueNameSanitizer
7+
8+
public static partial class BackwardsCompatibleQueueNameSanitizer
9+
{
10+
public static string WithMd5Shortener(string queueName)
11+
{
12+
return Sanitize(queueName, useMd5Hashing: true);
13+
}
14+
15+
public static string WithSha1Shortener(string queueName)
16+
{
17+
return Sanitize(queueName, useMd5Hashing: false);
18+
}
19+
20+
static string Sanitize(string queueName, bool useMd5Hashing = true)
21+
{
22+
var queueNameInLowerCase = queueName.ToLowerInvariant();
23+
return ShortenQueueNameIfNecessary(SanitizeQueueName(queueNameInLowerCase), useMd5Hashing);
24+
}
25+
26+
static string ShortenQueueNameIfNecessary(string sanitizedQueueName, bool useMd5Hashing)
27+
{
28+
if (sanitizedQueueName.Length <= 63)
29+
{
30+
return sanitizedQueueName;
31+
}
32+
33+
var shortenedName = useMd5Hashing ? ShortenWithMd5(sanitizedQueueName) : ShortenWithSha1(sanitizedQueueName);
34+
35+
return $"{sanitizedQueueName.Substring(0, 63 - shortenedName.Length - 1).Trim('-')}-{shortenedName}";
36+
}
37+
38+
static string SanitizeQueueName(string queueName)
39+
{
40+
// this can lead to multiple '-' occurrences in a row
41+
var sanitized = InvalidCharacters().Replace(queueName, "-");
42+
return MultipleDashes().Replace(sanitized, "-");
43+
}
44+
45+
static string ShortenWithMd5(string test)
46+
{
47+
//use MD5 hash to get a 16-byte hash of the string
48+
using var provider = MD5.Create();
49+
var inputBytes = Encoding.Default.GetBytes(test);
50+
var hashBytes = provider.ComputeHash(inputBytes);
51+
//generate a guid from the hash:
52+
return new Guid(hashBytes).ToString();
53+
}
54+
55+
static string ShortenWithSha1(string queueName)
56+
{
57+
using var provider = SHA1.Create();
58+
var inputBytes = Encoding.Default.GetBytes(queueName);
59+
var hashBytes = provider.ComputeHash(inputBytes);
60+
61+
return ToChars(hashBytes);
62+
}
63+
64+
static string ToChars(byte[] hashBytes)
65+
{
66+
var chars = new char[hashBytes.Length * 2];
67+
for (var i = 0; i < chars.Length; i += 2)
68+
{
69+
var byteIndex = i / 2;
70+
chars[i] = HexToChar((byte)(hashBytes[byteIndex] >> 4));
71+
chars[i + 1] = HexToChar(hashBytes[byteIndex]);
72+
}
73+
74+
return new string(chars);
75+
}
76+
77+
static char HexToChar(byte a)
78+
{
79+
a &= 15;
80+
return a > 9 ? (char)(a - 10 + 97) : (char)(a + 48);
81+
}
82+
83+
[GeneratedRegex(@"[^a-z0-9\-]", RegexOptions.Compiled)]
84+
private static partial Regex InvalidCharacters();
85+
[GeneratedRegex(@"\-+", RegexOptions.Compiled)]
86+
private static partial Regex MultipleDashes();
87+
}
88+
89+
#endregion
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
using NServiceBus;
2+
3+
namespace Shared;
4+
5+
public record MyRequest(string Property) : IMessage;

0 commit comments

Comments
 (0)