Skip to content

Commit cdae238

Browse files
committed
Added Sample apps
1 parent 071bf23 commit cdae238

File tree

8 files changed

+473
-0
lines changed

8 files changed

+473
-0
lines changed

Foundatio.AzureStorage.slnx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@
55
<File Path="docker-compose.yml" />
66
<File Path="README.md" />
77
<File Path="tests/Directory.Build.props" />
8+
<File Path="samples/Directory.Build.props" />
89
</Folder>
910
<Folder Name="/Tests/">
1011
<Project Path="tests/Foundatio.AzureStorage.Tests/Foundatio.AzureStorage.Tests.csproj" />
1112
</Folder>
13+
<Folder Name="/Samples/">
14+
<Project Path="samples/Foundatio.AzureStorage.Enqueue/Foundatio.AzureStorage.Enqueue.csproj" />
15+
<Project Path="samples/Foundatio.AzureStorage.Dequeue/Foundatio.AzureStorage.Dequeue.csproj" />
16+
</Folder>
1217
<Project Path="src/Foundatio.AzureStorage/Foundatio.AzureStorage.csproj" />
1318
</Solution>

samples/Directory.Build.props

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project>
2+
<Import Project="..\build\common.props" />
3+
<PropertyGroup>
4+
<TargetFrameworks>net8.0</TargetFrameworks>
5+
<OutputType>Exe</OutputType>
6+
<IsPackable>False</IsPackable>
7+
</PropertyGroup>
8+
</Project>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<ItemGroup>
3+
<ProjectReference Include="..\..\src\Foundatio.AzureStorage\Foundatio.AzureStorage.csproj" />
4+
<ProjectReference Include="..\Foundatio.AzureStorage.Enqueue\Foundatio.AzureStorage.Enqueue.csproj" />
5+
<PackageReference Include="System.CommandLine" Version="2.0.1" />
6+
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
7+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
8+
</ItemGroup>
9+
</Project>
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
using System;
2+
using System.CommandLine;
3+
using System.Linq;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using Foundatio.AzureStorage.Samples;
7+
using Foundatio.Queues;
8+
using Microsoft.Extensions.Logging;
9+
10+
// Azure Storage Emulator connection string
11+
const string EmulatorConnectionString = "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://localhost:10000/devstoreaccount1;QueueEndpoint=http://localhost:10001/devstoreaccount1;";
12+
13+
// Define options
14+
var connectionStringOption = new Option<string>("--connection-string", "-c")
15+
{
16+
Description = "Azure Storage connection string (defaults to emulator)"
17+
};
18+
19+
var queueOption = new Option<string>("--queue", "-q")
20+
{
21+
Description = "Queue name",
22+
DefaultValueFactory = _ => "sample-queue"
23+
};
24+
25+
var modeOption = new Option<AzureStorageQueueCompatibilityMode>("--mode")
26+
{
27+
Description = "Compatibility mode (Default or Legacy)",
28+
DefaultValueFactory = _ => AzureStorageQueueCompatibilityMode.Default
29+
};
30+
31+
var countOption = new Option<int>("--count")
32+
{
33+
Description = "Number of messages to process (0 = infinite)",
34+
DefaultValueFactory = _ => 1
35+
};
36+
37+
// Create root command
38+
var rootCommand = new RootCommand("Azure Storage Queue Dequeue Sample");
39+
rootCommand.Options.Add(connectionStringOption);
40+
rootCommand.Options.Add(queueOption);
41+
rootCommand.Options.Add(modeOption);
42+
rootCommand.Options.Add(countOption);
43+
44+
// Set handler
45+
rootCommand.SetAction(async parseResult =>
46+
{
47+
var connectionString = parseResult.GetValue(connectionStringOption) ??
48+
Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION_STRING") ??
49+
EmulatorConnectionString;
50+
51+
var queueName = parseResult.GetValue(queueOption);
52+
var mode = parseResult.GetValue(modeOption);
53+
var count = parseResult.GetValue(countOption);
54+
55+
Console.WriteLine($"Using connection: {(connectionString == EmulatorConnectionString ? "Azure Storage Emulator" : "Custom connection string")}");
56+
Console.WriteLine($"Mode: {mode}");
57+
Console.WriteLine($"Queue: {queueName}");
58+
Console.WriteLine($"To process: {(count == 0 ? "infinite messages" : $"{count} message(s)")}");
59+
Console.WriteLine();
60+
Console.WriteLine("Press Ctrl+C to stop...");
61+
Console.WriteLine();
62+
63+
await DequeueMessages(connectionString, queueName, mode, count);
64+
return 0;
65+
});
66+
67+
// Parse and invoke
68+
return await rootCommand.Parse(args).InvokeAsync();
69+
70+
static async Task DequeueMessages(string connectionString, string queueName, AzureStorageQueueCompatibilityMode mode, int count)
71+
{
72+
using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole().SetMinimumLevel(LogLevel.Information));
73+
var logger = loggerFactory.CreateLogger("Dequeue");
74+
using var cts = new CancellationTokenSource();
75+
76+
Console.CancelKeyPress += (s, e) =>
77+
{
78+
e.Cancel = true;
79+
try
80+
{
81+
cts.Cancel();
82+
}
83+
catch
84+
{
85+
// ignored
86+
}
87+
88+
logger.LogInformation("Cancellation requested...");
89+
};
90+
91+
logger.LogInformation("Creating queue with mode: {Mode}", mode);
92+
93+
using var queue = new AzureStorageQueue<SampleMessage>(options => options
94+
.ConnectionString(connectionString)
95+
.Name(queueName)
96+
.CompatibilityMode(mode)
97+
.LoggerFactory(loggerFactory));
98+
99+
int processed = 0;
100+
bool infinite = count == 0;
101+
102+
logger.LogInformation("Waiting for messages... (Press Ctrl+C to stop)");
103+
104+
try
105+
{
106+
while (!cts.Token.IsCancellationRequested && (infinite || processed < count))
107+
{
108+
var entry = await queue.DequeueAsync(cts.Token);
109+
110+
if (entry == null)
111+
{
112+
if (!infinite && processed >= count)
113+
break;
114+
115+
continue;
116+
}
117+
118+
try
119+
{
120+
processed++;
121+
122+
logger.LogInformation("Dequeued message {MessageId}: '{Message}' from '{Source}' at {Timestamp}",
123+
entry.Id, entry.Value.Message, entry.Value.Source, entry.Value.Timestamp);
124+
125+
logger.LogInformation(" CorrelationId: '{CorrelationId}'", entry.CorrelationId ?? "<none>");
126+
127+
if (entry.Properties != null && entry.Properties.Count > 0)
128+
{
129+
logger.LogInformation(" Properties: [{Properties}]",
130+
string.Join(", ", entry.Properties.Select(p => $"{p.Key}={p.Value}")));
131+
}
132+
else
133+
{
134+
logger.LogInformation(" Properties: <none>");
135+
}
136+
137+
// Simulate processing time
138+
await Task.Delay(100, cts.Token);
139+
140+
await entry.CompleteAsync();
141+
logger.LogInformation(" Completed message {MessageId}", entry.Id);
142+
}
143+
catch (Exception ex)
144+
{
145+
logger.LogError(ex, "Error processing message {MessageId}", entry.Id);
146+
await entry.AbandonAsync();
147+
}
148+
}
149+
}
150+
catch (OperationCanceledException ex)
151+
{
152+
logger.LogInformation(ex, "Operation was cancelled");
153+
}
154+
155+
logger.LogInformation("Processed {ProcessedCount} message(s)", processed);
156+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<ItemGroup>
3+
<ProjectReference Include="..\..\src\Foundatio.AzureStorage\Foundatio.AzureStorage.csproj" />
4+
<PackageReference Include="System.CommandLine" Version="2.0.1" />
5+
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
6+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
7+
</ItemGroup>
8+
</Project>
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.CommandLine;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using Foundatio.AzureStorage.Samples;
7+
using Foundatio.Queues;
8+
using Microsoft.Extensions.Logging;
9+
10+
// Azure Storage Emulator connection string
11+
const string EmulatorConnectionString = "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://localhost:10000/devstoreaccount1;QueueEndpoint=http://localhost:10001/devstoreaccount1;";
12+
13+
// Define options
14+
var connectionStringOption = new Option<string>("--connection-string", "-c")
15+
{
16+
Description = "Azure Storage connection string (defaults to emulator)"
17+
};
18+
19+
var queueOption = new Option<string>("--queue", "-q")
20+
{
21+
Description = "Queue name",
22+
DefaultValueFactory = _ => "sample-queue"
23+
};
24+
25+
var messageOption = new Option<string>("--message", "-m")
26+
{
27+
Description = "Message to send",
28+
DefaultValueFactory = _ => "Hello World"
29+
};
30+
31+
var correlationIdOption = new Option<string>("--correlation-id")
32+
{
33+
Description = "Correlation ID for the message"
34+
};
35+
36+
var propertiesOption = new Option<string[]>("--property")
37+
{
38+
Description = "Custom properties in key=value format",
39+
DefaultValueFactory = _ => Array.Empty<string>()
40+
};
41+
42+
var modeOption = new Option<AzureStorageQueueCompatibilityMode>("--mode")
43+
{
44+
Description = "Compatibility mode (Default or Legacy)",
45+
DefaultValueFactory = _ => AzureStorageQueueCompatibilityMode.Legacy
46+
};
47+
48+
var countOption = new Option<int>("--count")
49+
{
50+
Description = "Number of messages to send",
51+
DefaultValueFactory = _ => 1
52+
};
53+
54+
// Create root command
55+
var rootCommand = new RootCommand("Azure Storage Queue Enqueue Sample");
56+
rootCommand.Options.Add(connectionStringOption);
57+
rootCommand.Options.Add(queueOption);
58+
rootCommand.Options.Add(messageOption);
59+
rootCommand.Options.Add(correlationIdOption);
60+
rootCommand.Options.Add(propertiesOption);
61+
rootCommand.Options.Add(modeOption);
62+
rootCommand.Options.Add(countOption);
63+
64+
// Set handler
65+
rootCommand.SetAction(async parseResult =>
66+
{
67+
var connectionString = parseResult.GetValue(connectionStringOption) ??
68+
Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION_STRING") ??
69+
EmulatorConnectionString;
70+
71+
var queueName = parseResult.GetValue(queueOption);
72+
var message = parseResult.GetValue(messageOption);
73+
var correlationId = parseResult.GetValue(correlationIdOption);
74+
var properties = parseResult.GetValue(propertiesOption);
75+
var mode = parseResult.GetValue(modeOption);
76+
var count = parseResult.GetValue(countOption);
77+
78+
Console.WriteLine($"Using connection: {(connectionString == EmulatorConnectionString ? "Azure Storage Emulator" : "Custom connection string")}");
79+
Console.WriteLine($"Mode: {mode}");
80+
Console.WriteLine();
81+
82+
await EnqueueMessages(connectionString, queueName, message, correlationId, properties, mode, count);
83+
return 0;
84+
});
85+
86+
// Parse and invoke
87+
return await rootCommand.Parse(args).InvokeAsync();
88+
89+
static async Task EnqueueMessages(string connectionString, string queueName, string message, string correlationId, string[] properties, AzureStorageQueueCompatibilityMode mode, int count)
90+
{
91+
using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole().SetMinimumLevel(LogLevel.Information));
92+
var logger = loggerFactory.CreateLogger("Enqueue");
93+
94+
logger.LogInformation("Creating queue with mode: {Mode}", mode);
95+
96+
using var queue = new AzureStorageQueue<SampleMessage>(options => options
97+
.ConnectionString(connectionString)
98+
.Name(queueName)
99+
.CompatibilityMode(mode)
100+
.LoggerFactory(loggerFactory));
101+
102+
var queueProperties = new Dictionary<string, string>();
103+
if (properties != null)
104+
{
105+
foreach (var prop in properties)
106+
{
107+
var parts = prop.Split('=', 2);
108+
if (parts.Length == 2)
109+
{
110+
queueProperties[parts[0]] = parts[1];
111+
}
112+
}
113+
}
114+
115+
for (int i = 0; i < count; i++)
116+
{
117+
var sampleMessage = new SampleMessage
118+
{
119+
Message = count > 1 ? $"{message} #{i + 1}" : message,
120+
Source = "Enqueue Sample"
121+
};
122+
123+
var entryOptions = new QueueEntryOptions
124+
{
125+
CorrelationId = correlationId,
126+
Properties = queueProperties.Count > 0 ? queueProperties : null
127+
};
128+
129+
var messageId = await queue.EnqueueAsync(sampleMessage, entryOptions);
130+
131+
logger.LogInformation("Enqueued message {MessageId}: '{Message}' with CorrelationId: '{CorrelationId}' Properties: [{Properties}]",
132+
messageId, sampleMessage.Message, correlationId ?? "<none>",
133+
string.Join(", ", queueProperties.Select(p => $"{p.Key}={p.Value}")));
134+
}
135+
136+
logger.LogInformation("Successfully enqueued {Count} message(s)", count);
137+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace Foundatio.AzureStorage.Samples;
4+
5+
public record SampleMessage
6+
{
7+
public string Message { get; init; } = string.Empty;
8+
public DateTime Timestamp { get; init; } = DateTime.UtcNow;
9+
public string Source { get; init; } = string.Empty;
10+
}

0 commit comments

Comments
 (0)