internal static Tuple<HttpWebRequest, Stream> BuildRequestForTableOperation(Uri uri, UriQueryBuilder builder, IBufferManager bufferManager, int? timeout, TableOperation operation, bool useVersionHeader, OperationContext ctx, TableRequestOptions options, string accountName)
        {
            HttpWebRequest msg = BuildRequestCore(uri, builder, operation.HttpMethod, timeout, useVersionHeader, ctx);

            TablePayloadFormat payloadFormat = options.PayloadFormat.Value;

            // Set Accept and Content-Type based on the payload format.
            SetAcceptHeaderForHttpWebRequest(msg, payloadFormat);
            Logger.LogInformational(ctx, SR.PayloadFormat, payloadFormat);

            if (operation.HttpMethod != "HEAD" && operation.HttpMethod != "GET")
            {
                SetContentTypeForHttpWebRequest(msg, payloadFormat);
            }

            if (operation.OperationType == TableOperationType.InsertOrMerge || operation.OperationType == TableOperationType.Merge)
            {
                options.AssertNoEncryptionPolicyOrStrictMode();

                // post tunnelling
                msg.Headers.Add("X-HTTP-Method", "MERGE");
            }

            // etag
            if (operation.OperationType == TableOperationType.Delete ||
                operation.OperationType == TableOperationType.Replace ||
                operation.OperationType == TableOperationType.Merge)
            {
                if (operation.Entity.ETag != null)
                {
                    msg.Headers.Add("If-Match", operation.Entity.ETag);
                }
            }

            // prefer header
            if (operation.OperationType == TableOperationType.Insert)
            {
                msg.Headers.Add("Prefer", operation.EchoContent ? "return-content" : "return-no-content");
            }
            
            if (operation.OperationType == TableOperationType.Insert ||
                operation.OperationType == TableOperationType.Merge ||
                operation.OperationType == TableOperationType.InsertOrMerge ||
                operation.OperationType == TableOperationType.InsertOrReplace ||
                operation.OperationType == TableOperationType.Replace)
            {
                // create the writer, indent for readability of the examples.  
                ODataMessageWriterSettings writerSettings = new ODataMessageWriterSettings()
                {
                    CheckCharacters = false,   // sets this flag on the XmlWriter for ATOM  
                    Version = TableConstants.ODataProtocolVersion // set the Odata version to use when writing the entry 
                };

                HttpWebRequestAdapterMessage adapterMsg = new HttpWebRequestAdapterMessage(msg, bufferManager);

                if (operation.HttpMethod != "HEAD" && operation.HttpMethod != "GET")
                {
                    SetContentTypeForAdapterMessage(adapterMsg, payloadFormat);
                }
                
                ODataMessageWriter odataWriter = new ODataMessageWriter(adapterMsg, writerSettings, new TableStorageModel(accountName));
                ODataWriter writer = odataWriter.CreateODataEntryWriter();
                WriteOdataEntity(operation.Entity, operation.OperationType, ctx, writer, options);

                return new Tuple<HttpWebRequest, Stream>(adapterMsg.GetPopulatedMessage(), adapterMsg.GetStream());
            }

            return new Tuple<HttpWebRequest, Stream>(msg, null);
        }
        internal static IEnumerable<ODataProperty> GetPropertiesFromDictionary(IDictionary<string, EntityProperty> properties, TableRequestOptions options, string partitionKey, string rowKey)
        {
            // Check if encryption policy is set and invoke EncryptEnity if it is set.
            if (options != null)
            {
                options.AssertPolicyIfRequired();

                if (options.EncryptionPolicy != null)
                {
                    properties = options.EncryptionPolicy.EncryptEntity(properties, partitionKey, rowKey, options.EncryptionResolver);
                }
            }

            return properties.Select(kvp => new ODataProperty() { Name = kvp.Key, Value = kvp.Value.PropertyAsObject });
        }
        internal static IEnumerable<ODataProperty> GetPropertiesWithKeys(ITableEntity entity, OperationContext operationContext, TableOperationType operationType, TableRequestOptions options)
        {
            if (operationType == TableOperationType.Insert)
            {
                if (entity.PartitionKey != null)
                {
                    yield return new ODataProperty() { Name = TableConstants.PartitionKey, Value = entity.PartitionKey };
                }

                if (entity.RowKey != null)
                {
                    yield return new ODataProperty() { Name = TableConstants.RowKey, Value = entity.RowKey };
                }
            }

            foreach (ODataProperty property in GetPropertiesFromDictionary(entity.WriteEntity(operationContext), options, entity.PartitionKey, entity.RowKey))
            {
                yield return property;
            }
        }
        internal static Tuple<HttpWebRequest, Stream> BuildRequestForTableBatchOperation(Uri uri, UriQueryBuilder builder, IBufferManager bufferManager, int? timeout, string tableName, TableBatchOperation batch, bool useVersionHeader, OperationContext ctx, TableRequestOptions options, string accountName)
        {
            HttpWebRequest msg = BuildRequestCore(NavigationHelper.AppendPathToSingleUri(uri, "$batch"), builder, "POST", timeout, useVersionHeader, ctx);
            TablePayloadFormat payloadFormat = options.PayloadFormat.Value;
            Logger.LogInformational(ctx, SR.PayloadFormat, payloadFormat);

            // create the writer, indent for readability of the examples.  
            ODataMessageWriterSettings writerSettings = new ODataMessageWriterSettings()
            {
                CheckCharacters = false,   // sets this flag on the XmlWriter for ATOM  
                Version = TableConstants.ODataProtocolVersion // set the Odata version to use when writing the entry 
            };

            HttpWebRequestAdapterMessage adapterMsg = new HttpWebRequestAdapterMessage(msg, bufferManager);

            ODataMessageWriter odataWriter = new ODataMessageWriter(adapterMsg, writerSettings);

            ODataBatchWriter batchWriter = odataWriter.CreateODataBatchWriter();
            batchWriter.WriteStartBatch();

            bool isQuery = batch.Count == 1 && batch[0].OperationType == TableOperationType.Retrieve;

            // Query operations should not be inside changeset in payload
            if (!isQuery)
            {
                // Start Operation
                batchWriter.WriteStartChangeset();
                batchWriter.Flush();
            }

            foreach (TableOperation operation in batch)
            {
                string httpMethod = operation.HttpMethod;
                if (operation.OperationType == TableOperationType.Merge || operation.OperationType == TableOperationType.InsertOrMerge)
                {
                    options.AssertNoEncryptionPolicyOrStrictMode();
                    httpMethod = "MERGE";
                }

                ODataBatchOperationRequestMessage mimePartMsg = batchWriter.CreateOperationRequestMessage(httpMethod, operation.GenerateRequestURI(uri, tableName));
                SetAcceptAndContentTypeForODataBatchMessage(mimePartMsg, payloadFormat);

                // etag
                if (operation.OperationType == TableOperationType.Delete ||
                    operation.OperationType == TableOperationType.Replace ||
                    operation.OperationType == TableOperationType.Merge)
                {
                    mimePartMsg.SetHeader("If-Match", operation.Entity.ETag);
                }

                // Prefer header
                if (operation.OperationType == TableOperationType.Insert)
                {
                    mimePartMsg.SetHeader("Prefer", operation.EchoContent ? "return-content" : "return-no-content");
                }
                
                if (operation.OperationType != TableOperationType.Delete && operation.OperationType != TableOperationType.Retrieve)
                {
                    using (ODataMessageWriter batchEntryWriter = new ODataMessageWriter(mimePartMsg, writerSettings, new TableStorageModel(accountName)))
                    {
                        // Write entity
                        ODataWriter entryWriter = batchEntryWriter.CreateODataEntryWriter();
                        WriteOdataEntity(operation.Entity, operation.OperationType, ctx, entryWriter, options);
                    }
                }
            }

            if (!isQuery)
            {
                // End Operation
                batchWriter.WriteEndChangeset();
            }

            // End Batch
            batchWriter.WriteEndBatch();
            batchWriter.Flush();

            return new Tuple<HttpWebRequest, Stream>(adapterMsg.GetPopulatedMessage(), adapterMsg.GetStream());
        }
        private static void WriteOdataEntity(ITableEntity entity, TableOperationType operationType, OperationContext ctx, ODataWriter writer, TableRequestOptions options)
        {
            ODataEntry entry = new ODataEntry()
            {
                Properties = GetPropertiesWithKeys(entity, ctx, operationType, options),
                TypeName = "account.sometype"
            };

            entry.SetAnnotation(new SerializationTypeNameAnnotation { TypeName = null });
            writer.WriteStart(entry);
            writer.WriteEnd();
            writer.Flush();
        }
        public void TableSetPermissionsPermissionsRequestOptionsOperationContextCancellationTokenTask()
        {
            CloudTableClient tableClient = GenerateCloudTableClient();
            string tableName = GenerateRandomTableName();
            CloudTable table = tableClient.GetTableReference(tableName);
            TablePermissions permissions = new TablePermissions();
            TableRequestOptions requestOptions = new TableRequestOptions();
            OperationContext operationContext = new OperationContext();
            CancellationToken cancellationToken = CancellationToken.None;

            permissions.SharedAccessPolicies.Add(Guid.NewGuid().ToString(), new SharedAccessTablePolicy()
            {
                Permissions = SharedAccessTablePermissions.Query,
                SharedAccessStartTime = DateTimeOffset.Now.Add(new TimeSpan(-1, 0, 0)),
                SharedAccessExpiryTime = DateTimeOffset.Now.Add(new TimeSpan(1, 0, 0))
            });

            try
            {
                table.CreateAsync().Wait();
                table.ExecuteAsync(TableOperation.Insert(new BaseEntity("PK", "RK"))).Wait();

                table.SetPermissionsAsync(permissions, requestOptions, operationContext, cancellationToken);
            }
            finally
            {
                table.DeleteIfExistsAsync().Wait();
            }
        }
        public void TableServiceContextTimeoutDuringSaveChangesNonBatchAPM()
        {
            CloudTableClient tableClient = GenerateCloudTableClient();
            TableServiceContext ctx = tableClient.GetTableServiceContext();

            for (int m = 0; m < 100; m++)
            {
                BaseEntity ent = new BaseEntity("testpartition", m.ToString());
                ent.Randomize();
                ent.A = ent.RowKey;
                ctx.AddObject(currentTable.Name, ent);
            }

            OperationContext opContext = new OperationContext();
            TableRequestOptions requestOptions = new TableRequestOptions() { MaximumExecutionTime = TimeSpan.FromSeconds(5) };

            using (HttpMangler proxy = new HttpMangler(false,
                new[] { DelayBehaviors.DelayAllRequestsIf(2000, XStoreSelectors.TableTraffic().IfHostNameContains(tableClient.Credentials.AccountName).SkipNSessions(10)) }))
            {
                try
                {
                    using (ManualResetEvent evt = new ManualResetEvent(false))
                    {
                        IAsyncResult result = ctx.BeginSaveChangesWithRetries(SaveChangesOptions.None, requestOptions, opContext,
                            (res) =>
                            {
                                result = res;
                                evt.Set();
                            }, null);

                        evt.WaitOne();

                        ctx.EndSaveChangesWithRetries(result);
                    }

                    ctx.SaveChangesWithRetries(SaveChangesOptions.None, requestOptions, opContext);
                }
                catch (StorageException ex)
                {
                    Assert.AreEqual(ex.RequestInformation.HttpStatusCode, (int)HttpStatusCode.RequestTimeout);
                    Assert.AreEqual("The client could not finish the operation within specified timeout.", ex.Message);
                    Assert.IsTrue(ex.InnerException is TimeoutException);
                }
            }
        }
        internal TableCommand<DataServiceResponse, DataServiceResponse> GenerateSaveChangesCommand(SaveChangesOptions options, TableRequestOptions requestOptions)
        {
            TableCommand<DataServiceResponse, DataServiceResponse> cmd = new TableCommand<DataServiceResponse, DataServiceResponse>();

            if (requestOptions.ServerTimeout.HasValue)
            {
                this.Timeout = (int)requestOptions.ServerTimeout.Value.TotalSeconds;
            }

            cmd.ExecuteFunc = () => this.SaveChanges(options);
            cmd.Begin = (callback, state) => this.BeginSaveChanges(options, callback, state);
            cmd.End = this.EndSaveChanges;
            cmd.ParseResponse = this.ParseDataServiceResponse;
            cmd.ParseDataServiceError = StorageExtendedErrorInformation.ReadDataServiceResponseFromStream;
            cmd.Context = this;
            requestOptions.ApplyToStorageCommand(cmd);

            return cmd;
        }
        public void TableGetPermissionsRequestOptionsOperationContextCancellationTokenTask()
        {
            CloudTableClient tableClient = GenerateCloudTableClient();
            string tableName = GenerateRandomTableName();
            CloudTable table = tableClient.GetTableReference(tableName);
            TableRequestOptions requestOptions = new TableRequestOptions();
            OperationContext operationContext = new OperationContext();
            CancellationToken cancellationToken = CancellationToken.None;

            try
            {
                table.CreateAsync().Wait();
                table.ExecuteAsync(TableOperation.Insert(new BaseEntity("PK", "RK"))).Wait();

                TablePermissions expected = new TablePermissions();
                TablePermissions actual = table.GetPermissionsAsync(requestOptions, operationContext, cancellationToken).Result;
                AssertPermissionsEqual(expected, actual);
            }
            finally
            {
                table.DeleteIfExistsAsync().Wait();
            }
        }
 public Task<DataServiceResponse> SaveChangesWithRetriesAsync(SaveChangesOptions options, TableRequestOptions requestOptions, OperationContext operationContext, CancellationToken cancellationToken)
 {
     return AsyncExtensions.TaskFromApm(this.BeginSaveChangesWithRetries, this.EndSaveChangesWithRetries, options, requestOptions, operationContext, cancellationToken);
 }
 public Task<DataServiceResponse> SaveChangesWithRetriesAsync(SaveChangesOptions options, TableRequestOptions requestOptions, OperationContext operationContext)
 {
     return this.SaveChangesWithRetriesAsync(options, requestOptions, operationContext, CancellationToken.None);
 }
 public ICancellableAsyncResult BeginSaveChangesWithRetries(SaveChangesOptions options, TableRequestOptions requestOptions, OperationContext operationContext, AsyncCallback callback, object state)
 {
     requestOptions = TableRequestOptions.ApplyDefaults(requestOptions, this.ServiceClient);
     operationContext = operationContext ?? new OperationContext();
     TableCommand<DataServiceResponse, DataServiceResponse> cmd = this.GenerateSaveChangesCommand(options, requestOptions);
     return TableExecutor.BeginExecuteAsync(cmd, requestOptions.RetryPolicy, operationContext, callback, state);
 }
 public DataServiceResponse SaveChangesWithRetries(SaveChangesOptions options, TableRequestOptions requestOptions = null, OperationContext operationContext = null)
 {
     requestOptions = TableRequestOptions.ApplyDefaults(requestOptions, this.ServiceClient);
     operationContext = operationContext ?? new OperationContext();
     TableCommand<DataServiceResponse, DataServiceResponse> cmd = this.GenerateSaveChangesCommand(options, requestOptions);
     return TableExecutor.ExecuteSync(cmd, requestOptions.RetryPolicy, operationContext);
 }
        internal TableCommand<DataServiceResponse, DataServiceResponse> GenerateSaveChangesCommand(SaveChangesOptions options, TableRequestOptions requestOptions)
        {
            TableCommand<DataServiceResponse, DataServiceResponse> cmd = new TableCommand<DataServiceResponse, DataServiceResponse>();

            if (requestOptions.ServerTimeout.HasValue)
            {
                this.Timeout = (int)requestOptions.ServerTimeout.Value.TotalSeconds;
            }

            cmd.ExecuteFunc = () => this.SaveChanges(options);
            cmd.Begin = (callback, state) => this.BeginSaveChanges(options, callback, state);
            cmd.End = this.EndSaveChanges;
            cmd.ParseResponse = this.ParseDataServiceResponse;
            cmd.ApplyRequestOptions(requestOptions);
            cmd.Context = this;

            return cmd;
        }