public async Task <bool> ConfirmAppendDataAsync(string subscriptionId, PwnedPasswordsTransaction transaction, CancellationToken cancellationToken = default)
    {
        try
        {
            Response <AppendTransactionEntity> transactionEntityResponse = await _transactionTable.GetEntityAsync <AppendTransactionEntity>(subscriptionId, transaction.TransactionId, cancellationToken : cancellationToken).ConfigureAwait(false);

            if (!transactionEntityResponse.Value.Confirmed)
            {
                transactionEntityResponse.Value.Confirmed = true;
                Response?updateResponse = await _transactionTable.UpdateEntityAsync(transactionEntityResponse.Value, transactionEntityResponse.Value.ETag, cancellationToken : cancellationToken).ConfigureAwait(false);

                _log.LogInformation("Subscription {SubscriptionId} successfully confirmed transaction {TransactionId}. Queueing data for blob updates.", subscriptionId, transaction.TransactionId);
                return(true);
            }

            // We've already confirmed this transaction.
            return(false);
        }
        catch (RequestFailedException e) when(e.Status == 404)
        {
            throw new ArgumentOutOfRangeException("Transaction id not found.", e);
        }
        catch (RequestFailedException e) when(e.Status == StatusCodes.Status409Conflict)
        {
            throw new ArgumentException("Transaciton has already been updated.", e);
        }
        catch (RequestFailedException e)
        {
            _log.LogError(e, "Error looking up/updating transaction with id = {TransactionId} for subscription {SubscriptionId}.", transaction.TransactionId, subscriptionId);
            throw new InvalidOperationException("Error confirming transaction.", e);
        }
    }
        public async Task TableEntity_IfBoundToPocoTableEntity_CanCall()
        {
            // Arrange
            await TableClient.AddEntityAsync(new TableEntity(PartitionKey, RowKey)
            {
                { "Fruit", ("Banana") },
                { "Duration", ("\"00:00:01\"") },
                { "Value", ("Foo") }
            });

            // Act
            await CallAsync <BindTableEntityToPocoTableEntityProgram>();

            // Assert
            TableEntity entity = await TableClient.GetEntityAsync <TableEntity>(PartitionKey, RowKey);

            Assert.NotNull(entity);
            Assert.AreEqual(PartitionKey, entity.PartitionKey); // Guard
            Assert.AreEqual(RowKey, entity.RowKey);             // Guard

            // TODO: behavior change. Was 3 before
            Assert.AreEqual(7, entity.Count);
            Assert.AreEqual("Pear", entity["Fruit"]);
            Assert.AreEqual("\"00:02:00\"", entity["Duration"]);
            Assert.AreEqual("Bar", entity["Value"]);
        }
    public static async Task <IActionResult> UpdateTodo(
        [HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = Route + "/{id}")] HttpRequest req,
        [Table(TableName, Connection = "AzureWebJobsStorage")] TableClient todoTable,
        ILogger log, string id)
    {
        string          requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        var             updated     = JsonConvert.DeserializeObject <TodoUpdateModel>(requestBody);
        TodoTableEntity existingRow;

        try
        {
            var findResult = await todoTable.GetEntityAsync <TodoTableEntity>(PartitionKey, id);

            existingRow = findResult.Value;
        }
        catch (RequestFailedException e) when(e.Status == 404)
        {
            return(new NotFoundResult());
        }

        existingRow.IsCompleted = updated.IsCompleted;
        if (!string.IsNullOrEmpty(updated.TaskDescription))
        {
            existingRow.TaskDescription = updated.TaskDescription;
        }

        await todoTable.UpdateEntityAsync(existingRow, existingRow.ETag, TableUpdateMode.Replace);

        return(new OkObjectResult(existingRow.ToTodo()));
    }
Example #4
0
        public async Task <DishEntity> InsertAsync(DishEntity dish)
        {
            if (dish.PartitionKey == null)
            {
                dish.PartitionKey = "lye";
            }
            if (dish.RowKey == null)
            {
                dish.RowKey = Guid.NewGuid().ToString();
            }

            var response = await _dishTable.AddEntityAsync(dish);

            _logger.LogInformation("Inserted new dish with RowKey {RowKey} - Status: {HttpStatus}", dish.RowKey, response.Status);
            var entity = await _dishTable.GetEntityAsync <DishEntity>(dish.PartitionKey, dish.RowKey);

            return(entity);
        }
