Skip to content

Commit a1f0dbb

Browse files
authored
Allow blob name overriding (#180)
* Add blob name resolver to the configuration * Add verification test
1 parent 5bc05be commit a1f0dbb

9 files changed

+116
-18
lines changed

README.md

+35-15
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,15 @@ To Install from the Nuget Package Manager Console
3333
* [Sending a message without exposing the storage account to receivers](#sending-a-message-without-exposing-the-storage-account-to-receivers)
3434
* [Configure blob container name](#configure-blob-container-name)
3535
* [Configure message property to identify attachment blob](#configure-message-property-to-identify-attachment-blob)
36+
* [Configure custom blob name override](#configure-custom-blob-name-override)
3637
* [Configure message property for SAS uri to attachment blob](#configure-message-property-for-sas-uri-to-attachment-blob)
3738
* [Configure criteria for message max size identification](#configure-criteria-for-message-max-size-identification)
3839
* [Configuring connection string provider](#configuring-connection-string-provider)
3940
* [Configuring plugin using StorageCredentials (Service or Container SAS)](#configuring-plugin-using-storagecredentials-service-or-container-sas)
4041
* [Using attachments with Azure Functions](#using-attachments-with-azure-functions)
4142
* [Cleanup](#cleanup)
4243
* [Who's trusting this plugin in production](#whos-trusting-this-plugin-in-production)
43-
* [Icon](#icon)
44-
<!-- endtoc -->
45-
44+
* [Icon](#icon)<!-- endtoc -->
4645

4746
## Examples
4847

@@ -57,7 +56,7 @@ var sender = new MessageSender(connectionString, queueName);
5756
var config = new AzureStorageAttachmentConfiguration(storageConnectionString);
5857
sender.RegisterAzureStorageAttachmentPlugin(config);
5958
```
60-
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L14-L20) / [anchor](#snippet-configurationandregistration)</sup>
59+
<sup><a href='/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L14-L20' title='File snippet `configurationandregistration` was extracted from'>snippet source</a> | <a href='#snippet-configurationandregistration' title='Navigate to start of snippet `configurationandregistration`'>anchor</a></sup>
6160
<!-- endsnippet -->
6261

6362
Sending
@@ -73,7 +72,7 @@ var serialized = JsonConvert.SerializeObject(payload);
7372
var payloadAsBytes = Encoding.UTF8.GetBytes(serialized);
7473
var message = new Message(payloadAsBytes);
7574
```
76-
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L26-L36) / [anchor](#snippet-attachmentsending)</sup>
75+
<sup><a href='/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L26-L36' title='File snippet `attachmentsending` was extracted from'>snippet source</a> | <a href='#snippet-attachmentsending' title='Navigate to start of snippet `attachmentsending`'>anchor</a></sup>
7776
<!-- endsnippet -->
7877

7978
Receiving
@@ -86,7 +85,7 @@ receiver.RegisterAzureStorageAttachmentPlugin(config);
8685
var message = await receiver.ReceiveAsync().ConfigureAwait(false);
8786
// message will contain the original payload
8887
```
89-
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L42-L49) / [anchor](#snippet-attachmentreceiving)</sup>
88+
<sup><a href='/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L42-L49' title='File snippet `attachmentreceiving` was extracted from'>snippet source</a> | <a href='#snippet-attachmentreceiving' title='Navigate to start of snippet `attachmentreceiving`'>anchor</a></sup>
9089
<!-- endsnippet -->
9190

9291
### Sending a message without exposing the storage account to receivers
@@ -103,7 +102,7 @@ var config = new AzureStorageAttachmentConfiguration(storageConnectionString)
103102
messagePropertyToIdentifySasUri: "mySasUriProperty");
104103
sender.RegisterAzureStorageAttachmentPlugin(config);
105104
```
106-
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L54-L63) / [anchor](#snippet-configurationandregistrationsas)</sup>
105+
<sup><a href='/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L54-L63' title='File snippet `configurationandregistrationsas` was extracted from'>snippet source</a> | <a href='#snippet-configurationandregistrationsas' title='Navigate to start of snippet `configurationandregistrationsas`'>anchor</a></sup>
107106
<!-- endsnippet -->
108107

109108
Sending
@@ -119,7 +118,7 @@ var serialized = JsonConvert.SerializeObject(payload);
119118
var payloadAsBytes = Encoding.UTF8.GetBytes(serialized);
120119
var message = new Message(payloadAsBytes);
121120
```
122-
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L69-L79) / [anchor](#snippet-attachmentsendingsas)</sup>
121+
<sup><a href='/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L86-L96' title='File snippet `attachmentsendingsas` was extracted from'>snippet source</a> | <a href='#snippet-attachmentsendingsas' title='Navigate to start of snippet `attachmentsendingsas`'>anchor</a></sup>
123122
<!-- endsnippet -->
124123

125124
Receiving only mode (w/o Storage account credentials)
@@ -132,7 +131,7 @@ Receiving only mode (w/o Storage account credentials)
132131
messageReceiver.RegisterAzureStorageAttachmentPluginForReceivingOnly("mySasUriProperty");
133132
var message = await messageReceiver.ReceiveAsync().ConfigureAwait(false);
134133
```
135-
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L85-L92) / [anchor](#snippet-attachmentreceivingsas)</sup>
134+
<sup><a href='/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L102-L109' title='File snippet `attachmentreceivingsas` was extracted from'>snippet source</a> | <a href='#snippet-attachmentreceivingsas' title='Navigate to start of snippet `attachmentreceivingsas`'>anchor</a></sup>
136135
<!-- endsnippet -->
137136

138137
### Configure blob container name
@@ -151,6 +150,27 @@ Default blob identifier property name is "$attachment.blob".
151150
new AzureStorageAttachmentConfiguration(storageConnectionString, messagePropertyToIdentifyAttachmentBlob: "myblob");
152151
```
153152

153+
### Configure custom blob name override
154+
155+
Default blob name is a GUID.
156+
157+
<!-- snippet: Configure_blob_name_override -->
158+
<a id='snippet-configure_blob_name_override'/></a>
159+
```cs
160+
var sender = new MessageSender(connectionString, queueName);
161+
var config = new AzureStorageAttachmentConfiguration(storageConnectionString)
162+
.OverrideBlobName(message =>
163+
{
164+
var tenantId = message.UserProperties["tenantId"].ToString();
165+
var blobName = $"{tenantId}/{message.MessageId}";
166+
return blobName;
167+
});
168+
sender.RegisterAzureStorageAttachmentPlugin(config);
169+
```
170+
<sup><a href='/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L68-L80' title='File snippet `configure_blob_name_override` was extracted from'>snippet source</a> | <a href='#snippet-configure_blob_name_override' title='Navigate to start of snippet `configure_blob_name_override`'>anchor</a></sup>
171+
<!-- endsnippet -->
172+
173+
154174
### Configure message property for SAS uri to attachment blob
155175

156176
Default SAS uri property name is "$attachment.sas.uri".
@@ -170,7 +190,7 @@ Default is to convert any body to attachment.
170190
new AzureStorageAttachmentConfiguration(storageConnectionString,
171191
messageMaxSizeReachedCriteria: message => message.Body.Length > 200 * 1024);
172192
```
173-
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L97-L103) / [anchor](#snippet-configure_criteria_for_message_max_size_identification)</sup>
193+
<sup><a href='/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L114-L120' title='File snippet `configure_criteria_for_message_max_size_identification` was extracted from'>snippet source</a> | <a href='#snippet-configure_criteria_for_message_max_size_identification' title='Navigate to start of snippet `configure_criteria_for_message_max_size_identification`'>anchor</a></sup>
174194
<!-- endsnippet -->
175195

176196
### Configuring connection string provider
@@ -184,7 +204,7 @@ The plugin comes with a `PlainTextConnectionStringProvider` and can be used in t
184204
var provider = new PlainTextConnectionStringProvider(connectionString);
185205
var config = new AzureStorageAttachmentConfiguration(provider);
186206
```
187-
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L109-L114) / [anchor](#snippet-configuring_connection_string_provider)</sup>
207+
<sup><a href='/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L126-L131' title='File snippet `configuring_connection_string_provider` was extracted from'>snippet source</a> | <a href='#snippet-configuring_connection_string_provider' title='Navigate to start of snippet `configuring_connection_string_provider`'>anchor</a></sup>
188208
<!-- endsnippet -->
189209

190210
### Configuring plugin using StorageCredentials (Service or Container SAS)
@@ -195,10 +215,10 @@ var config = new AzureStorageAttachmentConfiguration(provider);
195215
var credentials = new StorageCredentials( /*Shared key OR Service SAS OR Container SAS*/);
196216
var config = new AzureStorageAttachmentConfiguration(credentials, blobEndpoint);
197217
```
198-
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L120-L125) / [anchor](#snippet-configuring_plugin_using_storagecredentials)</sup>
218+
<sup><a href='/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L137-L142' title='File snippet `configuring_plugin_using_storagecredentials` was extracted from'>snippet source</a> | <a href='#snippet-configuring_plugin_using_storagecredentials' title='Navigate to start of snippet `configuring_plugin_using_storagecredentials`'>anchor</a></sup>
199219
<!-- endsnippet -->
200220

201-
See [`StorageCredentials`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.storage.auth.storagecredentials?) for more details.
221+
See [`StorageCredentials`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.storage.auth.storagecredentials) for more details.
202222

203223
### Using attachments with Azure Functions
204224

@@ -214,7 +234,7 @@ Upload attachment to Azure Storage blob
214234
//To make it possible to use SAS URI when downloading, use WithBlobSasUri() when creating configuration object
215235
await message.UploadAzureStorageAttachment(config);
216236
```
217-
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L130-L135) / [anchor](#snippet-upload_attachment_without_registering_plugin)</sup>
237+
<sup><a href='/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L147-L152' title='File snippet `upload_attachment_without_registering_plugin` was extracted from'>snippet source</a> | <a href='#snippet-upload_attachment_without_registering_plugin' title='Navigate to start of snippet `upload_attachment_without_registering_plugin`'>anchor</a></sup>
218238
<!-- endsnippet -->
219239

220240
Download attachment from Azure Storage blob
@@ -231,7 +251,7 @@ await message.DownloadAzureStorageAttachment("$custom-attachment.sas.uri");
231251
//Using configuration object
232252
await message.DownloadAzureStorageAttachment(config);
233253
```
234-
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L139-L150) / [anchor](#snippet-download_attachment_without_registering_plugin)</sup>
254+
<sup><a href='/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L156-L167' title='File snippet `download_attachment_without_registering_plugin` was extracted from'>snippet source</a> | <a href='#snippet-download_attachment_without_registering_plugin' title='Navigate to start of snippet `download_attachment_without_registering_plugin`'>anchor</a></sup>
235255
<!-- endsnippet -->
236256

237257
#### Additional providers

README.source.md

+7
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ Default blob identifier property name is "$attachment.blob".
6666
new AzureStorageAttachmentConfiguration(storageConnectionString, messagePropertyToIdentifyAttachmentBlob: "myblob");
6767
```
6868

69+
### Configure custom blob name override
70+
71+
Default blob name is a GUID.
72+
73+
snippet: Configure_blob_name_override
74+
75+
6976
### Configure message property for SAS uri to attachment blob
7077

7178
Default SAS uri property name is "$attachment.sas.uri".

src/ServiceBus.AttachmentPlugin.Tests/ApprovalFiles/ApiApprovals.AzureStorageAttachmentPlugin.approved.txt

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace Microsoft.Azure.ServiceBus
99
}
1010
public static class AzureStorageAttachmentConfigurationExtensions
1111
{
12+
public static Microsoft.Azure.ServiceBus.AzureStorageAttachmentConfiguration OverrideBlobName(this Microsoft.Azure.ServiceBus.AzureStorageAttachmentConfiguration azureStorageAttachmentConfiguration, System.Func<Microsoft.Azure.ServiceBus.Message, string> blobNameResolver) { }
1213
public static Microsoft.Azure.ServiceBus.AzureStorageAttachmentConfiguration WithBlobSasUri(this Microsoft.Azure.ServiceBus.AzureStorageAttachmentConfiguration azureStorageAttachmentConfiguration, string messagePropertyToIdentifySasUri = "$attachment.sas.uri", System.TimeSpan? sasTokenValidationTime = default) { }
1314
}
1415
public static class AzureStorageAttachmentExtensions

src/ServiceBus.AttachmentPlugin.Tests/ServiceBus.AttachmentPlugin.Tests.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>netcoreapp3.0;net461</TargetFrameworks>
4+
<TargetFrameworks>netcoreapp3.1;net461</TargetFrameworks>
55
<RootNamespace>ServiceBus.AttachmentPlugin.Tests</RootNamespace>
66
<Optimize>false</Optimize>
77
<SignAssembly>true</SignAssembly>

src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs

+17
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,23 @@ void ConfigurationAndRegistrationSas(string connectionString, string queueName,
6363
#endregion
6464
}
6565

66+
void Configure_blob_name_override(string connectionString, string queueName, string storageConnectionString)
67+
{
68+
#region Configure_blob_name_override
69+
70+
var sender = new MessageSender(connectionString, queueName);
71+
var config = new AzureStorageAttachmentConfiguration(storageConnectionString)
72+
.OverrideBlobName(message =>
73+
{
74+
var tenantId = message.UserProperties["tenantId"].ToString();
75+
var blobName = $"{tenantId}/{message.MessageId}";
76+
return blobName;
77+
});
78+
sender.RegisterAzureStorageAttachmentPlugin(config);
79+
80+
#endregion
81+
}
82+
6683
[SuppressMessage("ReSharper", "UnusedVariable")]
6784
void AttachmentSendingSas()
6885
{

src/ServiceBus.AttachmentPlugin.Tests/When_using_message_extensions.cs

+22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace ServiceBus.AttachmentPlugin.Tests
22
{
3+
using System;
34
using System.Text;
45
using System.Threading.Tasks;
56
using Microsoft.Azure.ServiceBus;
@@ -71,5 +72,26 @@ public async Task Should_send_and_receive_with_custom_sas_uri_property()
7172

7273
Assert.Equal(payload, Encoding.UTF8.GetString(receivedMessage.Body));
7374
}
75+
76+
[Fact]
77+
public async Task Should_be_able_to_override_blob_name_and_receive_message_payload_using_the_new_name()
78+
{
79+
var payload = "payload";
80+
var bytes = Encoding.UTF8.GetBytes(payload);
81+
var message = new Message(bytes) { MessageId = Guid.NewGuid().ToString("N") };
82+
var configuration = new AzureStorageAttachmentConfiguration(
83+
connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider);
84+
85+
configuration.OverrideBlobName(msg => $"test/{msg.MessageId}");
86+
87+
await message.UploadAzureStorageAttachment(configuration);
88+
89+
Assert.Null(message.Body);
90+
91+
var receivedMessage = await message.DownloadAzureStorageAttachment(configuration);
92+
93+
Assert.Equal(payload, Encoding.UTF8.GetString(receivedMessage.Body));
94+
Assert.Equal($"test/{message.MessageId}", message.UserProperties[configuration.MessagePropertyToIdentifyAttachmentBlob]);
95+
}
7496
}
7597
}

src/ServiceBus.AttachmentPlugin/AzureStorageAttachment.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ public override async Task<Message> BeforeMessageSend(Message message)
5656
// swallow in case a container SAS is used
5757
}
5858

59-
var blobUri = new Uri($"{containerUri}/{Guid.NewGuid().ToString()}");
59+
var blobName = configuration.BlobNameResolver(message);
60+
var blobUri = new Uri($"{containerUri}/{blobName}");
6061
var blob = new CloudBlockBlob(blobUri, configuration.StorageCredentials);
6162

6263
SetValidMessageId(blob, message.MessageId);
@@ -104,7 +105,7 @@ static void SetValidUntil(ICloudBlob blob, TimeSpan timeToBeReceived)
104105
public override async Task<Message> AfterMessageReceive(Message message)
105106
{
106107
var userProperties = message.UserProperties;
107-
108+
108109
if (!userProperties.TryGetValue(configuration.MessagePropertyToIdentifyAttachmentBlob, out var blobNameObject))
109110
{
110111
return message;

src/ServiceBus.AttachmentPlugin/AzureStorageAttachmentConfiguration.cs

+2
Original file line numberDiff line numberDiff line change
@@ -120,5 +120,7 @@ Func<Message, bool> GetMessageMaxSizeReachedCriteria(Func<Message, bool>? messag
120120
internal bool UsingSas => StorageCredentials.IsSAS;
121121

122122
internal Uri BlobEndpoint { get; }
123+
124+
internal Func<Message, string> BlobNameResolver { get; set; } = message => Guid.NewGuid().ToString();
123125
}
124126
}

src/ServiceBus.AttachmentPlugin/AzureStorageAttachmentConfigurationExtensions.cs

+28
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,33 @@ public static AzureStorageAttachmentConfiguration WithBlobSasUri(
3939
return azureStorageAttachmentConfiguration;
4040
}
4141

42+
/// <summary>
43+
/// Allow attachment blob name overriding.
44+
/// </summary>
45+
/// <param name="azureStorageAttachmentConfiguration"></param>
46+
/// <param name="blobNameResolver">A custom blob name resolver to override the default name set to a GUID.</param>
47+
/// <returns></returns>
48+
public static AzureStorageAttachmentConfiguration OverrideBlobName(
49+
this AzureStorageAttachmentConfiguration azureStorageAttachmentConfiguration,
50+
Func<Message, string> blobNameResolver)
51+
{
52+
Guard.AgainstNull(nameof(blobNameResolver), blobNameResolver);
53+
54+
azureStorageAttachmentConfiguration.BlobNameResolver = BlobNameResolver;
55+
56+
return azureStorageAttachmentConfiguration;
57+
58+
string BlobNameResolver(Message message)
59+
{
60+
try
61+
{
62+
return blobNameResolver(message);
63+
}
64+
catch (Exception exception)
65+
{
66+
throw new Exception("An exception occurred when executing the blobNameResolver delegate.", exception);
67+
}
68+
}
69+
}
4270
}
4371
}

0 commit comments

Comments
 (0)