Skip to content

Commit 20c4c3f

Browse files
authored
[Storage] Queues - Failed message handler (#17001)
In this PR: - Ability to provide a handler to capture queue messages that are in invalid format. Bonus: - Ability to get parent queue service (like we did in #16437 ) Pending dependency: #18170
1 parent 21ebca7 commit 20c4c3f

File tree

33 files changed

+3191
-36
lines changed

33 files changed

+3191
-36
lines changed

sdk/storage/Azure.Storage.Common/src/Azure.Storage.Common.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFrameworks>$(RequiredTargetFrameworks)</TargetFrameworks>
44
</PropertyGroup>
@@ -17,6 +17,10 @@
1717
</Description>
1818
<RootNamespace>Azure.Storage</RootNamespace>
1919
</PropertyGroup>
20+
<PropertyGroup>
21+
<!-- Force a project reference until SyncAsyncEventHandler has shipped -->
22+
<UseProjectReferenceToAzureClients>true</UseProjectReferenceToAzureClients>
23+
</PropertyGroup>
2024
<ItemGroup>
2125
<PackageReference Include="Azure.Core" />
2226
</ItemGroup>

sdk/storage/Azure.Storage.Queues/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,20 @@ QueueClient queue = new QueueClient(accountUri, new DefaultAzureCredential());
125125

126126
Learn more about enabling Azure Active Directory for authentication with Azure Storage in [our documentation][storage_ad] and [our samples](#next-steps).
127127

128+
### Message encoding
129+
130+
This version of library does not encode message by default. V11 and prior versions as well as Azure Functions use base64-encoded messages by default.
131+
Therefore it's recommended to use this feature for interop scenarios.
132+
133+
```C# Snippet:Azure_Storage_Queues_Samples_Sample03_MessageEncoding_ConfigureMessageEncodingAsync
134+
QueueClientOptions queueClientOptions = new QueueClientOptions()
135+
{
136+
MessageEncoding = QueueMessageEncoding.Base64
137+
};
138+
139+
QueueClient queueClient = new QueueClient(connectionString, queueName, queueClientOptions);
140+
```
141+
128142
## Troubleshooting
129143

130144
All Azure Storage Queue service operations will throw a

sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.netstandard2.0.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ public QueueClient(System.Uri queueUri, Azure.Storage.StorageSharedKeyCredential
3434
public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.QueueSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; }
3535
public virtual Azure.Response<System.Collections.Generic.IEnumerable<Azure.Storage.Queues.Models.QueueSignedIdentifier>> GetAccessPolicy(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
3636
public virtual System.Threading.Tasks.Task<Azure.Response<System.Collections.Generic.IEnumerable<Azure.Storage.Queues.Models.QueueSignedIdentifier>>> GetAccessPolicyAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
37+
protected internal virtual Azure.Storage.Queues.QueueServiceClient GetParentQueueServiceClientCore() { throw null; }
3738
public virtual Azure.Response<Azure.Storage.Queues.Models.QueueProperties> GetProperties(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
3839
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Storage.Queues.Models.QueueProperties>> GetPropertiesAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
40+
protected virtual System.Threading.Tasks.Task OnMessageDecodingFailedAsync(Azure.Storage.Queues.Models.QueueMessage receivedMessage, Azure.Storage.Queues.Models.PeekedMessage peekedMessage, bool runSynchronously, System.Threading.CancellationToken cancellationToken) { throw null; }
3941
public virtual Azure.Response<Azure.Storage.Queues.Models.PeekedMessage> PeekMessage(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
4042
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Storage.Queues.Models.PeekedMessage>> PeekMessageAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
4143
public virtual Azure.Response<Azure.Storage.Queues.Models.PeekedMessage[]> PeekMessages(int? maxMessages = default(int?), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
@@ -72,6 +74,7 @@ public QueueClientOptions(Azure.Storage.Queues.QueueClientOptions.ServiceVersion
7274
public System.Uri GeoRedundantSecondaryUri { get { throw null; } set { } }
7375
public Azure.Storage.Queues.QueueMessageEncoding MessageEncoding { get { throw null; } set { } }
7476
public Azure.Storage.Queues.QueueClientOptions.ServiceVersion Version { get { throw null; } }
77+
public event Azure.Core.SyncAsyncEventHandler<Azure.Storage.Queues.QueueMessageDecodingFailedEventArgs> MessageDecodingFailed { add { } remove { } }
7578
public enum ServiceVersion
7679
{
7780
V2019_02_02 = 1,
@@ -82,6 +85,13 @@ public enum ServiceVersion
8285
V2020_06_12 = 6,
8386
}
8487
}
88+
public partial class QueueMessageDecodingFailedEventArgs : Azure.SyncAsyncEventArgs
89+
{
90+
public QueueMessageDecodingFailedEventArgs(Azure.Storage.Queues.QueueClient queueClient, Azure.Storage.Queues.Models.QueueMessage receivedMessage, Azure.Storage.Queues.Models.PeekedMessage peekedMessage, bool runSynchronously, System.Threading.CancellationToken cancellationToken) : base (default(bool), default(System.Threading.CancellationToken)) { }
91+
public Azure.Storage.Queues.Models.PeekedMessage PeekedMessage { get { throw null; } }
92+
public Azure.Storage.Queues.QueueClient Queue { get { throw null; } }
93+
public Azure.Storage.Queues.Models.QueueMessage ReceivedMessage { get { throw null; } }
94+
}
8595
public enum QueueMessageEncoding
8696
{
8797
None = 0,
@@ -369,6 +379,7 @@ public SpecializedQueueClientOptions(Azure.Storage.Queues.QueueClientOptions.Ser
369379
}
370380
public static partial class SpecializedQueueExtensions
371381
{
382+
public static Azure.Storage.Queues.QueueServiceClient GetParentQueueServiceClient(this Azure.Storage.Queues.QueueClient client) { throw null; }
372383
public static Azure.Storage.Queues.QueueClient WithClientSideEncryptionOptions(this Azure.Storage.Queues.QueueClient client, Azure.Storage.ClientSideEncryptionOptions clientSideEncryptionOptions) { throw null; }
373384
}
374385
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using Azure.Storage.Queues.Models;
6+
using NUnit.Framework;
7+
8+
namespace Azure.Storage.Queues.Samples.Tests
9+
{
10+
public class Sample03_MessageEncoding : SampleTest
11+
{
12+
[Test]
13+
public void ConfigureMessageEncodingAsync()
14+
{
15+
var connectionString = ConnectionString;
16+
var queueName = "foo";
17+
#region Snippet:Azure_Storage_Queues_Samples_Sample03_MessageEncoding_ConfigureMessageEncodingAsync
18+
19+
QueueClientOptions queueClientOptions = new QueueClientOptions()
20+
{
21+
MessageEncoding = QueueMessageEncoding.Base64
22+
};
23+
24+
QueueClient queueClient = new QueueClient(connectionString, queueName, queueClientOptions);
25+
#endregion
26+
}
27+
28+
[Test]
29+
public void MessageDecodingFailedHandlerAsync()
30+
{
31+
var connectionString = ConnectionString;
32+
var queueName = "foo";
33+
#region Snippet:Azure_Storage_Queues_Samples_Sample03_MessageEncoding_MessageDecodingFailedHandlerAsync
34+
35+
QueueClientOptions queueClientOptions = new QueueClientOptions()
36+
{
37+
MessageEncoding = QueueMessageEncoding.Base64
38+
};
39+
40+
queueClientOptions.MessageDecodingFailed += async (QueueMessageDecodingFailedEventArgs args) =>
41+
{
42+
if (args.PeekedMessage != null)
43+
{
44+
Console.WriteLine($"Invalid message has been peeked, message id={args.PeekedMessage.MessageId} body={args.PeekedMessage.Body}");
45+
}
46+
else if (args.ReceivedMessage != null)
47+
{
48+
Console.WriteLine($"Invalid message has been received, message id={args.ReceivedMessage.MessageId} body={args.ReceivedMessage.Body}");
49+
50+
if (args.RunSynchronously)
51+
{
52+
args.Queue.DeleteMessage(args.ReceivedMessage.MessageId, args.ReceivedMessage.PopReceipt);
53+
}
54+
else
55+
{
56+
await args.Queue.DeleteMessageAsync(args.ReceivedMessage.MessageId, args.ReceivedMessage.PopReceipt);
57+
}
58+
}
59+
};
60+
61+
QueueClient queueClient = new QueueClient(connectionString, queueName, queueClientOptions);
62+
#endregion
63+
}
64+
}
65+
}

sdk/storage/Azure.Storage.Queues/src/Azure.Storage.Queues.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
<Compile Include="$(AzureCoreSharedSources)HttpMessageSanitizer.cs" Link="Shared\Core\%(RecursiveDir)\%(Filename)%(Extension)" />
3737
<Compile Include="$(AzureCoreSharedSources)DiagnosticScopeFactory.cs" Link="Shared\Core\%(RecursiveDir)\%(Filename)%(Extension)" />
3838
<Compile Include="$(AzureCoreSharedSources)TaskExtensions.cs" Link="Shared\Core\%(RecursiveDir)\%(Filename)%(Extension)" />
39+
<Compile Include="$(AzureCoreSharedSources)SyncAsyncEventHandlerExtensions.cs" Link="Shared\Core\%(RecursiveDir)\%(Filename)%(Extension)" />
3940
</ItemGroup>
4041
<ItemGroup>
4142
<Compile Include="$(AzureStorageSharedSources)ClientsideEncryption\*.cs" Link="Shared\ClientsideEncryption\%(RecursiveDir)\%(Filename)%(Extension)" />

0 commit comments

Comments
 (0)