public override async Task <bool> DeleteAsync(string id)
        {
            if (id == null)
            {
                throw new ArgumentNullException("id");
            }

            CompositeTableKey key = this.GetStorageKey(id);

            TableOperation operation = null;
            TData          data      = await this.GetCurrentItem(key, includeDeleted : !this.IncludeDeleted);

            if (this.EnableSoftDelete)
            {
                data.Deleted = true;
                operation    = TableOperation.Merge(data);
            }
            else
            {
                operation = TableOperation.Delete(data);
            }

            bool deleted = false;

            if (operation != null)
            {
                await this.ExecuteOperationAsync(operation, OperationType.Delete);

                deleted = true;
            }

            return(deleted);
        }
Exemple #2
0
        public async Task LookupAsync_DoesNotCreateStorageTable()
        {
            // Behavior is same for Delete, Undelete, Update and Lookup which each depend on GetCurrentItem
            var isolatedManager = new StorageDomainManagerMock(this, "lookupTableNotFound");

            try
            {
                await isolatedManager.Table.DeleteIfExistsAsync();

                Assert.False(isolatedManager.Table.Exists());

                string id = new CompositeTableKey("unknown", "item").ToString();
                HttpResponseException ex = await AssertEx.ThrowsAsync <HttpResponseException>(async() => await isolatedManager.LookupAsync(id));

                Assert.Equal(HttpStatusCode.NotFound, ex.Response.StatusCode);

                // Table.ExecuteAsync for retrieve returns TableResult with 404 status code when table is not found
                // instead of throwing exception. As a result, the lookup fails fast and we do not create the table.
                Assert.False(isolatedManager.Table.Exists());
            }
            finally
            {
                isolatedManager.Dispose();
            }
        }
Exemple #3
0
        public async Task LookupAsync_ReturnsSoftDeletedRecord_IfIncludeDeletedIsTrue()
        {
            // Arrange
            Person person = TestData.Persons.First();

            person.PartitionKey = person.LastName;
            person.RowKey       = person.FirstName;
            person.CreatedAt    = null;
            person.UpdatedAt    = null;

            await this.manager.InsertAsync(person);

            this.manager.EnableSoftDelete = true;
            bool result = await this.manager.DeleteAsync(person.Id);

            // Act
            this.manager.IncludeDeleted = true;
            CompositeTableKey id       = new CompositeTableKey(person.LastName, person.FirstName);
            Person            lookedup = (await this.manager.LookupAsync(id.ToString())).Queryable.First();

            // Assert
            Assert.Equal(person.Id, lookedup.Id);
            Assert.Equal(true, lookedup.Deleted);
            Assert.Equal(person.FirstName, lookedup.FirstName);
            Assert.Equal(person.LastName, lookedup.LastName);
        }
Exemple #4
0
        public void Parse_SucceedsOnValidKeys(string key, string[] expectedSubkeys)
        {
            // Act
            CompositeTableKey tableKey = CompositeTableKey.Parse(key);

            // Assert
            Assert.Equal(expectedSubkeys, tableKey.Segments);
        }
Exemple #5
0
        public async Task ConvertStorageException_BadRequest_IfInvalidErrorType()
        {
            CompositeTableKey key = new CompositeTableKey("KeyPart1", "KeyPart2");
            StorageException  storageException = new StorageException("ConvertStorageException invalid error type test", null);

            HttpResponseException ex = await this.manager.ConvertStorageException(storageException, key);

            Assert.Equal(HttpStatusCode.BadRequest, ex.Response.StatusCode);
        }
Exemple #6
0
        public async Task UndeleteAsync_ThrowsNotFound_IfIdNotFound()
        {
            string id = new CompositeTableKey("unknown", "item").ToString();

            // Act/Assert
            HttpResponseException ex = await AssertEx.ThrowsAsync <HttpResponseException>(async() => await this.manager.UndeleteAsync(id, null));

            Assert.Equal(HttpStatusCode.NotFound, ex.Response.StatusCode);
        }
 private void VerifyUpdatedKey(CompositeTableKey key, TData data)
 {
     if (data == null || data.PartitionKey != key.Segments[0] || data.RowKey != key.Segments[1])
     {
         string msg = ASResources.TableController_KeyMismatch.FormatForUser("Id", key.ToString(), data.Id);
         HttpResponseMessage badKey = this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
         throw new HttpResponseException(badKey);
     }
 }