Example #5
0
        public async Task Table_IfBoundToOutParameterAndTableIsMissingAndAdds_CreatesTable <T>()
        {
            // Act
            await CallAsync <BindOut <T> >();

            // Assert
            var entity = TableClient.GetEntityAsync <TableEntity>(PartitionKey, RowKey);

            Assert.AreEqual("test value", entity.Result.Value["Value"]);
        }
        private async Task TestTableBoundToCollectorCanCallAsync <T>() where T : new()
        {
            // Arrange
            await CallAsync <T>();

            // Assert
            TableEntity entity = await TableClient.GetEntityAsync <TableEntity>(PartitionKey, RowKey);

            Assert.NotNull(entity);
        }
        public async Task Table_IfBoundToICollectorJObject_AddInsertsEntity()
        {
            // Act
            await CallAsync <BindToICollectorJObjectProgram>();

            // Assert
            TableEntity entity = await TableClient.GetEntityAsync <TableEntity>(PartitionKey, RowKey);

            Assert.NotNull(entity);
            Assert.AreEqual("abcdef", entity["ValueStr"]);
            Assert.AreEqual(123, entity["ValueNum"]);
        }
        public async Task TableEntity_IfBoundToSdkTableEntity_CanCall()
        {
            // Arrange
            await TableClient.AddEntityAsync(CreateTableEntity(PartitionKey, RowKey, "Value", "Foo"));

            // Act
            await CallAsync <BindTableEntityToSdkTableEntityProgram>();

            // Assert
            SdkTableEntity entity = await TableClient.GetEntityAsync <SdkTableEntity>(PartitionKey, RowKey);

            Assert.NotNull(entity);
            Assert.AreEqual("Bar", entity.Value);
        }
        public async Task CustomizeSerialization()
        {
            string storageUri = StorageUri;
            string tableName  = "OfficeSupplies" + _random.Next();

            #region Snippet:CustomSerialization

            // Construct a new TableClient using a TokenCredential.
            var client = new TableClient(
                new Uri(storageUri),
                tableName,
#if SNIPPET
                new DefaultAzureCredential());
#else
                new ClientSecretCredential(
                    GetVariable("TENANT_ID"),
                    GetVariable("CLIENT_ID"),
                    GetVariable("CLIENT_SECRET")));
#endif

            // Create the table if it doesn't already exist.
            client.CreateIfNotExists();

            // Create a new entity with our customization attributes.
            var entity = new CustomSerializationEntity
            {
                PartitionKey = "CustomInventory",
                RowKey       = "special stock",
                Product      = "Fancy Marker",
                Price        = 1.00,
                Quantity     = 42,
                IgnoreMe     = "nothing to see here",
                RenameMe     = "This property will be saved to the table as 'rename_me'"
            };

            // Add the entity to the table. It will be serialized according to our customizations.
            await client.AddEntityAsync(entity);

            // Fetch the entity as a TableEntity so that we can verify that things were serialized as expected.
            var fetchedEntity = await client.GetEntityAsync <TableEntity>(entity.PartitionKey, entity.RowKey);

            // Print each property name to the console.
            foreach (string propertyName in fetchedEntity.Value.Keys)
            {
                Console.WriteLine(propertyName);
            }

            #endregion
        }
Example #10
0
        public async Task <SyncState> ReadAsync(CancellationToken cancellationToken = default)
        {
            TableClient tableClient = _tableServiceClient.GetTableClient(Constants.SyncStateTableName);

            try
            {
                var entity = await tableClient.GetEntityAsync <SyncStateEntity>(Constants.SyncStatePartitionKey, Constants.SyncStateRowKey, cancellationToken : cancellationToken);

                return(new SyncState(entity.Value.SyncedSequence, entity.Value.Timestamp.Value));
            }
            catch (RequestFailedException)
            {
                return(SyncState.CreateInitialSyncState());
            }
        }
        // Assert the given table has the given entity with PropertyName=ExpectedValue
        private async Task AssertStringPropertyAsync(
            string propertyName,
            string expectedValue,
            string tableName    = null,
            string partitionKey = PartitionKey,
            string rowKey       = RowKey)
        {
            // Assert
            tableName ??= TableName;
            TableClient table = ServiceClient.GetTableClient(tableName);

            Assert.True(await TableExistsAsync(table).ConfigureAwait(false));
            TableEntity entity = await table.GetEntityAsync <TableEntity>(partitionKey, rowKey);

            Assert.AreEqual(expectedValue, entity[propertyName]);
        }
        private async Task TestBindToConcurrentlyUpdatedTableEntity <T>(string parameterName)
        {
            // Arrange
            await TableClient.CreateIfNotExistsAsync();

            await TableClient.AddEntityAsync(CreateTableEntity(PartitionKey, RowKey, "Value", "Foo"));

            // Act & Assert
            var exception = Assert.CatchAsync <FunctionInvocationException>(async() => await CallAsync <T>("Call"));

            AssertInvocationETagFailure(parameterName, exception);
            SdkTableEntity entity = await TableClient.GetEntityAsync <SdkTableEntity>(PartitionKey, RowKey);

            Assert.NotNull(entity);
            Assert.AreEqual("FooBackground", entity.Value);
        }
        public async Task TableEntity_IfBoundToJObject_CanCall()
        {
            // Arrange
            await TableClient.AddEntityAsync(CreateTableEntity(PartitionKey, RowKey, "Value", "Foo"));

            await CallAsync <BindTableEntityToJObjectProgram>(arguments : new
            {
                table = TableName, // Test resolution
                pk1   = PartitionKey,
                rk1   = RowKey
            });

            // Assert
            SdkTableEntity entity = await TableClient.GetEntityAsync <SdkTableEntity>(PartitionKey, RowKey);

            Assert.NotNull(entity);
        }
    public async Task <string?> GetTokenAsync(string tenantId, string userId)
    {
        await _tableClient.CreateIfNotExistsAsync();

        try
        {
            var response = await _tableClient.GetEntityAsync <UserTokenEntity>(partitionKey : tenantId, rowKey : userId);

            _logger.LogInformation("Found token for user ([{tenantId}], [{userId}])", tenantId, userId);
            return(response?.Value?.Token);
        }
        catch (RequestFailedException ex) when(ex.Status == 404)
        {
            _logger.LogInformation("No token stored for user ([{tenantId}], [{userId}])", tenantId, userId);
            return(null);
        }
    }
