Skip to content

Commit

Permalink
Merge pull request #28 from SeanFeldman/release-2.1.0
Browse files Browse the repository at this point in the history
Release 2.1.0
  • Loading branch information
SeanFeldman authored Nov 27, 2017
2 parents 0a50370 + 6b2ab1f commit 55702c8
Show file tree
Hide file tree
Showing 15 changed files with 134 additions and 30 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ var msg = await receiver.ReceiveAsync().ConfigureAwait(false);
// msg will contain the original payload
```

Receiving only mode (w/o Storage account credentials)

```c#
// Overide message property used to identify SAS URI
// .RegisterAzureStorageAttachmentPluginForReceivingOnly() is using "$attachment.sas.uri" by default
var receiver = messageReceiver.RegisterAzureStorageAttachmentPluginForReceivingOnly("mySasUriProperty");
var msg = await receiver.ReceiveAsync().ConfigureAwait(false);
```


### Configure blob container name

Expand Down
3 changes: 0 additions & 3 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ before_build:
# build configuration #
#---------------------------------#

# build platform, i.e. x86, x64, Any CPU. This setting is optional.
platform: Any CPU

# build Configuration, i.e. Debug, Release, etc.
configuration: Release

Expand Down
7 changes: 7 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<LangVersion>latest</LangVersion>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
namespace ServiceBus.AttachmentPlugin.Tests
{
using System;
using System.Threading;

public class AzureStorageEmulatorFixture : IDisposable
public class AzureStorageEmulatorFixture
{
public AzureStorageEmulatorFixture()
{
Expand All @@ -12,9 +11,5 @@ public AzureStorageEmulatorFixture()
// Microsoft.WindowsAzure.Storage.StorageException : Unable to connect to the remote server
Thread.Sleep(1000);
}

public void Dispose()
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20171031-01" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.0-beta2-build3683" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public async Task Should_receive_it()
}

[Fact]
public async Task Shoud_not_set_sas_uri_by_default()
public async Task Should_not_set_sas_uri_by_default()
{
var payload = "payload";
var bytes = Encoding.UTF8.GetBytes(payload);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

namespace ServiceBus.AttachmentPlugin.Tests
{
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.ServiceBus;
using Microsoft.Azure.ServiceBus.Core;
using Xunit;

public class When_using_receive_only_plugin : IClassFixture<AzureStorageEmulatorFixture>
{
[Fact]
public async Task Should_download_attachment_using_provided_from_sas_uri()
{
var payload = "payload";
var bytes = Encoding.UTF8.GetBytes(payload);
var message = new Message(bytes)
{
MessageId = Guid.NewGuid().ToString(),
};
var plugin = new AzureStorageAttachment(new AzureStorageAttachmentConfiguration(
connectionString: "UseDevelopmentStorage=true",
containerName: "attachments",
messagePropertyToIdentifyAttachmentBlob:
"attachment-id")
.WithSasUri(
sasTokenValidationTime: TimeSpan.FromHours(4),
messagePropertyToIdentifySasUri: "mySasUriProperty"));
await plugin.BeforeMessageSend(message);

var messageReceiver = new MessageReceiver(new ServiceBusConnectionStringBuilder(
endpoint: "sb://test.servicebus.windows.net/",
entityPath: "entity",
sharedAccessKey: "---",
sharedAccessKeyName: "RootManageSharedAccessKey"));
messageReceiver.RegisterAzureStorageAttachmentPluginForReceivingOnly("mySasUriProperty");
var receiveOnlyPlugin = messageReceiver.RegisteredPlugins[0];
var result = await receiveOnlyPlugin.AfterMessageReceive(message);

Assert.True(message.UserProperties.ContainsKey("mySasUriProperty"));
Assert.Equal(payload, Encoding.UTF8.GetString(result.Body));
}
}
}
1 change: 1 addition & 0 deletions src/ServiceBus.AttachmentPlugin.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002A_005C_002APackages_005C_002A_002A_005C_002A_002E_002A/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=3D880FCA_002DD2DA_002D4AB9_002D8017_002DBA8B7C86D359_002Fd_003AApp_005FPackages/@EntryIndexedValue">ExplicitlyExcluded</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/AnalysisEnabled/@EntryValue">SOLUTION</s:String>
<s:Boolean x:Key="/Default/CodeInspection/Highlighting/IdentifierHighlightingEnabled/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeTypeMemberModifiers/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeTypeModifiers/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AssignToImplicitGlobalInFunctionScope/@EntryIndexedValue">DO_NOT_SHOW</s:String>
Expand Down
8 changes: 4 additions & 4 deletions src/ServiceBus.AttachmentPlugin/AzureStorageAttachment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ public override async Task<Message> BeforeMessageSend(Message message)
var container = client.Value.GetContainerReference(configuration.ContainerName);
await container.CreateIfNotExistsAsync().ConfigureAwait(false);
var blob = container.GetBlockBlobReference(Guid.NewGuid().ToString());

SetValidMessageId(blob, message.MessageId);
SetValidUntil(blob, message.TimeToLive);

await blob.UploadFromByteArrayAsync(message.Body,0, message.Body.Length).ConfigureAwait(false);

message.Body = null;
Expand Down Expand Up @@ -105,8 +105,8 @@ public override async Task<Message> AfterMessageReceive(Message message)
}
catch (StorageException exception)
{
throw new Exception($"Blob with name '{blob.Name}' under container '{blob.Container.Name}' cannot be found."
+ $" Check {nameof(AzureStorageAttachmentConfiguration)}.{nameof(AzureStorageAttachmentConfiguration.ContainerName)} or"
throw new Exception($"Blob with name '{blob.Name}' under container '{blob.Container.Name}' cannot be found."
+ $" Check {nameof(AzureStorageAttachmentConfiguration)}.{nameof(AzureStorageAttachmentConfiguration.ContainerName)} or"
+ $" {nameof(AzureStorageAttachmentConfiguration)}.{nameof(AzureStorageAttachmentConfiguration.MessagePropertyToIdentifyAttachmentBlob)} for correct values.", exception);
}
var fileByteLength = blob.Properties.Length;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ public class AzureStorageAttachmentConfiguration
/// <param name="containerName"></param>
/// <param name="messagePropertyToIdentifyAttachmentBlob"></param>
/// <param name="messageMaxSizeReachedCriteria">Default is always use attachments</param>
public AzureStorageAttachmentConfiguration(string connectionString,
public AzureStorageAttachmentConfiguration(
string connectionString,
string containerName = "attachments",
string messagePropertyToIdentifyAttachmentBlob = "$attachment.blob",

Func<Message, bool> messageMaxSizeReachedCriteria = null)
{
Guard.AgainstEmpty(nameof(containerName), containerName);
Expand All @@ -24,7 +24,7 @@ public AzureStorageAttachmentConfiguration(string connectionString,
MessagePropertyToIdentifyAttachmentBlob = messagePropertyToIdentifyAttachmentBlob;
MessageMaxSizeReachedCriteria = GetMessageMaxSizeReachedCriteria(messageMaxSizeReachedCriteria);
}

Func<Message, bool> GetMessageMaxSizeReachedCriteria(Func<Message, bool> messageMaxSizeReachedCriteria)
{
if (messageMaxSizeReachedCriteria == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public static class AzureStorageAttachmentConfigurationExtensions
/// <param name="sasTokenValidationTime">The time SAS uri is valid for.</param>
/// <returns></returns>
public static AzureStorageAttachmentConfiguration WithSasUri(
this AzureStorageAttachmentConfiguration azureStorageAttachmentConfiguration,
string messagePropertyToIdentifySasUri = DefaultMessagePropertyToIdentitySasUri,
this AzureStorageAttachmentConfiguration azureStorageAttachmentConfiguration,
string messagePropertyToIdentifySasUri = DefaultMessagePropertyToIdentitySasUri,
TimeSpan? sasTokenValidationTime = null)
{
if (sasTokenValidationTime == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,13 @@ public static void RegisterAzureStorageAttachmentPlugin(this ClientEntity client
{
client.RegisterPlugin(new AzureStorageAttachment(configuration));
}

/// <summary>Initiate plugin for Receive-Only mode to retrieve attachments using SAS URI. </summary>
/// <param name="client"><see cref="QueueClient"/>, <see cref="SubscriptionClient"/>, <see cref="QueueClient"/>, <see cref="MessageSender"/>, <see cref="MessageReceiver"/>, or <see cref="SessionClient"/> to register plugin with.</param>
/// <param name="messagePropertyToIdentifySasUri">Message property name to be used to retrieve message SAS UI.</param>
public static void RegisterAzureStorageAttachmentPluginForReceivingOnly(this ClientEntity client, string messagePropertyToIdentifySasUri = AzureStorageAttachmentConfigurationExtensions.DefaultMessagePropertyToIdentitySasUri)
{
client.RegisterPlugin(new ReceiveOnlyAzureStorageAttachment(messagePropertyToIdentifySasUri));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
namespace ServiceBus.AttachmentPlugin
{
using System;
using System.Threading.Tasks;
using Microsoft.Azure.ServiceBus;
using Microsoft.Azure.ServiceBus.Core;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;

class ReceiveOnlyAzureStorageAttachment : ServiceBusPlugin
{
string messagePropertyToIdentifySasUri;

public ReceiveOnlyAzureStorageAttachment(string messagePropertyToIdentifySasUri)
{
this.messagePropertyToIdentifySasUri = messagePropertyToIdentifySasUri;
}

public override string Name { get; } = nameof(ReceiveOnlyAzureStorageAttachment);

public override async Task<Message> AfterMessageReceive(Message message)
{
var userProperties = message.UserProperties;
if (!userProperties.ContainsKey(messagePropertyToIdentifySasUri))
{
return message;
}

var blob = new CloudBlockBlob(new Uri(userProperties[messagePropertyToIdentifySasUri].ToString()));
try
{
await blob.FetchAttributesAsync().ConfigureAwait(false);
}
catch (StorageException exception)
{
throw new Exception($"Blob with name '{blob.Name}' under container '{blob.Container.Name}' cannot be found.", exception);
}
var fileByteLength = blob.Properties.Length;
var bytes = new byte[fileByteLength];
await blob.DownloadToByteArrayAsync(bytes, 0).ConfigureAwait(false);
message.Body = bytes;
return message;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@

<PropertyGroup>
<Description>Microsoft Azure ServiceBus attachment plugin</Description>
<AssemblyTitle>ServiceBus.AttachmentPlugin</AssemblyTitle>
<Version>2.0.1</Version>
<Version>2.1.0</Version>
<Authors>Sean Feldman</Authors>
<TargetFrameworks>netstandard20;net461</TargetFrameworks>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AssemblyName>ServiceBus.AttachmentPlugin</AssemblyName>
<PackageId>ServiceBus.AttachmentPlugin</PackageId>
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
<PackageTags>Azure;Service Bus;ServiceBus;.NET;AMQP;IoT;Queue;Topic;Attachment;Plugin</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/SeanFeldman/ServiceBus.AttachmentPlugin/master/images/project-icon.png</PackageIconUrl>
<PackageLicenseUrl>https://raw.githubusercontent.com/SeanFeldman/ServiceBus.AttachmentPlugin/master/LICENSE</PackageLicenseUrl>
Expand All @@ -34,7 +30,7 @@
</ItemGroup>

<ItemGroup Label="SourceLink to embed PDBs with the assembly">
<PackageReference Include="SourceLink.Create.GitHub" Version="2.5.0" PrivateAssets="All" />
<PackageReference Include="SourceLink.Create.GitHub" Version="2.6.0" PrivateAssets="All" />
<DotNetCliToolReference Include="dotnet-sourcelink-git" Version="2.1.2" />
</ItemGroup>

Expand Down
7 changes: 4 additions & 3 deletions src/ServiceBus.AttachmentPlugin/TokenGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ internal static string GetBlobSasUri(CloudBlockBlob 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 = DateTime.UtcNow.AddMinutes(-5),
SharedAccessExpiryTime = DateTime.UtcNow.Add(timeSpan),
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.
Expand All @@ -23,4 +24,4 @@ internal static string GetBlobSasUri(CloudBlockBlob blob, TimeSpan timeSpan)
return blob.Uri + sasBlobToken;
}
}
}
}

0 comments on commit 55702c8

Please sign in to comment.