Exemple #8
0
        public void TryParse_FailsOnInvalidKeys(string key)
        {
            // Act
            CompositeTableKey tableKey;
            bool result = CompositeTableKey.TryParse(key, out tableKey);

            // Assert
            Assert.False(result);
            Assert.Null(tableKey);
        }
Exemple #9
0
        public void TryParse_SucceedsOnValidKeys(string key, string[] expectedSegments)
        {
            // Act
            CompositeTableKey tableKey;
            bool result = CompositeTableKey.TryParse(key, out tableKey);

            // Assert
            Assert.True(result);
            Assert.Equal(expectedSegments, tableKey.Segments);
        }
Exemple #10
0
        public async Task ReplaceAsync_Throws_BadRequestIfIdNotFound()
        {
            // Arrange
            string id     = new CompositeTableKey("unknown", "item").ToString();
            Person person = new Person();

            // Act/Assert
            HttpResponseException ex = await AssertEx.ThrowsAsync <HttpResponseException>(async() => await this.manager.ReplaceAsync(id, person));

            Assert.Equal(HttpStatusCode.BadRequest, ex.Response.StatusCode);
        }
Exemple #11
0
        public void ToString_GeneratesCorrectTableKey(string[] segments, string expectedKey)
        {
            // Arrange
            CompositeTableKey tableKey = new CompositeTableKey(segments);

            // Act
            string actualTableKey = tableKey.ToString();

            // Assert
            Assert.Equal(expectedKey, actualTableKey);
        }
        private async Task <TData> LookupItemAsync(string id)
        {
            if (id == null)
            {
                throw new ArgumentNullException("id");
            }

            CompositeTableKey key  = this.GetStorageKey(id);
            TData             data = await this.GetCurrentItem(key, this.IncludeDeleted);

            return(data);
        }
Exemple #13
0
        public void ToStringAndParse_Roundtrips(string[] expectedSegments)
        {
            // Arrange
            CompositeTableKey tableKey = new CompositeTableKey(expectedSegments);

            // Act
            string actualTableKey = tableKey.ToString();
            IEnumerable <string> actualSubkeys = CompositeTableKey.Parse(actualTableKey).Segments;

            // Assert
            Assert.Equal(expectedSegments, actualSubkeys);
        }
Exemple #14
0
 /// <summary>
 /// Attempts creating a new <see cref="CompositeTableKey"/> from a given <paramref name="tableKey"/>.
 /// The return value indicates whether the parsing succeeded.
 /// </summary>
 /// <param name="tableKey">The value containing the composite key.</param>
 /// <param name="compositeTableKey">If the method returns <c>true</c> then <paramref name="compositeTableKey"/> contains the result; otherwise <c>null</c>.</param>
 /// <returns></returns>
 public static bool TryParse(string tableKey, out CompositeTableKey compositeTableKey)
 {
     try
     {
         compositeTableKey = Parse(tableKey);
         return(true);
     }
     catch
     {
         compositeTableKey = null;
         return(false);
     }
 }
 /// <summary>
 /// Attempts creating a new <see cref="CompositeTableKey"/> from a given <paramref name="tableKey"/>.
 /// The return value indicates whether the parsing succeeded.
 /// </summary>
 /// <param name="tableKey">The value containing the composite key.</param>
 /// <param name="compositeTableKey">If the method returns <c>true</c> then <paramref name="compositeTableKey"/> contains the result; otherwise <c>null</c>.</param>
 /// <returns></returns>
 public static bool TryParse(string tableKey, out CompositeTableKey compositeTableKey)
 {
     try
     {
         compositeTableKey = Parse(tableKey);
         return true;
     }
     catch
     {
         compositeTableKey = null;
         return false;
     }
 }
Exemple #16
0
        public async Task LookupAsync_ReturnsData()
        {
            // Arrange
            Collection <Person> persons = TestData.Persons;

            await this.InsertPersons(persons);

            CompositeTableKey id = new CompositeTableKey("Nielsen", "Henrik");

            // Act
            SingleResult <Person> actual = await this.manager.LookupAsync(id.ToString());

            // Assert
            Assert.Equal("Henrik", actual.Queryable.First().FirstName);
        }