Example #15
0
        public async Task <T> GetTableRow <T>(string tableName, string rowKey, string partitionKey = "default")
            where T : ValueWithEtag
        {
            TableClient tableClient = await this.GetTableClient(tableName);

            try
            {
                var res = await tableClient.GetEntityAsync <ContentDataEntity>(partitionKey, rowKey);

                T value = JsonConvert.DeserializeObject <T>(res.Value.Content);
                value.etag = res.Value.ETag;
                return(value);
            }
            catch (RequestFailedException e)
            {
                return(null);
            }
        }
Example #16
0
        public async Task <IActionResult> GetFileAsync(string fileId)
        {
            // TODO: Verify that user is allowed to get files for this chat/call

            // Prepare Table Storage clients
            TableServiceClient tableServiceClient = new TableServiceClient(_storageAccountConnectionString);
            TableClient        tableClient        = tableServiceClient.GetTableClient(_tableName);

            tableClient.CreateIfNotExists();

            // Get file info from Table Storage
            Azure.Response <TableEntity> getTableEntityResponse;
            try
            {
                getTableEntityResponse = await tableClient.GetEntityAsync <TableEntity>(fileId, fileId);
            }
            catch (Azure.RequestFailedException e)
            {
                if (e.Status == 404)
                {
                    return(NotFound());
                }

                return(BadRequest("Couldn't get file from storage"));
            }

            var fileName = getTableEntityResponse.Value.GetString("FileName");

            // Prepare Blob Storage clients and container
            BlobContainerClient containerClient = new BlobContainerClient(_storageAccountConnectionString, _blobContainerName);

            containerClient.CreateIfNotExists();
            BlobClient blob = containerClient.GetBlobClient(fileId);

            // MemoryStream blobStream = new MemoryStream();
            // var downloadResult = await blob.DownloadToAsync(blobStream);
            var blobStream = await blob.OpenReadAsync();

            return(new FileStreamResult(blobStream, "application/octet-stream")
            {
                FileDownloadName = fileName
            });
        }
            public static async Task Call([Table(TableNameExpression)] ICollector <ITableEntity> collector,
                                          [Table(TableNameExpression)] TableClient table)
            {
                SdkTableEntity entity = await table.GetEntityAsync <SdkTableEntity>(PartitionKey, RowKey);

                Assert.NotNull(entity);
                Assert.AreEqual("Foo", entity.Value);
                // Update the entity to invalidate the version read by this method.
                await table.UpdateEntityAsync(new SdkTableEntity
                {
                    PartitionKey = PartitionKey,
                    RowKey       = RowKey,
                    Value        = "FooBackground"
                }, ETag.All);

                // The attempted update by this method should now fail.
                collector.Add(new TableEntity(PartitionKey, RowKey)
                {
                    ETag      = entity.ETag,
                    ["Value"] = "Bar"
                });
            }
        public async Task TableEntity_IfUpdatesPoco_Persists()
        {
            // Arrange
            const string originalValue = "abc";
            const string expectedValue = "def";

            await TableClient.AddEntityAsync(new TableEntity(PartitionKey, RowKey)
            {
                { "Value", (originalValue) }
            });

            // Act
            await CallAsync <UpdatePocoProgram>(arguments : new
            {
                newValue = expectedValue
            });

            // Assert
            TableEntity entity = await TableClient.GetEntityAsync <TableEntity>(PartitionKey, RowKey);

            Assert.NotNull(entity);
            Assert.AreEqual(expectedValue, entity["Value"]);
        }
        public async Task TableEntity_IfBoundUsingRouteParameters_Binds()
        {
            // Arrange

            await TableClient.AddEntityAsync(new TableEntity(PartitionKey, RowKey)
            {
                { "Value", (123) }
            });

            // Act
            await CallAsync <BindUsingRouteParametersProgram>(arguments : new
            {
                TableName    = TableName,
                PartitionKey = PartitionKey,
                RowKey       = RowKey
            });

            // Assert
            TableEntity entity = await TableClient.GetEntityAsync <TableEntity>(PartitionKey, RowKey);

            Assert.NotNull(entity);
            Assert.AreEqual(456, entity["Value"]);
        }
        public async Task TableEntity_IfUpdatesPoco_PersistsUsingNativeTableTypes()
        {
            // Arrange
            byte[] originalValue = new byte[] { 0x12, 0x34 };
            byte[] expectedValue = new byte[] { 0x56, 0x78 };

            await TableClient.AddEntityAsync(new TableEntity(PartitionKey, RowKey)
            {
                { "Value", (originalValue) }
            });

            // Act
            await CallAsync <UpdatePocoWithByteArrayValueProgram>(arguments : new
            {
                expectedValue
            });

            // Assert
            TableEntity entity = await TableClient.GetEntityAsync <TableEntity>(PartitionKey, RowKey);

            Assert.NotNull(entity);
            Assert.AreEqual(expectedValue, entity["Value"]);
        }
 public Task <Response <T> > GetByRowKeyAsync(string rowKey) => _tableClient.GetEntityAsync <T>(_partitionKey, rowKey);
