Skip to content

Commit dea6fdf

Browse files
authored
Add Azure StorageQueue integration (#17)
1 parent 2ec610e commit dea6fdf

34 files changed

+1329
-223
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
# dotenv files
77
.env
88

9+
# ai instructions
10+
AGENTS.md
11+
GEMINI.md
12+
913
# User-specific files
1014
*.rsuser
1115
*.suo

docs/assets/Screenshot_01.png

17.6 KB
Loading

docs/assets/Screenshot_02.png

22.7 KB
Loading

docs/assets/Screenshot_03.png

58.7 KB
Loading

docs/index.html

Lines changed: 83 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -120,66 +120,86 @@ <h1>EventHub Explorer</h1>
120120
</div>
121121

122122
<div class="container">
123-
<p>EventHub Explorer is a developer tool that allows you to interact with the Azure EventHubs service using a graphical user interface. It supports both real Azure Event Hubs and the <a href="https://learn.microsoft.com/en-us/azure/event-hubs/overview-emulator">eventhubs-emulator</a>.</p>
124-
125-
<img src="./assets/Screenshot_01.png" alt="HomePage" />
126-
<img src="./assets/Screenshot_02.png" alt="ConfigurationPage" />
127-
<img src="./assets/Screenshot_03.png" alt="EventHubPage" />
128-
129-
<h2>Features</h2>
130-
131-
<h3>Sending Messages to Event Hubs</h3>
132-
<ul>
133-
<li>Override GUID, DateTime values in a message before sending</li>
134-
<li>Ability to compress and encode a message before sending</li>
135-
<li>Send a <strong>single message</strong></li>
136-
<li>Send a <strong>batch of messages</strong></li>
137-
<li>Send a <strong>batch of messages</strong> with a <strong>time delay</strong> between each message</li>
138-
</ul>
139-
140-
<h3>Receiving Messages from Event Hubs</h3>
141-
<ul>
142-
<li>Format a message to JSON if it is a JSON string</li>
143-
<li>Ability to decompress and decode a message after receiving</li>
144-
<li>Receive messages <strong>without checkpoints</strong> (always fetch the newest messages)</li>
145-
<li>Receive messages <strong>with checkpoints</strong> (using external storage to track received message IDs)</li>
146-
</ul>
147-
148-
<div class="note">
149-
<p><strong>Note:</strong> The application uses the <code>$Default</code> consumer group by default.</p>
150-
</div>
151-
152-
<h2>Example Connection Strings</h2>
153-
154-
<h3>EventHubs Emulator</h3>
155-
<pre><code>Endpoint=sb://eventhub-docker;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;</code></pre>
156-
157-
<div class="note">
158-
<p><code>eventhub-docker</code> is the Docker service name of the Event Hubs emulator running in the same Docker network.</p>
159-
</div>
160-
161-
<h3>Azurite Blob Storage</h3>
162-
<pre><code>DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://eventhub-azurite:10000/devstoreaccount1;</code></pre>
163-
164-
<div class="note">
165-
<p><code>eventhub-azurite</code> is the Docker service name of the Azurite blob storage running in the same Docker network.</p>
166-
</div>
167-
168-
<h2>Requirements</h2>
169-
<ul>
170-
<li>Docker (for emulator and Azurite usage)</li>
171-
<li>Azure Event Hubs and Blob Storage credentials (for real Azure usage)</li>
172-
</ul>
173-
174-
<h2>Install options</h2>
175-
<ul>
176-
<li>Clone solution in the repo</li>
177-
<li>Or Use docker image <code>docker pull dvlaskin/eventhubexplorer</code></li>
178-
<li>Open in browser http://localhost:5235/</li>
179-
</ul>
180-
181-
<h3>Example of a docker compose file</h3>
182-
<pre><code>services:
123+
<p>EventHub Explorer is a developer tool that allows you to interact with Azure Event Hubs and Azure Storage Queues using a graphical user interface. It supports both real Azure services, the <a href="https://learn.microsoft.com/en-us/azure/event-hubs/overview-emulator">eventhubs-emulator</a> for Event Hubs and <a href="https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite">Azurite</a> for StorageQueue.</p>
124+
125+
<img src="./assets/Screenshot_01.png" alt="HomePage" />
126+
<img src="./assets/Screenshot_02.png" alt="ConfigurationPage" />
127+
<img src="./assets/Screenshot_03.png" alt="EventHubPage" />
128+
129+
<h2>Features</h2>
130+
131+
<h3>Sending Messages to Event Hubs</h3>
132+
<ul>
133+
<li>Override GUID, DateTime values in a message before sending</li>
134+
<li>Ability to compress and encode a message before sending</li>
135+
<li>Send a <strong>single message</strong></li>
136+
<li>Send a <strong>batch of messages</strong></li>
137+
<li>Send a <strong>batch of messages</strong> with a <strong>time delay</strong> between each message</li>
138+
</ul>
139+
140+
<h3>Receiving Messages from Event Hubs</h3>
141+
<ul>
142+
<li>Format a message to JSON if it is a JSON string</li>
143+
<li>Ability to decompress and decode a message after receiving</li>
144+
<li>Receive messages <strong>without checkpoints</strong> (always fetch the newest messages, if is not yet received another consumer)</li>
145+
<li>Receive messages <strong>with checkpoints</strong> (using external storage to track received message IDs)</li>
146+
</ul>
147+
148+
<div class="note">
149+
<p><strong>Note:</strong> The application uses the <code>$Default</code> consumer group by default.</p>
150+
</div>
151+
152+
<h3>Sending Messages to Storage Queues</h3>
153+
<ul>
154+
<li>Override GUID, DateTime values in a message before sending</li>
155+
<li>Ability to compress and encode a message before sending</li>
156+
<li>Send a <strong>single message</strong></li>
157+
<li>Send a <strong>batch of messages</strong></li>
158+
<li>Send a <strong>batch of messages</strong> with a <strong>time delay</strong> between each message</li>
159+
</ul>
160+
161+
<h3>Receiving Messages from Storage Queues</h3>
162+
<ul>
163+
<li>Format a message to JSON if it is a JSON string</li>
164+
<li>Ability to decompress and decode a message after receiving</li>
165+
</ul>
166+
167+
<h2>Example Connection Strings</h2>
168+
169+
<h3>EventHubs Emulator</h3>
170+
<pre><code>Endpoint=sb://eventhub-docker;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;</code></pre>
171+
<div class="note">
172+
<p><code>eventhub-docker</code> is the Docker service name of the Event Hubs emulator running in the same Docker network.</p>
173+
</div>
174+
175+
<h3>Azurite Blob Storage</h3>
176+
<pre><code>DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://eventhub-azurite:10000/devstoreaccount1;</code></pre>
177+
<div class="note">
178+
<p><code>eventhub-azurite</code> is the Docker service name of the Azurite blob storage running in the same Docker network.</p>
179+
</div>
180+
181+
<h3>Azurite Storage Queue</h3>
182+
<pre><code>DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;QueueEndpoint=http://eventhub-azurite:10001/devstoreaccount1;</code></pre>
183+
<div class="note">
184+
<p><code>eventhub-azurite</code> is the Docker service name of the Azurite storage running in the same Docker network.</p>
185+
</div>
186+
187+
<h2>Requirements</h2>
188+
<ul>
189+
<li>Docker for emulator and Azurite usage</li>
190+
<li>Azure Event Hubs, Blob and Queue Storage credentials (for real Azure usage)</li>
191+
</ul>
192+
193+
<h2>Install options</h2>
194+
<ul>
195+
<li>Clone solution in the repo</li>
196+
<li>Or use docker image <code>docker pull dvlaskin/eventhubexplorer</code></li>
197+
<li>Run docker image or WebUI project in the solution</li>
198+
<li>Open in browser http://localhost:5235/</li>
199+
</ul>
200+
201+
<h3>Example of a docker compose file</h3>
202+
<pre><code>services:
183203

184204
eventhubexplorer:
185205
image: dvlaskin/eventhubexplorer:latest
@@ -196,7 +216,9 @@ <h3>Example of a docker compose file</h3>
196216

197217
networks:
198218
docker-network:
199-
external: true</code></pre>
219+
external: true
220+
221+
</code></pre>
200222

201223
<h2>License</h2>
202224
<p>MIT</p>

readme.md

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22

33
![.NET Version](https://img.shields.io/badge/.NET%20Version-10.0-blueviolet)
44

5-
EventHub Explorer is a developer tool that allows you to interact with the Azure EventHubs service using a graphical user interface. It supports both real Azure Event Hubs and the [eventhubs-emulator](https://learn.microsoft.com/en-us/azure/event-hubs/overview-emulator).
5+
EventHub Explorer is a developer tool that allows you to interact with Azure Event Hubs
6+
and Azure Storage Queues using a graphical user interface.
7+
It supports both real Azure services,
8+
the [eventhubs-emulator](https://learn.microsoft.com/en-us/azure/event-hubs/overview-emulator)
9+
for Event Hubs
10+
and [Azurite](https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite)
11+
for StorageQueue.
612

713
<img src="./docs/assets/Screenshot_01.png" alt="HomePage" width="50%"/>
814
<img src="./docs/assets/Screenshot_02.png" alt="ConfigurationPage" width="50%"/>
@@ -23,11 +29,24 @@ EventHub Explorer is a developer tool that allows you to interact with the Azure
2329

2430
* Format a message to JSON if it is a JSON string
2531
* Ability to decompress and decode a message after receiving
26-
* Receive messages **without checkpoints** (always fetch the newest messages)
32+
* Receive messages **without checkpoints** (always fetch the newest messages, if is not yet received another consumer)
2733
* Receive messages **with checkpoints** (using external storage to track received message IDs)
2834

2935
> Note: The application uses the `$Default` consumer group by default.
3036
37+
### Sending Messages to Storage Queues
38+
39+
* Override GUID, DateTime values in a message before sending
40+
* Ability to compress and encode a message before sending
41+
* Send a **single message**
42+
* Send a **batch of messages**
43+
* Send a **batch of messages** with a **time delay** between each message
44+
45+
### Receiving Messages from Storage Queues
46+
47+
* Format a message to JSON if it is a JSON string
48+
* Ability to decompress and decode a message after receiving
49+
3150
## Example Connection Strings
3251

3352
### EventHubs Emulator
@@ -46,15 +65,24 @@ DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02x
4665

4766
> `eventhub-azurite` is the Docker service name of the Azurite blob storage running in the same Docker network.
4867
68+
### Azurite Storage Queue
69+
70+
```
71+
DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;QueueEndpoint=http://eventhub-azurite:10001/devstoreaccount1;
72+
```
73+
74+
> `eventhub-azurite` is the Docker service name of the Azurite storage running in the same Docker network.
75+
4976
## Requirements
5077

51-
* Docker (for emulator and Azurite usage)
52-
* Azure Event Hubs and Blob Storage credentials (for real Azure usage)
78+
* Docker for emulator and Azurite usage
79+
* Azure Event Hubs, Blob and Queue Storage credentials (for real Azure usage)
5380

5481
## Install options
5582

5683
* Clone solution in the repo
5784
* Or use docker image ```docker pull dvlaskin/eventhubexplorer```
85+
* Run docker image or WebUI project in the solution
5886
* Open in browser http://localhost:5235/
5987

6088
Example of a docker compose file
@@ -82,4 +110,4 @@ networks:
82110

83111
## License
84112

85-
MIT
113+
MIT

src/Application/Application.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</ItemGroup>
1212

1313
<ItemGroup>
14-
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
14+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.2" />
1515
</ItemGroup>
1616

1717
</Project>

src/Application/Utils/CompressingEncoding.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,33 @@
11
using System.Buffers;
22
using System.IO.Compression;
33
using System.Text;
4+
using Domain.Configs;
45

56
namespace Application.Utils;
67

78
public static class CompressingEncoding
89
{
10+
public static string DecodeMessage(ReadOnlyMemory<byte> messageBody, EventHubConfig config)
11+
{
12+
return config switch
13+
{
14+
{ UseGzipCompression: false } => Encoding.UTF8.GetString(messageBody.ToArray()),
15+
{ UseGzipCompression: true, UseBase64Coding: false } => messageBody.ToArray().Decompress(),
16+
_ => Encoding.UTF8.GetString(messageBody.ToArray()).DecodeBase64().Decompress()
17+
};
18+
}
19+
20+
public static string DecodeMessage(ReadOnlyMemory<byte> messageBody, StorageQueueConfig config)
21+
{
22+
return config switch
23+
{
24+
{ UseGzipCompression: false } => Encoding.UTF8.GetString(messageBody.ToArray()),
25+
{ UseGzipCompression: true, UseBase64Coding: false } => messageBody.ToArray().Decompress(),
26+
_ => Encoding.UTF8.GetString(messageBody.ToArray()).DecodeBase64().Decompress()
27+
};
28+
}
29+
30+
931
public static byte[] Compress(this string? message)
1032
{
1133
if (string.IsNullOrEmpty(message))

src/Domain/Configs/AppConfiguration.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ namespace Domain.Configs;
22

33
public class AppConfiguration
44
{
5-
public List<EventHubConfig> EventHubsConfigs { get; set; } = new();
5+
public List<EventHubConfig> EventHubsConfigs { get; set; } = [];
6+
public List<StorageQueueConfig> StorageQueuesConfigs { get; set; } = [];
67
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace Domain.Configs;
2+
3+
public class StorageQueueConfig
4+
{
5+
public Guid Id { get; set; } = Guid.NewGuid();
6+
public required string Title { get; set; }
7+
public required string ConnectionString { get; set; }
8+
public required string QueueName { get; set; }
9+
public bool UseGzipCompression { get; set; }
10+
public bool UseBase64Coding { get; set; }
11+
public Dictionary<string, bool> MessageFormatters { get; set; } = new();
12+
}

0 commit comments

Comments
 (0)