Exemple #17
0
        public async Task UpdateAsync_Throws_NotFoundIfIdNotFound()
        {
            // Arrange
            string         id    = new CompositeTableKey("unknown", "item").ToString();
            Delta <Person> patch = new Delta <Person>();

            // Act/Assert
            this.manager.IncludeDeleted = false;
            HttpResponseException ex = await AssertEx.ThrowsAsync <HttpResponseException>(async() => await this.manager.UpdateAsync(id, patch));

            Assert.Equal(HttpStatusCode.NotFound, ex.Response.StatusCode);

            this.manager.IncludeDeleted = true;
            ex = await AssertEx.ThrowsAsync <HttpResponseException>(async() => await this.manager.UpdateAsync(id, patch));

            Assert.Equal(HttpStatusCode.NotFound, ex.Response.StatusCode);
        }
        private async Task <TData> GetCurrentItem(CompositeTableKey key, bool includeDeleted)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            TableOperation query = TableOperation.Retrieve <TData>(key.Segments[0], key.Segments[1]);
            TData          item  = await this.ExecuteOperationAsync(query, OperationType.Read);

            if (item == null || (!includeDeleted && item.Deleted))
            {
                throw new HttpResponseException(this.Request.CreateNotFoundResponse());
            }

            return(item);
        }
        protected virtual CompositeTableKey GetStorageKey(string id)
        {
            if (id == null)
            {
                throw new ArgumentNullException("id");
            }

            CompositeTableKey compositeKey;

            if (!CompositeTableKey.TryParse(id, out compositeKey) || compositeKey.Segments.Count != 2)
            {
                // We have either invalid, no keys, or too many keys
                string error = ASResources.StorageTable_InvalidKey.FormatForUser(id);
                throw new HttpResponseException(this.Request.CreateBadRequestResponse(error));
            }

            return(compositeKey);
        }
        protected virtual CompositeTableKey GetCompositeKey(string id)
        {
            if (id == null)
            {
                throw new ArgumentNullException("id");
            }

            CompositeTableKey compositeKey;

            if (CompositeTableKey.TryParse(id, out compositeKey))
            {
                return(compositeKey);
            }

            string error = EFResources.TableKeys_InvalidKey.FormatForUser(id);

            throw new HttpResponseException(this.Request.CreateNotFoundResponse(error));
        }
        public override async Task <TData> ReplaceAsync(string id, TData data)
        {
            if (id == null)
            {
                throw new ArgumentNullException("id");
            }

            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            CompositeTableKey key = this.GetStorageKey(id);

            this.VerifyUpdatedKey(key, data);
            data.CreatedAt = DateTimeOffset.UtcNow;

            TableOperation replace = TableOperation.Replace(data);

            return(await this.ExecuteOperationAsync(replace, OperationType.Replace));
        }
        private async Task <TData> UpdateAsync(string id, Delta <TData> patch, bool includeDeleted, OperationType operationType)
        {
            if (id == null)
            {
                throw new ArgumentNullException("id");
            }

            if (patch == null)
            {
                throw new ArgumentNullException("patch");
            }

            CompositeTableKey key     = this.GetStorageKey(id);
            TData             current = await this.GetCurrentItem(key, includeDeleted);

            patch.Patch(current);
            this.VerifyUpdatedKey(key, current);

            TableOperation update = TableOperation.Merge(current);

            return(await this.ExecuteOperationAsync(update, operationType, key));
        }