Example #22
0
        public async Task <long> StoreStateData <TData, TState>(StateDto metaData, long currentSequenceNumber, TData data, bool saveHistory, string parentIdentifier)
            where TData : BaseStateDataModel <TState>
            where TState : struct, IConvertible
        {
            var tableName = NormalizeTableName(metaData.MachineName);

            _logger.LogTrace($"Using table name {tableName}");
            TableClient table = await GetTable(tableName);

            string partitionKey = string.IsNullOrWhiteSpace(parentIdentifier) ? metaData.Identifier : parentIdentifier;
            string rowKeyPrefix = string.IsNullOrWhiteSpace(parentIdentifier) ? "" : $"{metaData.Identifier}-";

            var currentResponse = await table.GetEntityAsync <StateDataTable>(partitionKey, rowKeyPrefix + "current");

            StateDataTable currentMarker = currentResponse?.Value;

            long sequenceNumber = currentMarker?.SequenceNumber ?? 0;

            if (sequenceNumber != currentSequenceNumber)
            {
                throw new Exception($"Out of sequence state update attempted. For {metaData.Identifier} attempted to replace {currentSequenceNumber}. Current version is actually {sequenceNumber}");
            }

            long nextSequenceNumber = sequenceNumber + 1;

            if (currentMarker == null)
            {
                currentMarker = new StateDataTable();
            }

            var serializedState = await _objectSerializer.Serialize(data);

            if (serializedState.Length > 28_000)
            {
                throw new Exception("Serialized data is > 28,000 chars");
            }

            currentMarker.PartitionKey    = partitionKey;
            currentMarker.RowKey          = rowKeyPrefix + "current";
            currentMarker.SequenceNumber  = nextSequenceNumber;
            currentMarker.MachineName     = metaData.MachineName;
            currentMarker.ContentLength   = serializedState.Length;
            currentMarker.SerializedState = serializedState;
            currentMarker.Source          = metaData.Source;
            currentMarker.Destination     = metaData.Destination;
            currentMarker.IsReentry       = metaData.IsReentry;
            currentMarker.Trigger         = metaData.Trigger;
            currentMarker.CorrelationId   = metaData.CorrelationId.ToString();
            currentMarker.UserIdentifier  = metaData.UserIdentifier;
            currentMarker.Username        = metaData.Username;
            currentMarker.UpdateAuditable(metaData);

            var record = new StateDataTable
            {
                PartitionKey    = partitionKey,
                RowKey          = rowKeyPrefix + nextSequenceNumber,
                MachineName     = metaData.MachineName,
                Source          = metaData.Source,
                ContentLength   = serializedState.Length,
                Destination     = metaData.Destination,
                IsReentry       = metaData.IsReentry,
                SequenceNumber  = nextSequenceNumber,
                SerializedState = serializedState,
                Trigger         = metaData.Trigger,
                UserIdentifier  = metaData.UserIdentifier,
                Username        = metaData.Username,
                CorrelationId   = metaData.CorrelationId.ToString()
            }.UpdateAuditable(metaData);

            try
            {
                List <TableTransactionAction> batch = new List <TableTransactionAction>();

                batch.Add(new TableTransactionAction(TableTransactionActionType.UpsertReplace, currentMarker));

                if (saveHistory)
                {
                    batch.Add(new TableTransactionAction(TableTransactionActionType.Add, record));
                }

                await table.SubmitTransactionAsync(batch);
            }
            catch (Azure.Data.Tables.TableTransactionFailedException ex)
            {
                _logger.LogError($"StatusCode={ex.Status}, HttpMessage={ex.ErrorCode}");
                throw;
            }
            catch (Exception ex)
            {
                var t = ex.GetType();
                _logger.LogError(ex, "Error calling storage");
                throw;
            }

            return(nextSequenceNumber);
        }
