diff --git a/README.md b/README.md index 7871a4c..5251d38 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ var sender = new MessageSender(connectionString, queueName); var config = new AzureStorageAttachmentConfiguration(storageConnectionString); sender.RegisterAzureStorageAttachmentPlugin(config); ``` -snippet source | anchor +snippet source | anchor Sending @@ -72,7 +72,7 @@ var serialized = JsonConvert.SerializeObject(payload); var payloadAsBytes = Encoding.UTF8.GetBytes(serialized); var message = new Message(payloadAsBytes); ``` -snippet source | anchor +snippet source | anchor Receiving @@ -85,7 +85,7 @@ receiver.RegisterAzureStorageAttachmentPlugin(config); var message = await receiver.ReceiveAsync().ConfigureAwait(false); // message will contain the original payload ``` -snippet source | anchor +snippet source | anchor ### Sending a message without exposing the storage account to receivers @@ -102,7 +102,7 @@ var config = new AzureStorageAttachmentConfiguration(storageConnectionString) messagePropertyToIdentifySasUri: "mySasUriProperty"); sender.RegisterAzureStorageAttachmentPlugin(config); ``` -snippet source | anchor +snippet source | anchor Sending @@ -118,7 +118,7 @@ var serialized = JsonConvert.SerializeObject(payload); var payloadAsBytes = Encoding.UTF8.GetBytes(serialized); var message = new Message(payloadAsBytes); ``` -snippet source | anchor +snippet source | anchor Receiving only mode (w/o Storage account credentials) @@ -131,7 +131,7 @@ Receiving only mode (w/o Storage account credentials) messageReceiver.RegisterAzureStorageAttachmentPluginForReceivingOnly("mySasUriProperty"); var message = await messageReceiver.ReceiveAsync().ConfigureAwait(false); ``` -snippet source | anchor +snippet source | anchor ### Configure blob container name @@ -167,7 +167,7 @@ var config = new AzureStorageAttachmentConfiguration(storageConnectionString) }); sender.RegisterAzureStorageAttachmentPlugin(config); ``` -snippet source | anchor +snippet source | anchor @@ -185,7 +185,7 @@ new AzureStorageAttachmentConfiguration(storageConnectionString) messagePropertyToIdentifySasUri: "mySasUriProperty", sasTokenValidationTime: TimeSpan.FromHours(12)); ``` -snippet source | anchor +snippet source | anchor ### Configure criteria for message max size identification @@ -199,7 +199,7 @@ Default is to convert any body to attachment. new AzureStorageAttachmentConfiguration(storageConnectionString, messageMaxSizeReachedCriteria: message => message.Body.Length > 200 * 1024); ``` -snippet source | anchor +snippet source | anchor ### Configuring connection string provider @@ -213,7 +213,7 @@ The plugin comes with a `PlainTextConnectionStringProvider` and can be used in t var provider = new PlainTextConnectionStringProvider(connectionString); var config = new AzureStorageAttachmentConfiguration(provider); ``` -snippet source | anchor +snippet source | anchor ### Configuring plugin using StorageCredentials (Service or Container SAS) @@ -221,10 +221,11 @@ var config = new AzureStorageAttachmentConfiguration(provider); ```cs -var credentials = new StorageCredentials( /*Shared key OR Service SAS OR Container SAS*/); -var config = new AzureStorageAttachmentConfiguration(credentials, blobEndpoint); +// TODO: change +// var credentials = new StorageCredentials( /*Shared key OR Service SAS OR Container SAS*/); +// var config = new AzureStorageAttachmentConfiguration(credentials, blobEndpoint); ``` -snippet source | anchor +snippet source | anchor See [`StorageCredentials`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.storage.auth.storagecredentials) for more details. diff --git a/src/ServiceBus.AttachmentPlugin.Tests/AzureStorageAttachmentConfigurationTests.cs b/src/ServiceBus.AttachmentPlugin.Tests/AzureStorageAttachmentConfigurationTests.cs index 28fe908..d6acc87 100644 --- a/src/ServiceBus.AttachmentPlugin.Tests/AzureStorageAttachmentConfigurationTests.cs +++ b/src/ServiceBus.AttachmentPlugin.Tests/AzureStorageAttachmentConfigurationTests.cs @@ -1,9 +1,7 @@ namespace ServiceBus.AttachmentPlugin.Tests { using System; - using System.Threading.Tasks; using Microsoft.Azure.ServiceBus; - using Microsoft.Azure.Storage.Auth; using Xunit; public class AzureStorageAttachmentConfigurationTests @@ -11,11 +9,10 @@ public class AzureStorageAttachmentConfigurationTests const string ConnectionString = "AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;DefaultEndpointsProtocol=http;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1"; [Fact] - public async Task Should_apply_defaults_for_missing_arguments() + public void Should_apply_defaults_for_missing_arguments() { - var configuration = new AzureStorageAttachmentConfiguration(new PlainTextConnectionStringProvider(ConnectionString)) + var configuration = new AzureStorageAttachmentConfiguration(ConnectionString) .WithBlobSasUri(); - Assert.Equal(ConnectionString, await configuration.ConnectionStringProvider!.GetConnectionString()); Assert.NotEmpty(configuration.ContainerName); Assert.NotEmpty(configuration.MessagePropertyToIdentifyAttachmentBlob); Assert.Equal(AzureStorageAttachmentConfigurationExtensions.DefaultSasTokenValidationTime.Days, configuration.BlobSasTokenValidationTime!.Value.Days); @@ -25,12 +22,12 @@ public async Task Should_apply_defaults_for_missing_arguments() [Fact] public void Should_not_accept_negative_token_validation_time() => - Assert.Throws(() => new AzureStorageAttachmentConfiguration(new PlainTextConnectionStringProvider(ConnectionString)) + Assert.Throws(() => new AzureStorageAttachmentConfiguration(ConnectionString) .WithBlobSasUri(sasTokenValidationTime: TimeSpan.FromHours(-4))); [Fact] public void Should_throw_when_embedded_SAS_option_is_used_with_container_SAS() => Assert.Throws(() => new AzureStorageAttachmentConfiguration( - new StorageCredentials("?sv=2018-03-28&sr=c&sig=5XxlRKoP4yEmibM2HhJlQuV7MG3rYgQXD89mLpNp%2F24%3D"), "http://127.0.0.1:10000/devstoreaccount1", "devstoreaccount1").WithBlobSasUri()); + "http://127.0.0.1:10000/devstoreaccount1?sv=2018-03-28&sr=c&sig=5XxlRKoP4yEmibM2HhJlQuV7MG3rYgQXD89mLpNp%2F24%3D", "devstoreaccount1").WithBlobSasUri()); } } \ No newline at end of file diff --git a/src/ServiceBus.AttachmentPlugin.Tests/AzureStorageEmulatorFixture.cs b/src/ServiceBus.AttachmentPlugin.Tests/AzureStorageEmulatorFixture.cs index 8409c61..af30740 100644 --- a/src/ServiceBus.AttachmentPlugin.Tests/AzureStorageEmulatorFixture.cs +++ b/src/ServiceBus.AttachmentPlugin.Tests/AzureStorageEmulatorFixture.cs @@ -1,73 +1,77 @@ namespace ServiceBus.AttachmentPlugin.Tests { using System; + using System.Linq; using System.Threading.Tasks; - using Microsoft.Azure.ServiceBus; - using Microsoft.Azure.Storage; - using Microsoft.Azure.Storage.Blob; + using Azure.Storage; + using Azure.Storage.Blobs; + using Azure.Storage.Blobs.Models; + using Azure.Storage.Sas; public class AzureStorageEmulatorFixture { - static string ConnectionString = "UseDevelopmentStorage=true"; - public static IProvideStorageConnectionString ConnectionStringProvider = new PlainTextConnectionStringProvider(ConnectionString); - CloudStorageAccount TestingStorageAccount = CloudStorageAccount.Parse(ConnectionString); + // development account + public const string TestingStorageAccountConnectionString = "UseDevelopmentStorage=true;"; - public string GetBlobEndpoint() + public static string GetBlobEndpoint() { - return TestingStorageAccount.BlobEndpoint.ToString(); + return "http://127.0.0.1:10000/devstoreaccount1"; } - public async Task GetContainerSas(string containerName) + public static async Task GetContainerSas(string containerName) { // get container - var blobClient = TestingStorageAccount.CreateCloudBlobClient(); - var container = blobClient.GetContainerReference(containerName); - if (!await container.ExistsAsync()) + var containerClient = new BlobContainerClient(TestingStorageAccountConnectionString, containerName); + if (!await containerClient.ExistsAsync()) { - await container.CreateIfNotExistsAsync(); + await containerClient.CreateIfNotExistsAsync(); } - await container.FetchAttributesAsync(); - var permissionsFound = await container.GetPermissionsAsync(); + await containerClient.GetPropertiesAsync(); + BlobContainerAccessPolicy permissionsFound = await containerClient.GetAccessPolicyAsync(); // create access policy and store it var accessPolicyId = "test-policy"; - if (!permissionsFound.SharedAccessPolicies.ContainsKey(accessPolicyId)) + var blobSignedIdentifier = permissionsFound.SignedIdentifiers.FirstOrDefault(x=> x.Id == accessPolicyId); + if (blobSignedIdentifier is null) { - var permissions = new BlobContainerPermissions + var permissions = new BlobSignedIdentifier { - PublicAccess = BlobContainerPublicAccessType.Off, - SharedAccessPolicies = + Id = accessPolicyId, + AccessPolicy = new BlobAccessPolicy { - { - accessPolicyId, - new SharedAccessBlobPolicy - { - Permissions = SharedAccessBlobPermissions.Add | SharedAccessBlobPermissions.Create | SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Write, - SharedAccessStartTime = DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(1)), - SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddDays(1) - } - } + Permissions = "acrw" } }; - await container.SetPermissionsAsync(permissions); + await containerClient.SetAccessPolicyAsync(PublicAccessType.None, new []{permissions}); } else { - permissionsFound.SharedAccessPolicies[accessPolicyId].SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddDays(1); - await container.SetPermissionsAsync(permissionsFound); + blobSignedIdentifier.AccessPolicy.ExpiresOn = DateTimeOffset.UtcNow.AddDays(1); + await containerClient.SetAccessPolicyAsync(PublicAccessType.None, new []{blobSignedIdentifier}); } - + // create SAS with policy - return container.GetSharedAccessSignature(null, accessPolicyId); + //return containerClient.sas.GetSharedAccessSignature(null, accessPolicyId); + + var blobSasBuilder = new BlobSasBuilder + { + Identifier = accessPolicyId, + BlobContainerName = containerName, + // StartsOn = DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(1)), + // ExpiresOn = DateTimeOffset.UtcNow.AddDays(1) + }; + //blobSasBuilder.SetPermissions(BlobSasPermissions.Add | BlobSasPermissions.Create | BlobSasPermissions.Read | BlobSasPermissions.Write); + var blobSasQueryParameters = blobSasBuilder.ToSasQueryParameters(new StorageSharedKeyCredential("devstoreaccount1", "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==")); + var fullUri = $"{GetBlobEndpoint()}?{blobSasQueryParameters}"; + return fullUri; } public async Task CreateContainer(string containerName) { - var containerUri = new Uri($"{TestingStorageAccount.BlobEndpoint}/{containerName}"); - var container = new CloudBlobContainer(containerUri, TestingStorageAccount.Credentials); + var container = new BlobContainerClient(TestingStorageAccountConnectionString, containerName); if (!await container.ExistsAsync()) { await container.CreateIfNotExistsAsync(); @@ -75,8 +79,7 @@ public async Task CreateContainer(string containerName) } public async Task DeleteContainer(string containerName) { - var containerUri = new Uri($"{TestingStorageAccount.BlobEndpoint}/{containerName}"); - var container = new CloudBlobContainer(containerUri, TestingStorageAccount.Credentials); + var container = new BlobContainerClient(TestingStorageAccountConnectionString, containerName); if (await container.ExistsAsync()) { await container.DeleteIfExistsAsync(); diff --git a/src/ServiceBus.AttachmentPlugin.Tests/ServiceBus.AttachmentPlugin.Tests.csproj b/src/ServiceBus.AttachmentPlugin.Tests/ServiceBus.AttachmentPlugin.Tests.csproj index 986d688..49a8261 100644 --- a/src/ServiceBus.AttachmentPlugin.Tests/ServiceBus.AttachmentPlugin.Tests.csproj +++ b/src/ServiceBus.AttachmentPlugin.Tests/ServiceBus.AttachmentPlugin.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1;net461 + netcoreapp3.1 ServiceBus.AttachmentPlugin.Tests false true diff --git a/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs b/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs index 8254533..c9bd09a 100644 --- a/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs +++ b/src/ServiceBus.AttachmentPlugin.Tests/Snippets.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Microsoft.Azure.ServiceBus; using Microsoft.Azure.ServiceBus.Core; -using Microsoft.Azure.Storage.Auth; using Newtonsoft.Json; class Snippets @@ -161,8 +160,9 @@ void Configuring_plugin_using_StorageCredentials(string connectionString, string { #region Configuring_plugin_using_StorageCredentials - var credentials = new StorageCredentials( /*Shared key OR Service SAS OR Container SAS*/); - var config = new AzureStorageAttachmentConfiguration(credentials, blobEndpoint); + // TODO: change + // var credentials = new StorageCredentials( /*Shared key OR Service SAS OR Container SAS*/); + // var config = new AzureStorageAttachmentConfiguration(credentials, blobEndpoint); #endregion } diff --git a/src/ServiceBus.AttachmentPlugin.Tests/When_receiving_message.cs b/src/ServiceBus.AttachmentPlugin.Tests/When_receiving_message.cs index 8d76e27..d77f306 100644 --- a/src/ServiceBus.AttachmentPlugin.Tests/When_receiving_message.cs +++ b/src/ServiceBus.AttachmentPlugin.Tests/When_receiving_message.cs @@ -19,15 +19,17 @@ public async Task Should_throw_exception_with_blob_path_for_blob_that_cant_be_fo }; var sendingPlugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments")); + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + containerName: "attachments")); await sendingPlugin.BeforeMessageSend(message); var receivingPlugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments-wrong-containers")); + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + containerName: "attachments-wrong-containers")); var exception = await Assert.ThrowsAsync(() => receivingPlugin.AfterMessageReceive(message)); Assert.Contains("attachments-wrong-containers", actualString: exception.Message); Assert.Contains(message.UserProperties["$attachment.blob"].ToString(), actualString: exception.Message); } } -} +} \ No newline at end of file diff --git a/src/ServiceBus.AttachmentPlugin.Tests/When_registering_plugin.cs b/src/ServiceBus.AttachmentPlugin.Tests/When_registering_plugin.cs index 70beb70..310d552 100644 --- a/src/ServiceBus.AttachmentPlugin.Tests/When_registering_plugin.cs +++ b/src/ServiceBus.AttachmentPlugin.Tests/When_registering_plugin.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Microsoft.Azure.ServiceBus; using Microsoft.Azure.ServiceBus.Core; - using Microsoft.Azure.Storage.Auth; using Xunit; public class When_registering_plugin : IClassFixture @@ -31,7 +30,7 @@ public void Should_get_back_AzureStorageAttachment_for_container_sas_based_confi { IClientEntity client = new FakeClientEntity("fake", string.Empty, RetryPolicy.Default); - var azureStorageAttachmentConfiguration = new AzureStorageAttachmentConfiguration(new StorageCredentials("?sv=2018-03-28&sr=c&sig=5XxlRKoP4yEmibM2HhJlQuV7MG3rYgQXD89mLpNp%2F24%3D"), "http://127.0.0.1:10000/devstoreaccount1"); + var azureStorageAttachmentConfiguration = new AzureStorageAttachmentConfiguration("http://127.0.0.1:10000/devstoreaccount1?sv=2018-03-28&sr=c&sig=5XxlRKoP4yEmibM2HhJlQuV7MG3rYgQXD89mLpNp%2F24%3D"); var registeredPlugin = AzureStorageAttachmentExtensions.RegisterAzureStorageAttachmentPlugin(client, azureStorageAttachmentConfiguration); diff --git a/src/ServiceBus.AttachmentPlugin.Tests/When_sending_message_using_connection_string.cs b/src/ServiceBus.AttachmentPlugin.Tests/When_sending_message_using_connection_string.cs index db40e07..5be36cd 100644 --- a/src/ServiceBus.AttachmentPlugin.Tests/When_sending_message_using_connection_string.cs +++ b/src/ServiceBus.AttachmentPlugin.Tests/When_sending_message_using_connection_string.cs @@ -3,10 +3,9 @@ using System; using System.Text; using System.Threading.Tasks; + using Azure.Storage.Blobs; + using Azure.Storage.Blobs.Models; using Microsoft.Azure.ServiceBus; - using Microsoft.Azure.Storage; - using Microsoft.Azure.Storage.Auth; - using Microsoft.Azure.Storage.Blob; using Xunit; public class When_sending_message_using_connection_string : IClassFixture @@ -28,7 +27,8 @@ public async Task Should_nullify_body_when_body_should_be_sent_as_attachment() MessageId = Guid.NewGuid().ToString(), }; var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName:"attachments", messagePropertyToIdentifyAttachmentBlob:"attachment-id")); + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + messagePropertyToIdentifyAttachmentBlob:"attachment-id")); var result = await plugin.BeforeMessageSend(message); Assert.Null(result.Body); @@ -46,7 +46,8 @@ public async Task Should_leave_body_as_is_for_message_not_exceeding_max_size() TimeToLive = TimeSpan.FromHours(1) }; var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName:"attachments", messagePropertyToIdentifyAttachmentBlob:"attachment-id", + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + messagePropertyToIdentifyAttachmentBlob:"attachment-id", messageMaxSizeReachedCriteria:msg => msg.Body.Length > 100)); var result = await plugin.BeforeMessageSend(message); @@ -65,19 +66,18 @@ public async Task Should_set_valid_until_datetime_on_blob_same_as_message_TTL() TimeToLive = TimeSpan.FromHours(1) }; var dateTimeNowUtc = new DateTime(2017, 1, 2); - var configuration = new AzureStorageAttachmentConfiguration(connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName:"attachments", + var configuration = new AzureStorageAttachmentConfiguration( + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, messagePropertyToIdentifyAttachmentBlob:"attachment-id"); AzureStorageAttachment.DateTimeFunc = () => dateTimeNowUtc; var plugin = new AzureStorageAttachment(configuration); await plugin.BeforeMessageSend(message); - var account = CloudStorageAccount.Parse(await configuration.ConnectionStringProvider!.GetConnectionString()); - var client = account.CreateCloudBlobClient(); - var container = client.GetContainerReference(configuration.ContainerName); + var container = configuration.ContainerName; var blobName = (string)message.UserProperties[configuration.MessagePropertyToIdentifyAttachmentBlob]; - var blob = container.GetBlockBlobReference(blobName); - await blob.FetchAttributesAsync(); - var validUntil = blob.Metadata[AzureStorageAttachment.ValidUntilUtc]; + var blob = new BlobClient(connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, blobContainerName: container, blobName: blobName); + BlobProperties properties = await blob.GetPropertiesAsync(); + var validUntil = properties.Metadata[AzureStorageAttachment.ValidUntilUtc]; Assert.Equal(dateTimeNowUtc.Add(message.TimeToLive).ToString(AzureStorageAttachment.DateFormat), validUntil); } @@ -88,7 +88,8 @@ public async Task Should_receive_it_using_connection_string() var bytes = Encoding.UTF8.GetBytes(payload); var message = new Message(bytes); var configuration = new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments", messagePropertyToIdentifyAttachmentBlob: "attachment-id"); + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + messagePropertyToIdentifyAttachmentBlob: "attachment-id"); var plugin = new AzureStorageAttachment(configuration); await plugin.BeforeMessageSend(message); @@ -107,7 +108,8 @@ public async Task Should_not_reupload_blob_if_one_is_already_assigned() var bytes = Encoding.UTF8.GetBytes(payload); var message = new Message(bytes); var configuration = new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments", messagePropertyToIdentifyAttachmentBlob: "attachment-id"); + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + messagePropertyToIdentifyAttachmentBlob: "attachment-id"); var plugin = new AzureStorageAttachment(configuration); @@ -130,7 +132,8 @@ public async Task Should_not_set_sas_uri_by_default() MessageId = Guid.NewGuid().ToString(), }; var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments", messagePropertyToIdentifyAttachmentBlob: "attachment-id")); + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + messagePropertyToIdentifyAttachmentBlob: "attachment-id")); var result = await plugin.BeforeMessageSend(message); Assert.Null(result.Body); @@ -145,15 +148,16 @@ public async Task Should_be_able_to_receive_using_container_sas() var bytes = Encoding.UTF8.GetBytes(payload); var message = new Message(bytes); var configuration = new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments", messagePropertyToIdentifyAttachmentBlob: "attachment-id"); + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + messagePropertyToIdentifyAttachmentBlob: "attachment-id"); var plugin = new AzureStorageAttachment(configuration); await plugin.BeforeMessageSend(message); Assert.Null(message.Body); - var credentials = new StorageCredentials(await fixture.GetContainerSas("attachments")); - var receiveConfiguration = new AzureStorageAttachmentConfiguration(credentials, fixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob: "attachment-id"); + var credentials = await AzureStorageEmulatorFixture.GetContainerSas("attachments"); + var receiveConfiguration = new AzureStorageAttachmentConfiguration(credentials, messagePropertyToIdentifyAttachmentBlob: "attachment-id"); var receivePlugin = new AzureStorageAttachment(receiveConfiguration); @@ -171,7 +175,9 @@ public async Task Should_be_able_to_send_if_container_was_not_found() var bytes = Encoding.UTF8.GetBytes(payload); var message = new Message(bytes); var configuration = new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments-that-didnt-exist", messagePropertyToIdentifyAttachmentBlob: "attachment-id"); + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + containerName: "attachments-that-didnt-exist", + messagePropertyToIdentifyAttachmentBlob: "attachment-id"); var plugin = new AzureStorageAttachment(configuration); await plugin.BeforeMessageSend(message); diff --git a/src/ServiceBus.AttachmentPlugin.Tests/When_sending_message_using_container_sas.cs b/src/ServiceBus.AttachmentPlugin.Tests/When_sending_message_using_container_sas.cs index 2ee8d6e..6a34442 100644 --- a/src/ServiceBus.AttachmentPlugin.Tests/When_sending_message_using_container_sas.cs +++ b/src/ServiceBus.AttachmentPlugin.Tests/When_sending_message_using_container_sas.cs @@ -3,19 +3,18 @@ using System; using System.Text; using System.Threading.Tasks; + using Azure.Storage.Blobs; + using Azure.Storage.Blobs.Models; using Microsoft.Azure.ServiceBus; - using Microsoft.Azure.Storage; - using Microsoft.Azure.Storage.Auth; - using Microsoft.Azure.Storage.Blob; using Xunit; public class When_sending_message_using_container_sas : IClassFixture { - readonly AzureStorageEmulatorFixture fixture; + // readonly AzureStorageEmulatorFixture fixture; public When_sending_message_using_container_sas(AzureStorageEmulatorFixture fixture) { - this.fixture = fixture; + // this.fixture = fixture; } [Fact] @@ -27,8 +26,8 @@ public async Task Should_nullify_body_when_body_should_be_sent_as_attachment() { MessageId = Guid.NewGuid().ToString(), }; - var credentials = new StorageCredentials(await fixture.GetContainerSas("attachments")); - var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration(credentials, fixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob:"attachment-id")); + var credentials = await AzureStorageEmulatorFixture.GetContainerSas("attachments"); + var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration(credentials, AzureStorageEmulatorFixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob:"attachment-id")); var result = await plugin.BeforeMessageSend(message); Assert.Null(result.Body); @@ -45,8 +44,8 @@ public async Task Should_leave_body_as_is_for_message_not_exceeding_max_size() MessageId = Guid.NewGuid().ToString(), TimeToLive = TimeSpan.FromHours(1) }; - var credentials = new StorageCredentials(await fixture.GetContainerSas("attachments")); - var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration(credentials, "http://127.0.0.1:10000/devstoreaccount1", messagePropertyToIdentifyAttachmentBlob:"attachment -id", + var credentials = await AzureStorageEmulatorFixture.GetContainerSas("attachments"); + var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration(credentials, AzureStorageEmulatorFixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob:"attachment -id", messageMaxSizeReachedCriteria:msg => msg.Body.Length > 100)); var result = await plugin.BeforeMessageSend(message); @@ -64,20 +63,18 @@ public async Task Should_set_valid_until_datetime_on_blob_same_as_message_TTL() MessageId = Guid.NewGuid().ToString(), TimeToLive = TimeSpan.FromHours(1) }; - var credentials = new StorageCredentials(await fixture.GetContainerSas("attachments")); - var configuration = new AzureStorageAttachmentConfiguration(credentials, fixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob:"attachment-id"); + var credentials = await AzureStorageEmulatorFixture.GetContainerSas("attachments"); + var configuration = new AzureStorageAttachmentConfiguration(credentials, AzureStorageEmulatorFixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob:"attachment-id"); var dateTimeNowUtc = new DateTime(2017, 1, 2); AzureStorageAttachment.DateTimeFunc = () => dateTimeNowUtc; var plugin = new AzureStorageAttachment(configuration); await plugin.BeforeMessageSend(message); - var account = CloudStorageAccount.Parse(await AzureStorageEmulatorFixture.ConnectionStringProvider.GetConnectionString()); - var client = account.CreateCloudBlobClient(); - var container = client.GetContainerReference("attachments"); + var client = new BlobContainerClient(connectionString:AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, blobContainerName: "attachments"); var blobName = (string)message.UserProperties[configuration.MessagePropertyToIdentifyAttachmentBlob]; - var blob = container.GetBlockBlobReference(blobName); - await blob.FetchAttributesAsync(); - var validUntil = blob.Metadata[AzureStorageAttachment.ValidUntilUtc]; + var blob = client.GetBlobClient(blobName); + BlobProperties properties = await blob.GetPropertiesAsync(); + var validUntil = properties.Metadata[AzureStorageAttachment.ValidUntilUtc]; Assert.Equal(dateTimeNowUtc.Add(message.TimeToLive).ToString(AzureStorageAttachment.DateFormat), validUntil); } @@ -87,8 +84,8 @@ public async Task Should_receive_it_using_container_sas() var payload = "payload"; var bytes = Encoding.UTF8.GetBytes(payload); var message = new Message(bytes); - var credentials = new StorageCredentials(await fixture.GetContainerSas("attachments")); - var configuration = new AzureStorageAttachmentConfiguration(credentials, fixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob: "attachment-id"); + var credentials = await AzureStorageEmulatorFixture.GetContainerSas("attachments"); + var configuration = new AzureStorageAttachmentConfiguration(credentials, AzureStorageEmulatorFixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob: "attachment-id"); var plugin = new AzureStorageAttachment(configuration); await plugin.BeforeMessageSend(message); @@ -106,8 +103,8 @@ public async Task Should_not_reupload_blob_if_one_is_already_assigned() var payload = "payload"; var bytes = Encoding.UTF8.GetBytes(payload); var message = new Message(bytes); - var credentials = new StorageCredentials(await fixture.GetContainerSas("attachments")); - var configuration = new AzureStorageAttachmentConfiguration(credentials, fixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob: "attachment-id"); + var credentials = await AzureStorageEmulatorFixture.GetContainerSas("attachments"); + var configuration = new AzureStorageAttachmentConfiguration(credentials, AzureStorageEmulatorFixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob: "attachment-id"); var plugin = new AzureStorageAttachment(configuration); @@ -129,8 +126,8 @@ public async Task Should_not_set_embedded_sas_uri_by_default() { MessageId = Guid.NewGuid().ToString(), }; - var credentials = new StorageCredentials(await fixture.GetContainerSas("attachments")); - var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration(credentials, fixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob: "attachment-id")); + var credentials = await AzureStorageEmulatorFixture.GetContainerSas("attachments"); + var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration(credentials, AzureStorageEmulatorFixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob: "attachment-id")); var result = await plugin.BeforeMessageSend(message); Assert.Null(result.Body); @@ -144,8 +141,8 @@ public async Task Should_be_able_to_receive_using_storage_connection_string() var payload = "payload"; var bytes = Encoding.UTF8.GetBytes(payload); var message = new Message(bytes); - var credentials = new StorageCredentials(await fixture.GetContainerSas("attachments")); - var configuration = new AzureStorageAttachmentConfiguration(credentials, fixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob: "attachment-id"); + var credentials = await AzureStorageEmulatorFixture.GetContainerSas("attachments"); + var configuration = new AzureStorageAttachmentConfiguration(credentials, AzureStorageEmulatorFixture.GetBlobEndpoint(), messagePropertyToIdentifyAttachmentBlob: "attachment-id"); var plugin = new AzureStorageAttachment(configuration); await plugin.BeforeMessageSend(message); @@ -153,7 +150,7 @@ public async Task Should_be_able_to_receive_using_storage_connection_string() Assert.Null(message.Body); var receivePlugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments", messagePropertyToIdentifyAttachmentBlob: "attachment-id")); + connectionString: await AzureStorageEmulatorFixture.GetContainerSas("attachments"), messagePropertyToIdentifyAttachmentBlob: "attachment-id")); var receivedMessage = await receivePlugin.AfterMessageReceive(message); diff --git a/src/ServiceBus.AttachmentPlugin.Tests/When_sending_message_with_embedded_sas_uri.cs b/src/ServiceBus.AttachmentPlugin.Tests/When_sending_message_with_embedded_sas_uri.cs index 924a49d..c51dd00 100644 --- a/src/ServiceBus.AttachmentPlugin.Tests/When_sending_message_with_embedded_sas_uri.cs +++ b/src/ServiceBus.AttachmentPlugin.Tests/When_sending_message_with_embedded_sas_uri.cs @@ -18,7 +18,7 @@ public async Task Should_set_sas_uri_when_specified() MessageId = Guid.NewGuid().ToString(), }; var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments", messagePropertyToIdentifyAttachmentBlob: "attachment-id") + connectionString: await AzureStorageEmulatorFixture.GetContainerSas("attachments"), messagePropertyToIdentifyAttachmentBlob: "attachment-id") .WithBlobSasUri(sasTokenValidationTime: TimeSpan.FromHours(4), messagePropertyToIdentifySasUri: "mySasUriProperty")); var result = await plugin.BeforeMessageSend(message); diff --git a/src/ServiceBus.AttachmentPlugin.Tests/When_using_message_extensions.cs b/src/ServiceBus.AttachmentPlugin.Tests/When_using_message_extensions.cs index 810ad3b..af7d373 100644 --- a/src/ServiceBus.AttachmentPlugin.Tests/When_using_message_extensions.cs +++ b/src/ServiceBus.AttachmentPlugin.Tests/When_using_message_extensions.cs @@ -23,7 +23,8 @@ public async Task Should_send_and_receive_with_configuration() var bytes = Encoding.UTF8.GetBytes(payload); var message = new Message(bytes); var configuration = new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments", messagePropertyToIdentifyAttachmentBlob: "attachment-id"); + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + messagePropertyToIdentifyAttachmentBlob: "attachment-id"); await message.UploadAzureStorageAttachment(configuration); @@ -41,7 +42,8 @@ public async Task Should_send_and_receive_with_default_sas_uri_property() var bytes = Encoding.UTF8.GetBytes(payload); var message = new Message(bytes); var configuration = new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments", messagePropertyToIdentifyAttachmentBlob: "attachment-id") + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + messagePropertyToIdentifyAttachmentBlob: "attachment-id") .WithBlobSasUri(); await message.UploadAzureStorageAttachment(configuration); @@ -61,7 +63,8 @@ public async Task Should_send_and_receive_with_custom_sas_uri_property() var message = new Message(bytes); var customSasUri = "$custom-attachment.sas.uri"; var configuration = new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments", messagePropertyToIdentifyAttachmentBlob: "attachment-id") + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + messagePropertyToIdentifyAttachmentBlob: "attachment-id") .WithBlobSasUri(customSasUri); await message.UploadAzureStorageAttachment(configuration); @@ -80,7 +83,8 @@ public async Task Should_be_able_to_override_blob_name_and_receive_message_paylo var bytes = Encoding.UTF8.GetBytes(payload); var message = new Message(bytes) { MessageId = Guid.NewGuid().ToString("N") }; var configuration = new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider); + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + messagePropertyToIdentifyAttachmentBlob: "attachment-id"); configuration.OverrideBlobName(msg => $"test/{msg.MessageId}"); @@ -104,7 +108,8 @@ public async Task Should_set_body_to_the_value_provided_by_body_replacer_overrid MessageId = Guid.NewGuid().ToString(), }; var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments", messagePropertyToIdentifyAttachmentBlob: "attachment-id") + connectionString: AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + messagePropertyToIdentifyAttachmentBlob: "attachment-id") .OverrideBody(msg => Array.Empty())); var result = await plugin.BeforeMessageSend(message); @@ -122,7 +127,8 @@ public async Task Should_set_body_to_null_if_body_replacer_override_is_not_provi MessageId = Guid.NewGuid().ToString(), }; var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, containerName: "attachments", messagePropertyToIdentifyAttachmentBlob: "attachment-id")); + AzureStorageEmulatorFixture.TestingStorageAccountConnectionString, + messagePropertyToIdentifyAttachmentBlob: "attachment-id")); var result = await plugin.BeforeMessageSend(message); Assert.Null(result.Body); diff --git a/src/ServiceBus.AttachmentPlugin.Tests/When_using_receive_only_plugin.cs b/src/ServiceBus.AttachmentPlugin.Tests/When_using_receive_only_plugin.cs index 63c2f27..9896738 100644 --- a/src/ServiceBus.AttachmentPlugin.Tests/When_using_receive_only_plugin.cs +++ b/src/ServiceBus.AttachmentPlugin.Tests/When_using_receive_only_plugin.cs @@ -29,10 +29,9 @@ public async Task Should_download_attachment_using_provided_blob_sas_uri() MessageId = Guid.NewGuid().ToString(), }; var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration( - connectionStringProvider: AzureStorageEmulatorFixture.ConnectionStringProvider, + connectionString: await AzureStorageEmulatorFixture.GetContainerSas("attachments"), containerName: "attachments-sendonly", - messagePropertyToIdentifyAttachmentBlob: - "attachment-id") + messagePropertyToIdentifyAttachmentBlob: "attachment-id") .WithBlobSasUri( sasTokenValidationTime: TimeSpan.FromHours(4), messagePropertyToIdentifySasUri: "mySasUriProperty")); diff --git a/src/ServiceBus.AttachmentPlugin/AzureStorageAttachment.cs b/src/ServiceBus.AttachmentPlugin/AzureStorageAttachment.cs index 61c69c4..e6d70ea 100644 --- a/src/ServiceBus.AttachmentPlugin/AzureStorageAttachment.cs +++ b/src/ServiceBus.AttachmentPlugin/AzureStorageAttachment.cs @@ -2,11 +2,13 @@ { using System; using System.Collections.Generic; + using System.IO; using System.Threading.Tasks; + using Azure; + using Azure.Storage.Blobs; + using Azure.Storage.Blobs.Specialized; using Microsoft.Azure.ServiceBus; using Microsoft.Azure.ServiceBus.Core; - using Microsoft.Azure.Storage; - using Microsoft.Azure.Storage.Blob; class AzureStorageAttachment : ServiceBusPlugin { @@ -41,7 +43,7 @@ public override async Task BeforeMessageSend(Message message) } var containerUri = new Uri($"{configuration.BlobEndpoint}{configuration.ContainerName}"); - var container = new CloudBlobContainer(containerUri, configuration.StorageCredentials); + var container = new BlobContainerClient(containerUri, configuration.StorageSharedKeyCredentials); try { @@ -51,19 +53,21 @@ public override async Task BeforeMessageSend(Message message) await container.CreateIfNotExistsAsync().ConfigureAwait(false); } } - catch (StorageException) + catch (RequestFailedException) { // swallow in case a container SAS is used } var blobName = configuration.BlobNameResolver(message); var blobUri = new Uri($"{containerUri}/{blobName}"); - var blob = new CloudBlockBlob(blobUri, configuration.StorageCredentials); + var blob = new BlockBlobClient(blobUri, configuration.StorageSharedKeyCredentials); - SetValidMessageId(blob, message.MessageId); - SetValidUntil(blob, message.TimeToLive); + var metadata = new Dictionary(); + SetValidMessageId(metadata, message.MessageId); + SetValidUntil(metadata, message.TimeToLive); - await blob.UploadFromByteArrayAsync(message.Body, 0, message.Body.Length).ConfigureAwait(false); + using var memory = new MemoryStream(message.Body); + await blob.UploadAsync(memory, metadata:metadata).ConfigureAwait(false); message.Body = configuration.BodyReplacer(message); message.UserProperties[configuration.MessagePropertyToIdentifyAttachmentBlob] = blob.Name; @@ -83,15 +87,15 @@ public override async Task BeforeMessageSend(Message message) bool AttachmentBlobAssociated(IDictionary messageUserProperties) => messageUserProperties.TryGetValue(configuration.MessagePropertyToIdentifyAttachmentBlob, out var _); - static void SetValidMessageId(ICloudBlob blob, string messageId) + static void SetValidMessageId(Dictionary metadata, string messageId) { if (!string.IsNullOrWhiteSpace(messageId)) { - blob.Metadata[MessageId] = messageId; + metadata[MessageId] = messageId; } } - static void SetValidUntil(ICloudBlob blob, TimeSpan timeToBeReceived) + static void SetValidUntil(Dictionary metadata, TimeSpan timeToBeReceived) { if (timeToBeReceived == TimeSpan.MaxValue) { @@ -99,7 +103,7 @@ static void SetValidUntil(ICloudBlob blob, TimeSpan timeToBeReceived) } var validUntil = DateTimeFunc().Add(timeToBeReceived); - blob.Metadata[ValidUntilUtc] = validUntil.ToString(DateFormat); + metadata[ValidUntilUtc] = validUntil.ToString(DateFormat); } public override async Task AfterMessageReceive(Message message) @@ -115,34 +119,32 @@ public override async Task AfterMessageReceive(Message message) try { - await blob.FetchAttributesAsync().ConfigureAwait(false); + using var memory = new MemoryStream(); + await blob.DownloadToAsync(memory).ConfigureAwait(false); + message.Body = memory.ToArray(); + return message; } - catch (StorageException exception) + catch (RequestFailedException exception) { - throw new Exception($"Blob with name '{blob.Name}' under container '{blob.Container.Name}' cannot be found." + throw new Exception($"Blob with name '{blob.Name}' under container '{blob.BlobContainerName}' cannot be found." + $" Check {nameof(AzureStorageAttachmentConfiguration)}.{nameof(AzureStorageAttachmentConfiguration.ContainerName)} or" + $" {nameof(AzureStorageAttachmentConfiguration)}.{nameof(AzureStorageAttachmentConfiguration.MessagePropertyToIdentifyAttachmentBlob)} for correct values.", exception); } - var fileByteLength = blob.Properties.Length; - var bytes = new byte[fileByteLength]; - await blob.DownloadToByteArrayAsync(bytes, 0).ConfigureAwait(false); - message.Body = bytes; - return message; } - CloudBlockBlob BuildBlob(IDictionary userProperties, object blobNameObject) + BlockBlobClient BuildBlob(IDictionary userProperties, object blobNameObject) { if (configuration.MessagePropertyForBlobSasUri != null) { if (userProperties.TryGetValue(configuration.MessagePropertyForBlobSasUri, out var propertyForBlobSasUri)) { - return new CloudBlockBlob(new Uri((string)propertyForBlobSasUri)); + return new BlockBlobClient(new Uri((string)propertyForBlobSasUri)); } } var blobName = (string) blobNameObject; var blobUri = new Uri($"{configuration.BlobEndpoint}{configuration.ContainerName}/{blobName}"); - return new CloudBlockBlob(blobUri, configuration.StorageCredentials); + return new BlockBlobClient(blobUri, configuration.StorageSharedKeyCredentials); } } } diff --git a/src/ServiceBus.AttachmentPlugin/AzureStorageAttachmentConfiguration.cs b/src/ServiceBus.AttachmentPlugin/AzureStorageAttachmentConfiguration.cs index 8f176f4..615f37a 100644 --- a/src/ServiceBus.AttachmentPlugin/AzureStorageAttachmentConfiguration.cs +++ b/src/ServiceBus.AttachmentPlugin/AzureStorageAttachmentConfiguration.cs @@ -1,8 +1,8 @@ namespace Microsoft.Azure.ServiceBus { using System; - using Storage; - using Storage.Auth; + using global::Azure.Core; + using global::Azure.Storage; /// Runtime configuration for Azure Storage Attachment plugin. public class AzureStorageAttachmentConfiguration @@ -17,41 +17,52 @@ public AzureStorageAttachmentConfiguration( string containerName = AzureStorageAttachmentConfigurationConstants.DefaultContainerName, string messagePropertyToIdentifyAttachmentBlob = AzureStorageAttachmentConfigurationConstants.DefaultMessagePropertyToIdentifyAttachmentBlob, Func? messageMaxSizeReachedCriteria = default) - : this(new PlainTextConnectionStringProvider(connectionString), containerName, messagePropertyToIdentifyAttachmentBlob, messageMaxSizeReachedCriteria) { - } + Guard.AgainstNull(nameof(connectionString), connectionString); + Guard.AgainstEmpty(nameof(containerName), containerName); + Guard.AgainstEmpty(nameof(messagePropertyToIdentifyAttachmentBlob), messagePropertyToIdentifyAttachmentBlob); + + ContainerName = containerName; + MessagePropertyToIdentifyAttachmentBlob = messagePropertyToIdentifyAttachmentBlob; + MessageMaxSizeReachedCriteria = GetMessageMaxSizeReachedCriteria(messageMaxSizeReachedCriteria); + var storageConnectionString = ReflectedAzureStorageConnectionString.Create(connectionString); + StorageSharedKeyCredentials = storageConnectionString.Credentials; + BlobEndpoint = EnsureBlobEndpointEndsWithSlash(storageConnectionString.BlobEndpoint); + } + /// Constructor to create new configuration object. /// Container name is not required as it's included in the SharedAccessSignature. - /// + /// /// Blob endpoint in the format of "https://account.blob.core.windows.net/". For the emulator the value is "http://127.0.0.1:10000/devstoreaccount1". /// /// /// Default is always use attachments public AzureStorageAttachmentConfiguration( - StorageCredentials storageCredentials, + StorageSharedKeyCredential storageSharedKeyCredentials, string blobEndpoint, string containerName = AzureStorageAttachmentConfigurationConstants.DefaultContainerName, string messagePropertyToIdentifyAttachmentBlob = AzureStorageAttachmentConfigurationConstants.DefaultMessagePropertyToIdentifyAttachmentBlob, Func? messageMaxSizeReachedCriteria = default) { - Guard.AgainstNull(nameof(storageCredentials), storageCredentials); + Guard.AgainstNull(nameof(storageSharedKeyCredentials), storageSharedKeyCredentials); Guard.AgainstEmpty(nameof(blobEndpoint), blobEndpoint); Guard.AgainstEmpty(nameof(containerName), containerName); Guard.AgainstEmpty(nameof(messagePropertyToIdentifyAttachmentBlob), messagePropertyToIdentifyAttachmentBlob); - StorageCredentials = storageCredentials; - BlobEndpoint = EnsureBlobEndpointEndsWithSlash(blobEndpoint); + StorageSharedKeyCredentials = storageSharedKeyCredentials; + // TODO: figure out + BlobEndpoint = EnsureBlobEndpointEndsWithSlash(new Uri(blobEndpoint)); ContainerName = containerName; MessagePropertyToIdentifyAttachmentBlob = messagePropertyToIdentifyAttachmentBlob; MessageMaxSizeReachedCriteria = GetMessageMaxSizeReachedCriteria(messageMaxSizeReachedCriteria); } - static Uri EnsureBlobEndpointEndsWithSlash(string blobEndpoint) + static Uri EnsureBlobEndpointEndsWithSlash(Uri blobEndpoint) { - if (blobEndpoint.EndsWith("/", StringComparison.OrdinalIgnoreCase)) + if (blobEndpoint.Segments[^1].Equals("/", StringComparison.OrdinalIgnoreCase)) { - return new Uri(blobEndpoint); + return blobEndpoint; } // Emulator blob endpoint doesn't end with slash @@ -69,19 +80,20 @@ public AzureStorageAttachmentConfiguration( string messagePropertyToIdentifyAttachmentBlob = AzureStorageAttachmentConfigurationConstants.DefaultMessagePropertyToIdentifyAttachmentBlob, Func? messageMaxSizeReachedCriteria = default) { - Guard.AgainstNull(nameof(connectionStringProvider), connectionStringProvider); - Guard.AgainstEmpty(nameof(containerName), containerName); - Guard.AgainstEmpty(nameof(messagePropertyToIdentifyAttachmentBlob), messagePropertyToIdentifyAttachmentBlob); - - var connectionString = connectionStringProvider.GetConnectionString().GetAwaiter().GetResult(); - var account = CloudStorageAccount.Parse(connectionString); - - ConnectionStringProvider = connectionStringProvider; - StorageCredentials = account.Credentials; - BlobEndpoint = EnsureBlobEndpointEndsWithSlash(account.BlobEndpoint.ToString()); - ContainerName = containerName; - MessagePropertyToIdentifyAttachmentBlob = messagePropertyToIdentifyAttachmentBlob; - MessageMaxSizeReachedCriteria = GetMessageMaxSizeReachedCriteria(messageMaxSizeReachedCriteria); + throw new NotImplementedException(); + // Guard.AgainstNull(nameof(connectionStringProvider), connectionStringProvider); + // Guard.AgainstEmpty(nameof(containerName), containerName); + // Guard.AgainstEmpty(nameof(messagePropertyToIdentifyAttachmentBlob), messagePropertyToIdentifyAttachmentBlob); + // + // var connectionString = connectionStringProvider.GetConnectionString().GetAwaiter().GetResult(); + // var account = CloudStorageAccount.Parse(connectionString); + // + // ConnectionStringProvider = connectionStringProvider; + // StorageSharedKeyCredentials = account.Credentials; + // BlobEndpoint = EnsureBlobEndpointEndsWithSlash(account.BlobEndpoint.ToString()); + // ContainerName = containerName; + // MessagePropertyToIdentifyAttachmentBlob = messagePropertyToIdentifyAttachmentBlob; + // MessageMaxSizeReachedCriteria = GetMessageMaxSizeReachedCriteria(messageMaxSizeReachedCriteria); } Func GetMessageMaxSizeReachedCriteria(Func? messageMaxSizeReachedCriteria) @@ -103,26 +115,28 @@ Func GetMessageMaxSizeReachedCriteria(Func? messag }; } - internal IProvideStorageConnectionString? ConnectionStringProvider { get; } - + //////////////////// + internal Uri? BlobEndpoint { get; } + internal string ContainerName { get; } + + internal StorageSharedKeyCredential? StorageSharedKeyCredentials { get; } + // or + internal TokenCredential? TokenCredential { get; } + + internal Func BlobNameResolver { get; set; } = message => Guid.NewGuid().ToString(); - internal string? MessagePropertyForBlobSasUri { get; set; } - - internal TimeSpan? BlobSasTokenValidationTime { get; set; } - + internal Func BodyReplacer { get; set; } = message => null; + internal string MessagePropertyToIdentifyAttachmentBlob { get; } internal Func MessageMaxSizeReachedCriteria { get; } + + //////?? + internal string? MessagePropertyForBlobSasUri { get; set; } - internal StorageCredentials StorageCredentials { get; } - - internal bool UsingSas => StorageCredentials.IsSAS; - - internal Uri BlobEndpoint { get; } - - internal Func BlobNameResolver { get; set; } = message => Guid.NewGuid().ToString(); + internal TimeSpan? BlobSasTokenValidationTime { get; set; } - internal Func BodyReplacer { get; set; } = message => null; + internal bool UsingSas { get; } = false; } } \ No newline at end of file diff --git a/src/ServiceBus.AttachmentPlugin/AzureStorageAttachmentConfigurationExtensions.cs b/src/ServiceBus.AttachmentPlugin/AzureStorageAttachmentConfigurationExtensions.cs index 7719969..4f4786e 100644 --- a/src/ServiceBus.AttachmentPlugin/AzureStorageAttachmentConfigurationExtensions.cs +++ b/src/ServiceBus.AttachmentPlugin/AzureStorageAttachmentConfigurationExtensions.cs @@ -25,16 +25,16 @@ public static AzureStorageAttachmentConfiguration WithBlobSasUri( { throw new Exception("Invalid configuration: .WithBlobSasUri() requires account shared key and cannot be used with service/container Shared Access Signature."); } - + if (sasTokenValidationTime == null) { sasTokenValidationTime = DefaultSasTokenValidationTime; } Guard.AgainstNegativeOrZeroTimeSpan(nameof(sasTokenValidationTime), sasTokenValidationTime); - + azureStorageAttachmentConfiguration.MessagePropertyForBlobSasUri = messagePropertyToIdentifySasUri; azureStorageAttachmentConfiguration.BlobSasTokenValidationTime = sasTokenValidationTime.Value; - + return azureStorageAttachmentConfiguration; } diff --git a/src/ServiceBus.AttachmentPlugin/ReceiveOnlyAzureStorageAttachment.cs b/src/ServiceBus.AttachmentPlugin/ReceiveOnlyAzureStorageAttachment.cs index e7c1e59..e2bd0ed 100644 --- a/src/ServiceBus.AttachmentPlugin/ReceiveOnlyAzureStorageAttachment.cs +++ b/src/ServiceBus.AttachmentPlugin/ReceiveOnlyAzureStorageAttachment.cs @@ -1,11 +1,12 @@ namespace ServiceBus.AttachmentPlugin { using System; + using System.IO; using System.Threading.Tasks; + using Azure; + using Azure.Storage.Blobs.Specialized; using Microsoft.Azure.ServiceBus; using Microsoft.Azure.ServiceBus.Core; - using Microsoft.Azure.Storage; - using Microsoft.Azure.Storage.Blob; class ReceiveOnlyAzureStorageAttachment : ServiceBusPlugin { @@ -28,19 +29,20 @@ public override async Task AfterMessageReceive(Message message) return message; } - var blob = new CloudBlockBlob(new Uri(userProperties[messagePropertyToIdentifySasUri].ToString())); + var blob = new BlockBlobClient(new Uri(userProperties[messagePropertyToIdentifySasUri].ToString() + ?? throw new Exception($"Value of {nameof(messagePropertyToIdentifySasUri)} `{messagePropertyToIdentifySasUri}` was null."))); try { - await blob.FetchAttributesAsync().ConfigureAwait(false); + await blob.GetPropertiesAsync().ConfigureAwait(false); } - catch (StorageException exception) + catch (RequestFailedException exception) { - throw new Exception($"Blob with name '{blob.Name}' under container '{blob.Container.Name}' cannot be found.", exception); + throw new Exception($"Blob with name '{blob.Name}' under container '{blob.BlobContainerName}' cannot be found.", exception); } - var fileByteLength = blob.Properties.Length; - var bytes = new byte[fileByteLength]; - await blob.DownloadToByteArrayAsync(bytes, 0).ConfigureAwait(false); - message.Body = bytes; + + await using var memory = new MemoryStream(); + await blob.DownloadToAsync(memory).ConfigureAwait(false); + message.Body = memory.ToArray(); return message; } } diff --git a/src/ServiceBus.AttachmentPlugin/ReflectedAzureStorageConnectionString.cs b/src/ServiceBus.AttachmentPlugin/ReflectedAzureStorageConnectionString.cs new file mode 100644 index 0000000..cd7fd8a --- /dev/null +++ b/src/ServiceBus.AttachmentPlugin/ReflectedAzureStorageConnectionString.cs @@ -0,0 +1,47 @@ +namespace Microsoft.Azure.ServiceBus +{ + using System; + using global::Azure.Storage; + + internal class ReflectedAzureStorageConnectionString + { + static Type storageConnectionStringType = Type.GetType("Azure.Storage.StorageConnectionString, Azure.Storage.Common") ?? throw new Exception("`Azure.Storage.StorageConnectionString, Azure.Storage.Common` is not found"); + object storageConnectionStringObject; + + public static ReflectedAzureStorageConnectionString Create(string connectionString) + { + var storageConnectionStringObject = storageConnectionStringType! + .GetMethod("Parse", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)! + .Invoke(null, new object[] { connectionString }); + + if (storageConnectionStringObject is null) + { + throw new Exception($"Failed to initialize {nameof(ReflectedAzureStorageConnectionString)}."); + } + + return new ReflectedAzureStorageConnectionString(storageConnectionStringObject!); + } + + public StorageSharedKeyCredential Credentials => Get("Credentials"); + public string EndpointSuffix => Get("EndpointSuffix"); + public Uri BlobEndpoint => Get("BlobEndpoint"); + public bool IsDevStoreAccount => Get("IsDevStoreAccount"); + public (Uri primary, Uri secondary) BlobStorageUri => Get<(Uri, Uri)>("BlobStorageUri"); + + ReflectedAzureStorageConnectionString(object storageConnectionStringObject) + { + this.storageConnectionStringObject = storageConnectionStringObject; + } + + T Get(string propertyName, bool isPublic = false) + { + var propertyInfo = storageConnectionStringType.GetProperty(propertyName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic); + if (propertyInfo is null) + { + throw new Exception($"{storageConnectionStringType.FullName} does not contain a property '{propertyName}'."); + } + + return (T)propertyInfo.GetValue(storageConnectionStringObject)!; + } + } +} \ No newline at end of file diff --git a/src/ServiceBus.AttachmentPlugin/ServiceBus.AttachmentPlugin.csproj b/src/ServiceBus.AttachmentPlugin/ServiceBus.AttachmentPlugin.csproj index e7ce3e3..04b797a 100644 --- a/src/ServiceBus.AttachmentPlugin/ServiceBus.AttachmentPlugin.csproj +++ b/src/ServiceBus.AttachmentPlugin/ServiceBus.AttachmentPlugin.csproj @@ -4,7 +4,7 @@ Microsoft Azure ServiceBus attachment plugin 6.2.0 Sean Feldman - netstandard2.0;net461 + netcoreapp3.1 Azure;Service Bus;ServiceBus;.NET;AMQP;IoT;Queue;Topic;Attachment;Plugin project-icon.png LICENSE.md @@ -31,7 +31,8 @@ - + + diff --git a/src/ServiceBus.AttachmentPlugin/TokenGenerator.cs b/src/ServiceBus.AttachmentPlugin/TokenGenerator.cs index 843454b..cc6b136 100644 --- a/src/ServiceBus.AttachmentPlugin/TokenGenerator.cs +++ b/src/ServiceBus.AttachmentPlugin/TokenGenerator.cs @@ -1,27 +1,30 @@ namespace ServiceBus.AttachmentPlugin { using System; - using Microsoft.Azure.Storage.Blob; + using Azure.Storage.Blobs.Specialized; static class TokenGenerator { - internal static string GetBlobSasUri(CloudBlockBlob blob, TimeSpan timeSpan) + internal static string GetBlobSasUri(BlockBlobClient blob, TimeSpan timeSpan) { - //Set the expiry time and permissions for the blob. - //In this case the start time is specified as a few minutes in the past, to mitigate clock skew. - //The shared access signature will be valid immediately. - var now = DateTime.UtcNow; - var sasConstraints = new SharedAccessBlobPolicy - { - SharedAccessStartTime = now.AddMinutes(-5), - SharedAccessExpiryTime = now.Add(timeSpan), - Permissions = SharedAccessBlobPermissions.Delete | SharedAccessBlobPermissions.Read - }; - //Generate the shared access signature on the blob, setting the constraints directly on the signature. - var sasBlobToken = blob.GetSharedAccessSignature(sasConstraints); - - //Return the URI string for the container, including the SAS token. - return blob.Uri + sasBlobToken; + // TODO: review https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-user-delegation-sas-create-dotnet + + throw new NotImplementedException(); + // //Set the expiry time and permissions for the blob. + // //In this case the start time is specified as a few minutes in the past, to mitigate clock skew. + // //The shared access signature will be valid immediately. + // var now = DateTime.UtcNow; + // var sasConstraints = new SharedAccessBlobPolicy + // { + // SharedAccessStartTime = now.AddMinutes(-5), + // SharedAccessExpiryTime = now.Add(timeSpan), + // Permissions = SharedAccessBlobPermissions.Delete | SharedAccessBlobPermissions.Read + // }; + // //Generate the shared access signature on the blob, setting the constraints directly on the signature. + // var sasBlobToken = blob.GetSharedAccessSignature(sasConstraints); + // + // //Return the URI string for the container, including the SAS token. + // return blob.Uri + sasBlobToken; } } } \ No newline at end of file