Exemple #23
0
        public async Task LookupAsync_DoesNotReturnSoftDeletedRecord_IfIncludeDeletedIsFalse()
        {
            // Arrange
            Person person = TestData.Persons.First();

            person.PartitionKey = person.LastName;
            person.RowKey       = person.FirstName;
            person.CreatedAt    = null;
            person.UpdatedAt    = null;

            await this.manager.InsertAsync(person);

            this.manager.EnableSoftDelete = true;
            bool result = await this.manager.DeleteAsync(person.Id);

            // Act
            this.manager.IncludeDeleted = false;
            CompositeTableKey     id = new CompositeTableKey(person.LastName, person.FirstName);
            HttpResponseException ex = await AssertEx.ThrowsAsync <HttpResponseException>(async() => await this.manager.LookupAsync(id.ToString()));

            Assert.Equal(HttpStatusCode.NotFound, ex.Response.StatusCode);
        }
        private async Task <TData> ExecuteOperationAsync(TableOperation operation, OperationType operationType, CompositeTableKey key = null, bool createTable = false)
        {
            StorageException storageException = null;

            try
            {
                if (createTable)
                {
                    await this.Table.CreateIfNotExistsAsync();
                }

                var tableResult = await this.Table.ExecuteAsync(operation);

                return(tableResult.Result as TData);
            }
            catch (StorageException exception)
            {
                storageException = exception;
            }

            if (TableResponseNotFound(storageException) && !createTable)
            {
                return(await this.ExecuteOperationAsync(operation, operationType, key, createTable : true));
            }
            else
            {
                throw await this.ConvertStorageException(storageException, key);
            }
        }
        internal async Task <HttpResponseException> ConvertStorageException(StorageException exception, CompositeTableKey key)
        {
            if (exception == null)
            {
                throw new ArgumentNullException("exception");
            }

            ITraceWriter        traceWriter = this.Request.GetConfiguration().Services.GetTraceWriter();
            HttpResponseMessage error       = null;

            if ((exception.RequestInformation != null) && (exception.RequestInformation.ExtendedErrorInformation != null))
            {
                string message = CommonResources.DomainManager_Conflict.FormatForUser(exception.RequestInformation.ExtendedErrorInformation.ErrorMessage);
                traceWriter.Info(message, this.Request, LogCategories.TableControllers);

                if (exception.RequestInformation.ExtendedErrorInformation.ErrorCode == TableErrorCodeStrings.EntityAlreadyExists)
                {
                    error = this.Request.CreateErrorResponse(HttpStatusCode.Conflict, message);
                }
                else if (exception.RequestInformation.ExtendedErrorInformation.ErrorCode == StorageErrorCodeStrings.ConditionNotMet ||
                         exception.RequestInformation.ExtendedErrorInformation.ErrorCode == TableErrorCodeStrings.UpdateConditionNotSatisfied)
                {
                    // the two values above indicate that the etag doesn't match, but the error thrown from the emulator
                    // is different from that in the service, so both must be included

                    var content = await this.GetCurrentItem(key);

                    error = this.Request.CreateResponse(HttpStatusCode.PreconditionFailed, content);
                }
                else if (exception.RequestInformation.ExtendedErrorInformation.ErrorCode == StorageErrorCodeStrings.ResourceNotFound)
                {
                    error = this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                }
            }

            if (error == null)
            {
                string message = ASResources.DomainManager_InvalidOperation.FormatForUser(exception.Message);
                error = this.Request.CreateBadRequestResponse(message);
                traceWriter.Error(message, this.Request, LogCategories.TableControllers);
            }

            return(new HttpResponseException(error));
        }
 protected virtual Task <TData> GetCurrentItem(CompositeTableKey key)
 {
     return(this.GetCurrentItem(key, this.IncludeDeleted));
 }
        public void ToStringAndParse_Roundtrips(string[] expectedSegments)
        {
            // Arrange
            CompositeTableKey tableKey = new CompositeTableKey(expectedSegments);

            // Act
            string actualTableKey = tableKey.ToString();
            IEnumerable<string> actualSubkeys = CompositeTableKey.Parse(actualTableKey).Segments;

            // Assert
            Assert.Equal(expectedSegments, actualSubkeys);
        }
        public void ToString_GeneratesCorrectTableKey(string[] segments, string expectedKey)
        {
            // Arrange
            CompositeTableKey tableKey = new CompositeTableKey(segments);

            // Act
            string actualTableKey = tableKey.ToString();

            // Assert
            Assert.Equal(expectedKey, actualTableKey);
        }
Exemple #29
0
 public void Parse_ThrowsOnInvalidKeys(string key)
 {
     Assert.Throws <ArgumentException>(() => CompositeTableKey.Parse(key));
 }