public async Task TestUploadBlobUsingUniversal()
        {
            // Arrange
            var urlExpected = @"https://titlestorage.xboxlive.com/universalplatform/users/xuid(2814662072777140)/scids/00000000-0000-0000-0000-0000694f5acb/data/queststatus/quest01.json,json";

            MockXboxLiveData.MockRequestData uploadRequestData = MockXboxLiveData.MockResponses["UniversalPlatformUploadBlob"];
            var titleBlobMetadata = new TitleStorageBlobMetadata(TitleStorageType.UniversalPlatform, @"queststatus/quest01.json", TitleStorageBlobType.Json);

            var uploadedQuest = new Quest
            {
                QuestName          = "Quest 01",
                CharactersInvolved = new List <string>()
                {
                    "Character 01", "Character 02", "Character 03"
                }
            };

            var testQuestJson       = JsonSerialization.ToJson(uploadedQuest);
            var blobBuffer          = Encoding.ASCII.GetBytes(testQuestJson).ToList();
            var blobQueryProperties = new BlobQueryProperties();

            // Act
            await this.titleStorageService.UploadBlobAsync(user, titleBlobMetadata, blobBuffer, blobQueryProperties);

            // Assert
            Assert.AreEqual("PUT", uploadRequestData.Request.Method);
            Assert.AreEqual(urlExpected, uploadRequestData.Request.Url);
        }
        public async Task TestDeleteBlobUsingUniversal()
        {
            // Arrange
            var urlExpected = @"https://titlestorage.xboxlive.com/universalplatform/users/xuid(2814662072777140)/scids/00000000-0000-0000-0000-0000694f5acb/data/queststatus/quest01.json,json";

            MockXboxLiveData.MockRequestData mockRequestData = MockXboxLiveData.MockResponses["UniversalPlatformDeleteBlob"];
            var titleBlobMetadata   = new TitleStorageBlobMetadata(TitleStorageType.UniversalPlatform, @"queststatus/quest01.json", TitleStorageBlobType.Json);
            var blobQueryProperties = new BlobQueryProperties();

            // Act
            await this.titleStorageService.DeleteBlobAsync(user, titleBlobMetadata, blobQueryProperties);

            // Assert
            Assert.AreEqual("DELETE", mockRequestData.Request.Method);
            Assert.AreEqual(urlExpected, mockRequestData.Request.Url);
        }
        public async Task TestUploadBlobUsingUniversalUsingBinaryAndContentLength()
        {
            // Arrange
            var url1Expected = @"https://titlestorage.xboxlive.com/universalplatform/users/xuid(2814662072777140)/scids/00000000-0000-0000-0000-0000694f5acb/data/file.bin,binary?finalBlock=True";

            MockXboxLiveData.MockRequestData uploadRequestData = MockXboxLiveData.MockResponses["UniversalPlatformUploadBinary01"];
            var titleBlobMetadata   = new TitleStorageBlobMetadata(TitleStorageType.UniversalPlatform, @"file.bin", TitleStorageBlobType.Binary);
            var longText            = "< p >Lorem ipsum dolor sit amet, netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante.Donec eu libero sit amet quam egestas semper. Aenean";
            var blobBuffer          = Encoding.ASCII.GetBytes(longText).ToList();
            var blobQueryProperties = new BlobQueryProperties();

            // Act
            await this.titleStorageService.UploadBlobAsync(user, titleBlobMetadata, blobBuffer, blobQueryProperties);

            // Assert
            Assert.AreEqual("PUT", uploadRequestData.Request.Method);
            Assert.AreEqual(url1Expected, uploadRequestData.Request.Url);
        }
        public async Task TestDownloadBlobUsingUniversal()
        {
            // Arrange
            var urlExpected = @"https://titlestorage.xboxlive.com/universalplatform/users/xuid(2814662072777140)/scids/00000000-0000-0000-0000-0000694f5acb/data/queststatus/quest01.json,json";

            MockXboxLiveData.MockRequestData mockRequestData = MockXboxLiveData.MockResponses["UniversalPlatformDownloadBlob"];
            var responseJson        = JObject.Parse(mockRequestData.Response.ResponseBodyString);
            var titleBlobMetadata   = new TitleStorageBlobMetadata(TitleStorageType.UniversalPlatform, @"queststatus/quest01.json", TitleStorageBlobType.Json);
            var blobQueryProperties = new BlobQueryProperties();

            // Act
            var downloadBlobResult = await this.titleStorageService.DownloadBlobAsync(user, titleBlobMetadata, blobQueryProperties);

            var downloadBlobString = Encoding.Default.GetString(downloadBlobResult.BlobBuffer.ToArray());
            var downloadedQuest    = JsonSerialization.FromJson <Quest>(downloadBlobString);

            // Assert
            Assert.AreEqual("GET", mockRequestData.Request.Method);
            Assert.AreEqual(urlExpected, mockRequestData.Request.Url);
            VerifyDownloadQuest(downloadedQuest, responseJson);
        }
        /// <summary>
        /// Deletes a blob from title storage.
        /// </summary>
        /// <param name="user">The Xbox User of the title storage to enumerate. Ignored when enumerating GlobalStorage.</param>
        /// <param name="blobMetadata">The blob metadata for the title storage blob to delete.</param>
        /// <param name="blobQueryProperties">An instance of the <see cref="BlobQueryProperties"/> class with properties of the download query.</param>
        /// <returns>An empty task.</returns>
        public Task DeleteBlobAsync(XboxLiveUser user, TitleStorageBlobMetadata blobMetadata, BlobQueryProperties blobQueryProperties)
        {
            var eTagMatchCondition = blobQueryProperties.ETagMatchCondition == TitleStorageETagMatchCondition.IfMatch ?
                                     TitleStorageETagMatchCondition.IfMatch : TitleStorageETagMatchCondition.NotUsed;
            var subPathAndQueryResult = this.GetTitleStorageBlobMetadataDownloadSubpath(user, blobMetadata, string.Empty);

            if (string.IsNullOrEmpty(subPathAndQueryResult))
            {
                return(Task.FromResult <object>(null));
            }

            var httpRequest = XboxLiveHttpRequest.Create(HttpMethod.Delete, TitleStorageBaseUri.ToString(), subPathAndQueryResult);

            httpRequest.ContractVersion = TitleStorageApiContract;
            httpRequest.ContentType     = ContentTypeHeaderValue;
            httpRequest.XboxLiveAPI     = XboxLiveAPIName.DeleteBlob;

            SetEtagHeader(httpRequest, blobMetadata.ETag, eTagMatchCondition);
            return(httpRequest.GetResponseWithAuth(user).ContinueWith(responseTask =>
            {
                if (responseTask.Result.ErrorCode != 0)
                {
                    throw new Exception("Invalid HTTP received on delete. Error Message: " + responseTask.Result.ErrorMessage);
                }
            }));
        }
        /// <summary>
        /// Upload blob data to title storage.
        /// </summary>
        /// <param name="user">The Xbox User of the title storage to enumerate. Ignored when enumerating GlobalStorage.</param>
        /// <param name="blobMetadata">The blob metadata for the title storage blob to upload.</param>
        /// <param name="blobBuffer">The Blob content to be uploaded.</param>
        /// <param name="blobQueryProperties">An instance of the <see cref="BlobQueryProperties"/> class with properties of the upload query.</param>
        /// <returns>An instance of the <see cref="TitleStorageBlobMetadata"/> class with updated ETag and Length Properties.</returns>
        public Task <TitleStorageBlobMetadata> UploadBlobAsync(XboxLiveUser user, TitleStorageBlobMetadata blobMetadata, List <byte> blobBuffer, BlobQueryProperties blobQueryProperties)
        {
            if (blobBuffer == null)
            {
                throw new Exception("Blob buffer is null");
            }

            if (blobBuffer.Count == 0)
            {
                throw new Exception("Blob Buffer is empty");
            }

            var preferredUploadBlockSize = blobQueryProperties.PreferredBlockSize < MinUploadBlockSize ? MinUploadBlockSize : blobQueryProperties.PreferredBlockSize;

            preferredUploadBlockSize = blobQueryProperties.PreferredBlockSize > MaxUploadBlockSize ? MaxUploadBlockSize : preferredUploadBlockSize;

            var resultBlocBlobMetadata = new TitleStorageBlobMetadata(blobMetadata.StorageType, blobMetadata.BlobPath,
                                                                      blobMetadata.BlobType, blobMetadata.DisplayName, blobMetadata.ETag);

            var isBinaryData = (blobMetadata.BlobType == TitleStorageBlobType.Binary);

            var  dataChunk         = new List <byte>();
            uint start             = 0;
            var  continuationToken = string.Empty;

            while (start < blobBuffer.Count)
            {
                dataChunk.Clear();
                bool isFinalBlock;
                if (isBinaryData)
                {
                    var count = (uint)(blobBuffer.Count) - start;
                    if (count > preferredUploadBlockSize)
                    {
                        count = preferredUploadBlockSize;
                    }

                    for (var index = 0; index < count; index++)
                    {
                        dataChunk.Add(blobBuffer[(int)(index + start)]);
                    }

                    start       += count;
                    isFinalBlock = start == blobBuffer.Count;
                }
                else
                {
                    dataChunk    = blobBuffer;
                    start        = (uint)(dataChunk.Count);
                    isFinalBlock = true;
                }

                var subpathAndQueryResult = this.GetTitleStorageBlobMetadataUploadSubpath(user, blobMetadata, continuationToken, isFinalBlock);
                var httpRequest           = XboxLiveHttpRequest.Create(HttpMethod.Put, TitleStorageBaseUri.ToString(), subpathAndQueryResult);
                httpRequest.ContractVersion = TitleStorageApiContract;
                httpRequest.ContentType     = ContentTypeHeaderValue;
                httpRequest.LongHttpCall    = true;

                SetEtagHeader(httpRequest, blobMetadata.ETag, blobQueryProperties.ETagMatchCondition);
                var encoding = Encoding.UTF8;
                httpRequest.RequestBody  = encoding.GetString(dataChunk.ToArray());
                httpRequest.XboxLiveAPI  = XboxLiveAPIName.UploadBlob;
                httpRequest.RetryAllowed = false;

                var localIsFinalBlock = isFinalBlock;
                httpRequest.GetResponseWithAuth(user).ContinueWith(responseTask =>
                {
                    var json          = responseTask.Result.ResponseBodyString;
                    continuationToken = string.Empty;
                    if (responseTask.Result.ErrorCode == 0 && !string.IsNullOrEmpty(json))
                    {
                        var pagingInfo    = JsonSerialization.FromJson <PagingInfo>(json);
                        continuationToken = pagingInfo.ContinuationToken;
                    }

                    if (responseTask.Result.ErrorCode == 0 && localIsFinalBlock)
                    {
                        resultBlocBlobMetadata.SetBlobMetadataProperties((uint)(blobBuffer.Count), responseTask.Result.ETag);
                    }
                }).Wait();
            }
            return(Task.FromResult(resultBlocBlobMetadata));
        }
        /// <summary>
        /// Downloads blob data from title storage.
        /// </summary>
        /// <param name="user">The Xbox User of the title storage to enumerate. Ignored when enumerating GlobalStorage.</param>
        /// <param name="blobMetadata">The blob metadata for the title storage blob to download.</param>
        /// <param name="blobQueryProperties">An instance of the <see cref="BlobQueryProperties"/> class with properties of the download query.</param>
        /// <returns>An instance of the <see cref="TitleStorageBlobResult"/> containing the blob content and an updated
        /// <see cref="TitleStorageBlobMetadata"/> object.</returns>
        public Task <TitleStorageBlobResult> DownloadBlobAsync(
            XboxLiveUser user,
            TitleStorageBlobMetadata blobMetadata,
            BlobQueryProperties blobQueryProperties)
        {
            var blobBuffer = new List <byte>();

            var resultBlocBlobMetadata = new TitleStorageBlobMetadata(
                blobMetadata.StorageType, blobMetadata.BlobPath,
                blobMetadata.BlobType, blobMetadata.DisplayName, blobMetadata.ETag);

            var preferredDownloadBlockSize =
                blobQueryProperties.PreferredBlockSize < MinDownloadBlockSize ?
                MinDownloadBlockSize :
                blobQueryProperties.PreferredBlockSize;

            var  isBinaryData  = (blobMetadata.BlobType == TitleStorageBlobType.Binary);
            var  isDownloading = true;
            uint startByte     = 0;

            var subPathAndQueryResult = this.GetTitleStorageBlobMetadataDownloadSubpath(
                user, blobMetadata, blobQueryProperties.SelectQuery);

            while (isDownloading)
            {
                var httpRequest = XboxLiveHttpRequest.Create(HttpMethod.Get, TitleStorageBaseUri.ToString(), subPathAndQueryResult);
                httpRequest.ContractVersion  = TitleStorageApiContract;
                httpRequest.ContentType      = ContentTypeHeaderValue;
                httpRequest.LongHttpCall     = true;
                httpRequest.ResponseBodyType = HttpCallResponseBodyType.VectorBody;

                SetEtagHeader(httpRequest, blobMetadata.ETag, blobQueryProperties.ETagMatchCondition);

                if (isBinaryData)
                {
                    httpRequest.SetRangeHeader(startByte, startByte + preferredDownloadBlockSize);
                }

                httpRequest.XboxLiveAPI = XboxLiveAPIName.DownloadBlob;
                httpRequest.GetResponseWithAuth(user).ContinueWith(responseTask =>
                {
                    var response = responseTask.Result;
                    if (response.ErrorCode == 0)
                    {
                        var responseVector = response.ResponseBodyVector;
                        if (responseVector.Length > 0)
                        {
                            blobBuffer.AddRange(responseVector);
                        }

                        startByte += (uint)responseVector.Length;
                        if (!isBinaryData || responseVector.Length < preferredDownloadBlockSize)
                        {
                            isDownloading = false;
                            resultBlocBlobMetadata.SetBlobMetadataProperties((uint)(responseVector.Length), response.ETag);
                        }
                    }
                }).Wait();
            }

            var resultBlobMetadataResult = new TitleStorageBlobResult(resultBlocBlobMetadata, blobBuffer.ToArray());

            return(Task.FromResult(resultBlobMetadataResult));
        }