Skip to content

Commit

Permalink
Merge pull request Azure#9 from jofriedm-msft/may16
Browse files Browse the repository at this point in the history
[.Net] Pop Receipt Support for Add Message
  • Loading branch information
pemari-msft committed May 6, 2016
2 parents 31cd626 + 016c4f0 commit ef7809d
Show file tree
Hide file tree
Showing 8 changed files with 295 additions and 73 deletions.
4 changes: 4 additions & 0 deletions BreakingChanges.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Tracking Breaking Changes since 7.0

- Queues: Add Message now modifies the PopReceipt, Id, NextVisibleTime, InsertionTime, and ExpirationTime properties of its CloudQueueMessage parameter, and returns this object as well. The message can then be passed to the UpdateMessage and DeleteMessage APIs.

Tracking Breaking Changes since 6.0

- All: Support for 2015-07-08 REST version. Please see our REST API documentation and blogs for information about the related added features. If you are using the Storage Emulator, please update to Emulator version 4.3.
Expand Down
51 changes: 31 additions & 20 deletions Lib/ClassLibraryCommon/Queue/CloudQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1305,15 +1305,17 @@ public virtual Task FetchAttributesAsync(QueueRequestOptions options, OperationC
/// If <c>null</c> then the message will be visible immediately.</param>
/// <param name="options">A <see cref="QueueRequestOptions"/> object that specifies additional options for the request. If <c>null</c>, default options are applied to the request.</param>
/// <param name="operationContext">An <see cref="OperationContext"/> object that represents the context for the current operation.</param>
/// <returns>A <see cref="CloudQueueMessage"/> object.</returns>
/// <remarks>The <see cref="CloudQueueMessage"/> object returned is the same as the message passed in. Both will be populated with the pop receipt along with the insertion/expiration time.</remarks>
[DoesServiceRequest]
public virtual void AddMessage(CloudQueueMessage message, TimeSpan? timeToLive = null, TimeSpan? initialVisibilityDelay = null, QueueRequestOptions options = null, OperationContext operationContext = null)
public virtual CloudQueueMessage AddMessage(CloudQueueMessage message, TimeSpan? timeToLive = null, TimeSpan? initialVisibilityDelay = null, QueueRequestOptions options = null, OperationContext operationContext = null)
{
CommonUtility.AssertNotNull("message", message);

QueueRequestOptions modifiedOptions = QueueRequestOptions.ApplyDefaults(options, this.ServiceClient);
operationContext = operationContext ?? new OperationContext();

Executor.ExecuteSync(
return Executor.ExecuteSync(
this.AddMessageImpl(message, timeToLive, initialVisibilityDelay, modifiedOptions),
modifiedOptions.RetryPolicy,
operationContext);
Expand Down Expand Up @@ -1365,19 +1367,22 @@ public virtual ICancellableAsyncResult BeginAddMessage(CloudQueueMessage message
/// Ends an asynchronous operation to add a message to the queue.
/// </summary>
/// <param name="asyncResult">An <see cref="IAsyncResult"/> that references the pending asynchronous operation.</param>
public virtual void EndAddMessage(IAsyncResult asyncResult)
/// <returns>A <see cref="CloudQueueMessage"/> object.</returns>
/// <remarks>The <see cref="CloudQueueMessage"/> object returned is the same as the message passed in. Both will be populated with the pop receipt along with the insertion/expiration time.</remarks>
public virtual CloudQueueMessage EndAddMessage(IAsyncResult asyncResult)
{
Executor.EndExecuteAsync<NullType>(asyncResult);
return Executor.EndExecuteAsync<CloudQueueMessage>(asyncResult);
}

#if TASK
/// <summary>
/// Initiates an asynchronous operation to add a message to the queue.
/// </summary>
/// <param name="message">A <see cref="CloudQueueMessage"/> object.</param>
/// <returns>A <see cref="Task"/> object that represents the asynchronous operation.</returns>
/// <returns>A <see cref="Task"/> object of type <see cref="CloudQueueMessage"/> that represents the asynchronous operation.</returns>
/// <remarks>The <see cref="CloudQueueMessage"/> object returned is the same as the message passed in. Both will be populated with the pop receipt along with the insertion/expiration time.</remarks>
[DoesServiceRequest]
public virtual Task AddMessageAsync(CloudQueueMessage message)
public virtual Task<CloudQueueMessage> AddMessageAsync(CloudQueueMessage message)
{
return this.AddMessageAsync(message, CancellationToken.None);
}
Expand All @@ -1387,11 +1392,12 @@ public virtual Task AddMessageAsync(CloudQueueMessage message)
/// </summary>
/// <param name="message">A <see cref="CloudQueueMessage"/> object.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for a task to complete.</param>
/// <returns>A <see cref="Task"/> object that represents the asynchronous operation.</returns>
/// <returns>A <see cref="Task"/> object of type <see cref="CloudQueueMessage"/> that represents the asynchronous operation.</returns>
/// <remarks>The <see cref="CloudQueueMessage"/> object returned is the same as the message passed in. Both will be populated with the pop receipt along with the insertion/expiration time.</remarks>
[DoesServiceRequest]
public virtual Task AddMessageAsync(CloudQueueMessage message, CancellationToken cancellationToken)
public virtual Task<CloudQueueMessage> AddMessageAsync(CloudQueueMessage message, CancellationToken cancellationToken)
{
return AsyncExtensions.TaskFromVoidApm(this.BeginAddMessage, this.EndAddMessage, message, cancellationToken);
return AsyncExtensions.TaskFromApm(this.BeginAddMessage, this.EndAddMessage, message, cancellationToken);
}

/// <summary>
Expand All @@ -1403,9 +1409,10 @@ public virtual Task AddMessageAsync(CloudQueueMessage message, CancellationToken
/// If <c>null</c> then the message will be visible immediately.</param>
/// <param name="options">A <see cref="QueueRequestOptions"/> object that specifies additional options for the request.</param>
/// <param name="operationContext">An <see cref="OperationContext"/> object that represents the context for the current operation.</param>
/// <returns>A <see cref="Task"/> object that represents the asynchronous operation.</returns>
/// <returns>A <see cref="Task"/> object of type <see cref="CloudQueueMessage"/> that represents the asynchronous operation.</returns>
/// <remarks>The <see cref="CloudQueueMessage"/> object returned is the same as the message passed in. Both will be populated with the pop receipt along with the insertion/expiration time.</remarks>
[DoesServiceRequest]
public virtual Task AddMessageAsync(CloudQueueMessage message, TimeSpan? timeToLive, TimeSpan? initialVisibilityDelay, QueueRequestOptions options, OperationContext operationContext)
public virtual Task<CloudQueueMessage> AddMessageAsync(CloudQueueMessage message, TimeSpan? timeToLive, TimeSpan? initialVisibilityDelay, QueueRequestOptions options, OperationContext operationContext)
{
return this.AddMessageAsync(message, timeToLive, initialVisibilityDelay, options, operationContext, CancellationToken.None);
}
Expand All @@ -1420,11 +1427,12 @@ public virtual Task AddMessageAsync(CloudQueueMessage message, TimeSpan? timeToL
/// <param name="options">A <see cref="QueueRequestOptions"/> object that specifies additional options for the request.</param>
/// <param name="operationContext">An <see cref="OperationContext"/> object that represents the context for the current operation.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe while waiting for a task to complete.</param>
/// <returns>A <see cref="Task"/> object that represents the asynchronous operation.</returns>
/// <returns>A <see cref="Task"/> object of type <see cref="CloudQueueMessage"/> that represents the asynchronous operation.</returns>
/// <remarks>The <see cref="CloudQueueMessage"/> object returned is the same as the message passed in. Both will will be populated with the pop receipt along with the insertion/expiration time.</remarks>
[DoesServiceRequest]
public virtual Task AddMessageAsync(CloudQueueMessage message, TimeSpan? timeToLive, TimeSpan? initialVisibilityDelay, QueueRequestOptions options, OperationContext operationContext, CancellationToken cancellationToken)
public virtual Task<CloudQueueMessage> AddMessageAsync(CloudQueueMessage message, TimeSpan? timeToLive, TimeSpan? initialVisibilityDelay, QueueRequestOptions options, OperationContext operationContext, CancellationToken cancellationToken)
{
return AsyncExtensions.TaskFromVoidApm(this.BeginAddMessage, this.EndAddMessage, message, timeToLive, initialVisibilityDelay, options, operationContext, cancellationToken);
return AsyncExtensions.TaskFromApm(this.BeginAddMessage, this.EndAddMessage, message, timeToLive, initialVisibilityDelay, options, operationContext, cancellationToken);
}
#endif

Expand Down Expand Up @@ -2544,8 +2552,8 @@ private RESTCommand<QueuePermissions> GetPermissionsImpl(QueueRequestOptions opt
/// <param name="timeToLive">A value indicating the message time-to-live.</param>
/// <param name="initialVisibilityDelay">The visibility delay for the message.</param>
/// <param name="options">A <see cref="QueueRequestOptions"/> object that specifies additional options for the request.</param>
/// <returns>A <see cref="RESTCommand{T}"/> that sets the permissions.</returns>
private RESTCommand<NullType> AddMessageImpl(CloudQueueMessage message, TimeSpan? timeToLive, TimeSpan? initialVisibilityDelay, QueueRequestOptions options)
/// <returns>A <see cref="RESTCommand{T}"/> that contains a <see cref="CloudQueueMessage"/>.</returns>
private RESTCommand<CloudQueueMessage> AddMessageImpl(CloudQueueMessage message, TimeSpan? timeToLive, TimeSpan? initialVisibilityDelay, QueueRequestOptions options)
{
int? timeToLiveInSeconds = null;
int? initialVisibilityDelayInSeconds = null;
Expand All @@ -2568,9 +2576,10 @@ private RESTCommand<NullType> AddMessageImpl(CloudQueueMessage message, TimeSpan
QueueRequest.WriteMessageContent(message.GetMessageContentForTransfer(this.EncodeMessage, options), memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);

RESTCommand<NullType> putCmd = new RESTCommand<NullType>(this.ServiceClient.Credentials, this.GetMessageRequestAddress());
RESTCommand<CloudQueueMessage> putCmd = new RESTCommand<CloudQueueMessage>(this.ServiceClient.Credentials, this.GetMessageRequestAddress());

options.ApplyToStorageCommand(putCmd);
putCmd.RetrieveResponseStream = true;
putCmd.BuildRequestDelegate = (uri, builder, serverTimeout, useVersionHeader, ctx) => QueueHttpWebRequestFactory.AddMessage(uri, serverTimeout, timeToLiveInSeconds, initialVisibilityDelayInSeconds, useVersionHeader, ctx);
putCmd.SendStream = memoryStream;
putCmd.StreamToDispose = memoryStream;
Expand All @@ -2597,10 +2606,12 @@ private RESTCommand<NullType> AddMessageImpl(CloudQueueMessage message, TimeSpan
};

putCmd.SignRequest = this.ServiceClient.AuthenticationHandler.SignRequest;
putCmd.PreProcessResponse = (cmd, resp, ex, ctx) =>
putCmd.PreProcessResponse = (cmd, resp, ex, ctx) => HttpResponseParsers.ProcessExpectedStatusCodeNoException(HttpStatusCode.Created, resp, null /* retVal */, cmd, ex);
putCmd.PostProcessResponse = (cmd, resp, ctx) =>
{
HttpResponseParsers.ProcessExpectedStatusCodeNoException(HttpStatusCode.Created, resp, NullType.Value, cmd, ex);
return NullType.Value;
GetMessagesResponse messageResponse = new GetMessagesResponse(cmd.ResponseStream);

return SelectAddMessageResponse(message, messageResponse.Messages.First());
};

return putCmd;
Expand Down
18 changes: 18 additions & 0 deletions Lib/Common/Queue/CloudQueue.Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,24 @@ private string GetCanonicalName()
return string.Format(CultureInfo.InvariantCulture, canonicalNameFormat, SR.Queue, accountName, queueName);
}

/// <summary>
/// Selects the get message response.
/// </summary>
/// <param name="message">The queue message.</param>
/// <param name="protocolMessage">The protocol message.</param>
/// <returns>The parsed message.</returns>
/// <remarks>The <see cref="CloudQueueMessage"/> object returned is the same as the message passed in. Both will contain the pop receipt along with the insertion/expiration time.</remarks>
private static CloudQueueMessage SelectAddMessageResponse(CloudQueueMessage message, QueueMessage protocolMessage)
{
message.InsertionTime = protocolMessage.InsertionTime;
message.ExpirationTime = protocolMessage.ExpirationTime;
message.NextVisibleTime = protocolMessage.NextVisibleTime.Value;
message.PopReceipt = protocolMessage.PopReceipt;
message.Id = protocolMessage.Id;

return message;
}

/// <summary>
/// Selects the get message response.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions Lib/WindowsDesktop/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@
[assembly: SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Scope = "type", Target = "Microsoft.WindowsAzure.Storage.Blob.CloudBlobClient", Justification = "Reviewed")]
[assembly: SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Scope = "member", Target = "Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer.#ListBlobsImpl(System.String,System.Nullable`1<System.Int32>,System.Boolean,Microsoft.WindowsAzure.Storage.Blob.BlobListingDetails,Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions,Microsoft.WindowsAzure.Storage.Blob.BlobContinuationToken)", Justification = "Reviewed")]
[assembly: SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Scope = "type", Target = "Microsoft.WindowsAzure.Storage.Queue.CloudQueue", Justification = "Reviewed")]
[assembly: SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Scope = "member", Target = "Microsoft.WindowsAzure.Storage.Queue.CloudQueue.#AddMessageImpl(Microsoft.WindowsAzure.Storage.Queue.CloudQueueMessage,System.Nullable`1<System.TimeSpan>,System.Nullable`1<System.TimeSpan>,Microsoft.WindowsAzure.Storage.Queue.QueueRequestOptions)", Justification = "Reviewed")]
[assembly: SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Scope = "member", Target = "Microsoft.WindowsAzure.Storage.Blob.CloudBlobSharedImpl.#GetBlobImpl(Microsoft.WindowsAzure.Storage.Blob.ICloudBlob,Microsoft.WindowsAzure.Storage.Blob.BlobAttributes,System.IO.Stream,System.Nullable`1<System.Int64>,System.Nullable`1<System.Int64>,Microsoft.WindowsAzure.Storage.AccessCondition,Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions)", Justification = "Reviewed.")]
[assembly: SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Scope = "member", Target = "Microsoft.WindowsAzure.Storage.Queue.CloudQueueClient.#ListQueuesImpl(System.String,System.Nullable`1<System.Int32>,Microsoft.WindowsAzure.Storage.Queue.Protocol.QueueListingDetails,Microsoft.WindowsAzure.Storage.Queue.QueueRequestOptions,Microsoft.WindowsAzure.Storage.Queue.Protocol.QueueContinuationToken)", Justification = "Reviewed.")]
[assembly: SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Scope = "member", Target = "Microsoft.WindowsAzure.Storage.Blob.CloudBlobClient.#ListContainersImpl(System.String,Microsoft.WindowsAzure.Storage.Blob.ContainerListingDetails,Microsoft.WindowsAzure.Storage.Blob.BlobContinuationToken,System.Nullable`1<System.Int32>,Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions)", Justification = "Reviewed.")]
Expand Down
Loading

0 comments on commit ef7809d

Please sign in to comment.