Example #23
0
        public static async Task <T> GetEntity <T>(this TableClient table, string partitionId, string rowId) where T : class, ITableEntity, new()
        {
            var result = await table.GetEntityAsync <T>(partitionId, rowId);

            return(result?.Value);
        }
        public async Task Table_IfBoundToICollectorPoco_AddInsertsUsingNativeTableTypes()
        {
            // Arrange
            PocoWithAllTypes expected = new PocoWithAllTypes
            {
                PartitionKey                   = PartitionKey,
                RowKey                         = RowKey,
                BooleanProperty                = true,
                NullableBooleanProperty        = null,
                ByteArrayProperty              = new byte[] { 0x12, 0x34 },
                DateTimeProperty               = DateTime.UtcNow,
                NullableDateTimeProperty       = null,
                DateTimeOffsetProperty         = DateTimeOffset.MaxValue,
                NullableDateTimeOffsetProperty = null,
                DoubleProperty                 = 3.14,
                NullableDoubleProperty         = null,
                GuidProperty                   = Guid.NewGuid(),
                NullableGuidProperty           = null,
                Int32Property                  = 123,
                NullableInt32Property          = null,
                Int64Property                  = 456,
                NullableInt64Property          = null,
                StringProperty                 = "abc",
                PocoProperty                   = new Poco
                {
                    PartitionKey = "def",
                    RowKey       = "ghi",
                    Property     = "jkl"
                }
            };

            // Act
            await CallAsync <BindToICollectorPocoWithAllTypesProgram>(arguments : new
            {
                entity = expected
            });

            // Assert
            TableEntity entity = await TableClient.GetEntityAsync <TableEntity>(PartitionKey, RowKey);

            Assert.AreEqual(expected.PartitionKey, entity.PartitionKey);
            Assert.AreEqual(expected.RowKey, entity.RowKey);
            AssertNullablePropertyEqual(expected.BooleanProperty, entity, "BooleanProperty");
            AssertPropertyNull(entity, "NullableBooleanProperty");
            AssertPropertyEqual(expected.ByteArrayProperty, entity, "ByteArrayProperty");
            // TODO: behavior change. DateTime was the default type before
            AssertNullablePropertyEqual(new DateTimeOffset(expected.DateTimeProperty), entity, "DateTimeProperty");
            AssertPropertyNull(entity, "NullableDateTimeProperty");
            AssertNullablePropertyEqual(expected.DateTimeOffsetProperty, entity,
                                        "DateTimeOffsetProperty");
            AssertPropertyNull(entity, "NullableDateTimeOffsetProperty");
            AssertNullablePropertyEqual(expected.DoubleProperty, entity, "DoubleProperty");
            AssertPropertyNull(entity, "NullableDoubleProperty");
            AssertNullablePropertyEqual(expected.GuidProperty, entity, "GuidProperty");
            AssertPropertyNull(entity, "NullableGuidProperty");
            AssertNullablePropertyEqual(expected.Int32Property, entity, "Int32Property");
            AssertPropertyNull(entity, "NullableInt32Property");
            AssertNullablePropertyEqual(expected.Int64Property, entity, "Int64Property");
            AssertPropertyNull(entity, "NullableInt64Property");
            AssertPropertyEqual(expected.StringProperty, entity, "StringProperty");
            AssertPropertyEqual(JsonConvert.SerializeObject(expected.PocoProperty, Formatting.Indented),
                                entity, "PocoProperty");
        }