Skip to content

Allow blob name overriding #180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 35 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,15 @@ To Install from the Nuget Package Manager Console
* [Sending a message without exposing the storage account to receivers](#sending-a-message-without-exposing-the-storage-account-to-receivers)
* [Configure blob container name](#configure-blob-container-name)
* [Configure message property to identify attachment blob](#configure-message-property-to-identify-attachment-blob)
* [Configure custom blob name override](#configure-custom-blob-name-override)
* [Configure message property for SAS uri to attachment blob](#configure-message-property-for-sas-uri-to-attachment-blob)
* [Configure criteria for message max size identification](#configure-criteria-for-message-max-size-identification)
* [Configuring connection string provider](#configuring-connection-string-provider)
* [Configuring plugin using StorageCredentials (Service or Container SAS)](#configuring-plugin-using-storagecredentials-service-or-container-sas)
* [Using attachments with Azure Functions](#using-attachments-with-azure-functions)
* [Cleanup](#cleanup)
* [Who's trusting this plugin in production](#whos-trusting-this-plugin-in-production)
* [Icon](#icon)
<!-- endtoc -->

* [Icon](#icon)<!-- endtoc -->

## Examples

Expand All @@ -57,7 +56,7 @@ var sender = new MessageSender(connectionString, queueName);
var config = new AzureStorageAttachmentConfiguration(storageConnectionString);
sender.RegisterAzureStorageAttachmentPlugin(config);
```
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L14-L20) / [anchor](#snippet-configurationandregistration)</sup>
<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>
<!-- endsnippet -->

Sending
Expand All @@ -73,7 +72,7 @@ var serialized = JsonConvert.SerializeObject(payload);
var payloadAsBytes = Encoding.UTF8.GetBytes(serialized);
var message = new Message(payloadAsBytes);
```
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L26-L36) / [anchor](#snippet-attachmentsending)</sup>
<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>
<!-- endsnippet -->

Receiving
Expand All @@ -86,7 +85,7 @@ receiver.RegisterAzureStorageAttachmentPlugin(config);
var message = await receiver.ReceiveAsync().ConfigureAwait(false);
// message will contain the original payload
```
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L42-L49) / [anchor](#snippet-attachmentreceiving)</sup>
<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>
<!-- endsnippet -->

### Sending a message without exposing the storage account to receivers
Expand All @@ -103,7 +102,7 @@ var config = new AzureStorageAttachmentConfiguration(storageConnectionString)
messagePropertyToIdentifySasUri: "mySasUriProperty");
sender.RegisterAzureStorageAttachmentPlugin(config);
```
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L54-L63) / [anchor](#snippet-configurationandregistrationsas)</sup>
<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>
<!-- endsnippet -->

Sending
Expand All @@ -119,7 +118,7 @@ var serialized = JsonConvert.SerializeObject(payload);
var payloadAsBytes = Encoding.UTF8.GetBytes(serialized);
var message = new Message(payloadAsBytes);
```
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L69-L79) / [anchor](#snippet-attachmentsendingsas)</sup>
<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>
<!-- endsnippet -->

Receiving only mode (w/o Storage account credentials)
Expand All @@ -132,7 +131,7 @@ Receiving only mode (w/o Storage account credentials)
messageReceiver.RegisterAzureStorageAttachmentPluginForReceivingOnly("mySasUriProperty");
var message = await messageReceiver.ReceiveAsync().ConfigureAwait(false);
```
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L85-L92) / [anchor](#snippet-attachmentreceivingsas)</sup>
<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>
<!-- endsnippet -->

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

### Configure custom blob name override

Default blob name is a GUID.

<!-- snippet: Configure_blob_name_override -->
<a id='snippet-configure_blob_name_override'/></a>
```cs
var sender = new MessageSender(connectionString, queueName);
var config = new AzureStorageAttachmentConfiguration(storageConnectionString)
.OverrideBlobName(message =>
{
var tenantId = message.UserProperties["tenantId"].ToString();
var blobName = $"{tenantId}/{message.MessageId}";
return blobName;
});
sender.RegisterAzureStorageAttachmentPlugin(config);
```
<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>
<!-- endsnippet -->


### Configure message property for SAS uri to attachment blob

Default SAS uri property name is "$attachment.sas.uri".
Expand All @@ -170,7 +190,7 @@ Default is to convert any body to attachment.
new AzureStorageAttachmentConfiguration(storageConnectionString,
messageMaxSizeReachedCriteria: message => message.Body.Length > 200 * 1024);
```
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L97-L103) / [anchor](#snippet-configure_criteria_for_message_max_size_identification)</sup>
<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>
<!-- endsnippet -->

### Configuring connection string provider
Expand All @@ -184,7 +204,7 @@ The plugin comes with a `PlainTextConnectionStringProvider` and can be used in t
var provider = new PlainTextConnectionStringProvider(connectionString);
var config = new AzureStorageAttachmentConfiguration(provider);
```
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L109-L114) / [anchor](#snippet-configuring_connection_string_provider)</sup>
<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>
<!-- endsnippet -->

### Configuring plugin using StorageCredentials (Service or Container SAS)
Expand All @@ -195,10 +215,10 @@ var config = new AzureStorageAttachmentConfiguration(provider);
var credentials = new StorageCredentials( /*Shared key OR Service SAS OR Container SAS*/);
var config = new AzureStorageAttachmentConfiguration(credentials, blobEndpoint);
```
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L120-L125) / [anchor](#snippet-configuring_plugin_using_storagecredentials)</sup>
<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>
<!-- endsnippet -->

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

### Using attachments with Azure Functions

Expand All @@ -214,7 +234,7 @@ Upload attachment to Azure Storage blob
//To make it possible to use SAS URI when downloading, use WithBlobSasUri() when creating configuration object
await message.UploadAzureStorageAttachment(config);
```
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L130-L135) / [anchor](#snippet-upload_attachment_without_registering_plugin)</sup>
<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>
<!-- endsnippet -->

Download attachment from Azure Storage blob
Expand All @@ -231,7 +251,7 @@ await message.DownloadAzureStorageAttachment("$custom-attachment.sas.uri");
//Using configuration object
await message.DownloadAzureStorageAttachment(config);
```
<sup>[snippet source](/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs#L139-L150) / [anchor](#snippet-download_attachment_without_registering_plugin)</sup>
<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>
<!-- endsnippet -->

#### Additional providers
Expand Down
7 changes: 7 additions & 0 deletions README.source.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ Default blob identifier property name is "$attachment.blob".
new AzureStorageAttachmentConfiguration(storageConnectionString, messagePropertyToIdentifyAttachmentBlob: "myblob");
```

### Configure custom blob name override

Default blob name is a GUID.

snippet: Configure_blob_name_override


### Configure message property for SAS uri to attachment blob

Default SAS uri property name is "$attachment.sas.uri".
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Microsoft.Azure.ServiceBus
}
public static class AzureStorageAttachmentConfigurationExtensions
{
public static Microsoft.Azure.ServiceBus.AzureStorageAttachmentConfiguration OverrideBlobName(this Microsoft.Azure.ServiceBus.AzureStorageAttachmentConfiguration azureStorageAttachmentConfiguration, System.Func<Microsoft.Azure.ServiceBus.Message, string> blobNameResolver) { }
public static Microsoft.Azure.ServiceBus.AzureStorageAttachmentConfiguration WithBlobSasUri(this Microsoft.Azure.ServiceBus.AzureStorageAttachmentConfiguration azureStorageAttachmentConfiguration, string messagePropertyToIdentifySasUri = "$attachment.sas.uri", System.TimeSpan? sasTokenValidationTime = default) { }
}
public static class AzureStorageAttachmentExtensions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net461</TargetFrameworks>
<TargetFrameworks>netcoreapp3.1;net461</TargetFrameworks>
<RootNamespace>ServiceBus.AttachmentPlugin.Tests</RootNamespace>
<Optimize>false</Optimize>
<SignAssembly>true</SignAssembly>
Expand Down
17 changes: 17 additions & 0 deletions src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,23 @@ void ConfigurationAndRegistrationSas(string connectionString, string queueName,
#endregion
}

void Configure_blob_name_override(string connectionString, string queueName, string storageConnectionString)
{
#region Configure_blob_name_override

var sender = new MessageSender(connectionString, queueName);
var config = new AzureStorageAttachmentConfiguration(storageConnectionString)
.OverrideBlobName(message =>
{
var tenantId = message.UserProperties["tenantId"].ToString();
var blobName = $"{tenantId}/{message.MessageId}";
return blobName;
});
sender.RegisterAzureStorageAttachmentPlugin(config);

#endregion
}

[SuppressMessage("ReSharper", "UnusedVariable")]
void AttachmentSendingSas()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace ServiceBus.AttachmentPlugin.Tests
{
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.ServiceBus;
Expand Down Expand Up @@ -71,5 +72,26 @@ public async Task Should_send_and_receive_with_custom_sas_uri_property()

Assert.Equal(payload, Encoding.UTF8.GetString(receivedMessage.Body));
}

[Fact]
public async Task Should_be_able_to_override_blob_name_and_receive_message_payload_using_the_new_name()
{
var payload = "payload";
var bytes = Encoding.UTF8.GetBytes(payload);
var message = new Message(bytes) { MessageId = Guid.NewGuid().ToString("N") };
var configuration = new AzureStorageAttachmentConfiguration(
connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider);

configuration.OverrideBlobName(msg => $"test/{msg.MessageId}");

await message.UploadAzureStorageAttachment(configuration);

Assert.Null(message.Body);

var receivedMessage = await message.DownloadAzureStorageAttachment(configuration);

Assert.Equal(payload, Encoding.UTF8.GetString(receivedMessage.Body));
Assert.Equal($"test/{message.MessageId}", message.UserProperties[configuration.MessagePropertyToIdentifyAttachmentBlob]);
}
}
}
5 changes: 3 additions & 2 deletions src/ServiceBus.AttachmentPlugin/AzureStorageAttachment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public override async Task<Message> BeforeMessageSend(Message message)
// swallow in case a container SAS is used
}

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

SetValidMessageId(blob, message.MessageId);
Expand Down Expand Up @@ -104,7 +105,7 @@ static void SetValidUntil(ICloudBlob blob, TimeSpan timeToBeReceived)
public override async Task<Message> AfterMessageReceive(Message message)
{
var userProperties = message.UserProperties;

if (!userProperties.TryGetValue(configuration.MessagePropertyToIdentifyAttachmentBlob, out var blobNameObject))
{
return message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,7 @@ Func<Message, bool> GetMessageMaxSizeReachedCriteria(Func<Message, bool>? messag
internal bool UsingSas => StorageCredentials.IsSAS;

internal Uri BlobEndpoint { get; }

internal Func<Message, string> BlobNameResolver { get; set; } = message => Guid.NewGuid().ToString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,33 @@ public static AzureStorageAttachmentConfiguration WithBlobSasUri(
return azureStorageAttachmentConfiguration;
}

/// <summary>
/// Allow attachment blob name overriding.
/// </summary>
/// <param name="azureStorageAttachmentConfiguration"></param>
/// <param name="blobNameResolver">A custom blob name resolver to override the default name set to a GUID.</param>
/// <returns></returns>
public static AzureStorageAttachmentConfiguration OverrideBlobName(
this AzureStorageAttachmentConfiguration azureStorageAttachmentConfiguration,
Func<Message, string> blobNameResolver)
{
Guard.AgainstNull(nameof(blobNameResolver), blobNameResolver);

azureStorageAttachmentConfiguration.BlobNameResolver = BlobNameResolver;

return azureStorageAttachmentConfiguration;

string BlobNameResolver(Message message)
{
try
{
return blobNameResolver(message);
}
catch (Exception exception)
{
throw new Exception("An exception occurred when executing the blobNameResolver delegate.", exception);
}
}
}
}
}