/// <summary> /// Callback used when the BackgroundUploadResponseHandler finishes with an error. /// </summary> /// <param name="exception">The exception from the BackgroundUploadResponseHandler.</param> public void OnError(Exception exception) { var e = new LiveConnectException(ApiOperation.ApiClientErrorCode, ResourceHelper.GetString("BackgroundUploadResponseHandlerError"), exception); this.tcs.TrySetException(e); }
/// <summary> /// Called when a BackgroundTransferRequest's TransferStatus is set to Completed. /// This method will remove the request from the BackgroundTransferService and convert /// the result over to a LiveOperationResult and set it on the TaskCompletionSource. /// </summary> /// <param name="request"></param> private void OnTransferStatusComplete(BackgroundTransferRequest request) { Debug.Assert(request.TransferStatus == TransferStatus.Completed); Debug.Assert(BackgroundTransferHelper.IsUploadRequest(request)); // Remove the transfer request in order to make room in the queue for more transfers. // Transfers are not automatically removed by the system. // Cancelled requests have already been removed from the system and cannot be removed twice. if (!BackgroundTransferHelper.IsCanceledRequest(request)) { try { this.backgroundTransferService.Remove(request); } catch (Exception exception) { this.tcs.TrySetException(new LiveConnectException( ApiOperation.ApiClientErrorCode, ResourceHelper.GetString("BackgroundTransferServiceRemoveError"), exception)); return; } } this.OnBackgroundTransferRequestCompleted(request); if (request.TransferError != null) { var exception = new LiveConnectException(ApiOperation.ApiServerErrorCode, ResourceHelper.GetString("ServerError"), request.TransferError); this.tcs.TrySetException(exception); return; } if (!BackgroundTransferHelper.IsSuccessfulStatusCode(request.StatusCode)) { var exception = new LiveConnectException(ApiOperation.ApiServerErrorCode, ResourceHelper.GetString("ServerError")); this.tcs.TrySetException(exception); return; } // Once we know we have a *good* upload, we have to send it to the response handler // to read it's JSON response body. We are an observer to this class, so it will call us back // with its result. var responseHandler = new BackgroundUploadResponseHandler( request.DownloadLocation, this); responseHandler.ReadJsonResponseFromDownloadLocation(); }
/// <summary> /// Called when a BackgroundTransferRequet's TransferStatus is set to Completed. /// This method will remove the request from the BackgroundTransferService and call /// the LiveOperationEventArgs event handler. /// </summary> /// <param name="request">request with a TransferStatus that is set to Completed</param> private void OnTransferStatusComplete(BackgroundTransferRequest request) { Debug.Assert(request.TransferStatus == TransferStatus.Completed); Debug.Assert(BackgroundTransferHelper.IsDownloadRequest(request)); this.OnBackgroundTransferRequestCompleted(request); // Remove the transfer request in order to make room in the queue for more transfers. // Transfers are not automatically removed by the system. // Cancelled requests have already been removed from the system and cannot be removed twice. if (!BackgroundTransferHelper.IsCanceledRequest(request)) { try { this.backgroundTransferService.Remove(request); } catch (Exception exception) { this.tcs.TrySetException(new LiveConnectException( ApiOperation.ApiClientErrorCode, ResourceHelper.GetString("BackgroundTransferServiceRemoveError"), exception)); return; } } if (request.TransferError != null) { var exception = new LiveConnectException(ApiOperation.ApiServerErrorCode, ResourceHelper.GetString("ServerError"), request.TransferError); this.tcs.TrySetException(exception); } else if (!BackgroundTransferHelper.IsSuccessfulStatusCode(request.StatusCode)) { var exception = new LiveConnectException(ApiOperation.ApiServerErrorCode, ResourceHelper.GetString("ServerError")); this.tcs.TrySetException(exception); } else { string jsonResponse = string.Format(JsonResponse, request.DownloadLocation.OriginalString.Replace("\\", "\\\\")); var jsonReader = new JsonReader(jsonResponse); var jsonObject = jsonReader.ReadValue() as IDictionary <string, object>; var result = new LiveOperationResult(jsonObject, jsonResponse); this.tcs.TrySetResult(result); } }
/// <summary> /// Parses a string response body and creates a LiveOperationResult object from it. /// </summary> internal static LiveOperationResult CreateOperationResultFrom(string responseBody, ApiMethod method) { if (string.IsNullOrEmpty(responseBody)) { if (method != ApiMethod.Delete) { var error = new LiveConnectException( ApiClientErrorCode, ResourceHelper.GetString("NoResponseData")); return(new LiveOperationResult(error, false)); } return(new LiveOperationResult(null, responseBody)); } return(LiveOperationResult.FromResponse(responseBody)); }
/// <summary> /// Parses a string response body and creates a LiveOperationResult object from it. /// </summary> protected LiveOperationResult CreateOperationResultFrom(string responseBody) { if (string.IsNullOrEmpty(responseBody)) { if (this.Method != ApiMethod.Delete) { var error = new LiveConnectException( ApiClientErrorCode, ResourceHelper.GetString("NoResponseData")); return(new LiveOperationResult(error, false)); } return(new LiveOperationResult(new DynamicDictionary(), responseBody)); } return(LiveOperationResult.FromResponse(responseBody)); }
/// <summary> /// Process the error response. /// </summary> private async Task <LiveDownloadOperationResult> ProcessDownloadErrorResponse(Exception exception) { LiveDownloadOperationResult opResult; try { IInputStream responseStream = this.downloadOp.GetResultStreamAt(0); if (responseStream == null) { var error = new LiveConnectException( ApiOperation.ApiServerErrorCode, ResourceHelper.GetString("ConnectionError")); opResult = new LiveDownloadOperationResult(error, false); } else { var reader = new DataReader(responseStream); uint length = await reader.LoadAsync(TailoredDownloadOperation.MaxDownloadResponseLength); Exception error = CreateOperationResultFrom(reader.ReadString(length), this.Method).Error; if (error is FormatException) { // if we cannot understand the error response, // return the exception thrown by the background downloader. error = exception; } opResult = new LiveDownloadOperationResult(error, false); } } catch (COMException exp) { opResult = new LiveDownloadOperationResult(exp, false); } catch (FileNotFoundException exp) { opResult = new LiveDownloadOperationResult(exp, false); } return(opResult); }
/// <summary> /// Handles the refresh token completed event. Restarts the operation. /// </summary> private void OnRefreshTokenOperationCompleted(LiveLoginResult result) { switch (result.Status) { case LiveConnectSessionStatus.Connected: this.LiveClient.Session = result.Session; break; case LiveConnectSessionStatus.Unknown: // Once we know the user is unknown, we clear the session and fail the operation. // On Windows Blue, the user may disconnect the Microsoft account. // We ensure we are not allowing app to continue to access user's data after the user disconnects the account. this.LiveClient.Session = null; var error = new LiveConnectException(ApiOperation.ApiClientErrorCode, ResourceHelper.GetString("UserNotLoggedIn")); this.OnOperationCompleted(new LiveOperationResult(error, false)); return; } // We will attempt to perform the operation even if refresh fails. this.InternalExecute(); }
protected override void OnWebResponseReceived(WebResponse response) { LiveOperationResult opResult = this.CreateOperationResultFrom(response); if (opResult.Error != null) { this.OnOperationCompleted(opResult); return; } string uploadLink = null; if (opResult.Result != null && opResult.Result.ContainsKey(UploadLocationKey)) { uploadLink = opResult.Result[UploadLocationKey] as string; } if (string.IsNullOrEmpty(uploadLink)) { var error = new LiveConnectException(ApiOperation.ApiClientErrorCode, ResourceHelper.GetString("NoUploadLinkFound")); opResult = new LiveOperationResult(error, false); } else { try { Uri resourceUploadUrl = this.ConstructUploadUri(uploadLink); opResult = new LiveOperationResult(null, resourceUploadUrl.OriginalString); } catch (LiveConnectException exp) { opResult = new LiveOperationResult(exp, false); } } this.OnOperationCompleted(opResult); }
/// <summary> /// Parses the WebResponse's body and creates a LiveOperationResult object from it. /// </summary> protected LiveOperationResult CreateOperationResultFrom(WebResponse response) { LiveOperationResult opResult; bool nullResponse = (response == null); try { Stream responseStream = (!nullResponse) ? response.GetResponseStream() : null; if (nullResponse || responseStream == null) { var error = new LiveConnectException( ApiOperation.ApiClientErrorCode, ResourceHelper.GetString("ConnectionError")); opResult = new LiveOperationResult(error, false); } else { using (var sr = new StreamReader(responseStream)) { string rawResult = sr.ReadToEnd(); opResult = CreateOperationResultFrom(rawResult, this.Method); } } } finally { if (!nullResponse) { ((IDisposable)response).Dispose(); } } return(opResult); }
/// <summary> /// Parses a string response body and creates a LiveOperationResult object from it. /// </summary> protected LiveOperationResult CreateOperationResultFrom(string responseBody) { if (string.IsNullOrEmpty(responseBody)) { if (this.Method != ApiMethod.Delete) { var error = new LiveConnectException( ApiClientErrorCode, ResourceHelper.GetString("NoResponseData")); return new LiveOperationResult(error, false); } return new LiveOperationResult(new DynamicDictionary(), responseBody); } return LiveOperationResult.FromResponse(responseBody); }
/// <summary> /// Parses the WebResponse's body and creates a LiveOperationResult object from it. /// </summary> protected LiveOperationResult CreateOperationResultFrom(WebResponse response) { LiveOperationResult opResult; bool nullResponse = (response == null); try { Stream responseStream = (!nullResponse) ? response.GetResponseStream() : null; if (nullResponse || responseStream == null) { var error = new LiveConnectException( ApiOperation.ApiClientErrorCode, ResourceHelper.GetString("ConnectionError")); opResult = new LiveOperationResult(error, false); } else { using (var sr = new StreamReader(responseStream)) { string rawResult = sr.ReadToEnd(); opResult = this.CreateOperationResultFrom(rawResult); } } } finally { if (!nullResponse) { ((IDisposable)response).Dispose(); } } return opResult; }
/// <summary> /// Callback used when the BackgroundUploadResponseHandler finishes with an error in the json response. /// This method will conver the error result into a LiveCompletedEventArgs and call OnCompleted. /// </summary> /// <param name="code">The error code from the error.</param> /// <param name="message">The error message from the error.</param> public void OnErrorResponse(string code, string message) { var exception = new LiveConnectException(code, message); this.tcs.TrySetException(exception); }
private async void OnGetUploadLinkCompleted(LiveOperationResult result) { if (this.Status == OperationStatus.Cancelled) { base.OnCancel(); return; } if (result.Error != null || result.IsCancelled) { this.OnOperationCompleted(result); return; } var uploadUrl = new Uri(result.RawResult, UriKind.Absolute); // NOTE: the GetUploadLinkOperation will return a uri with the overwite, suppress_response_codes, // and suppress_redirect query parameters set. Debug.Assert(uploadUrl.Query != null); Debug.Assert(uploadUrl.Query.Contains(QueryParameters.Overwrite)); Debug.Assert(uploadUrl.Query.Contains(QueryParameters.SuppressRedirects)); Debug.Assert(uploadUrl.Query.Contains(QueryParameters.SuppressResponseCodes)); var uploader = new BT.BackgroundUploader(); uploader.Group = LiveConnectClient.LiveSDKUploadGroup; if (this.LiveClient.Session != null) { uploader.SetRequestHeader( ApiOperation.AuthorizationHeader, AuthConstants.BearerTokenType + " " + this.LiveClient.Session.AccessToken); } uploader.SetRequestHeader(ApiOperation.LibraryHeader, Platform.GetLibraryHeaderValue()); uploader.Method = HttpMethods.Put; this.uploadOpCts = new CancellationTokenSource(); Exception webError = null; LiveOperationResult opResult = null; try { if (this.InputStream != null) { this.uploadOp = await uploader.CreateUploadFromStreamAsync(uploadUrl, this.InputStream); } else { this.uploadOp = uploader.CreateUpload(uploadUrl, this.InputFile); } var progressHandler = new Progress<BT.UploadOperation>(this.OnUploadProgress); this.uploadOp = await this.uploadOp.StartAsync().AsTask(this.uploadOpCts.Token, progressHandler); } catch (TaskCanceledException exception) { opResult = new LiveOperationResult(exception, true); } catch (Exception exp) { // This might be an server error. We will read the response to determine the error message. webError = exp; } if (opResult == null) { try { IInputStream responseStream = this.uploadOp.GetResultStreamAt(0); if (responseStream == null) { var error = new LiveConnectException( ApiOperation.ApiClientErrorCode, ResourceHelper.GetString("ConnectionError")); opResult = new LiveOperationResult(error, false); } else { var reader = new DataReader(responseStream); uint length = await reader.LoadAsync(MaxUploadResponseLength); opResult = ApiOperation.CreateOperationResultFrom(reader.ReadString(length), ApiMethod.Upload); if (webError != null && opResult.Error != null && !(opResult.Error is LiveConnectException)) { // If the error did not come from the api service, // we'll just return the error thrown by the uploader. opResult = new LiveOperationResult(webError, false); } } } catch (COMException exp) { opResult = new LiveOperationResult(exp, false); } catch (FileNotFoundException exp) { opResult = new LiveOperationResult(exp, false); } } this.OnOperationCompleted(opResult); }
private static void ValidateError(LiveConnectException error, string expectedCode) { Assert.IsTrue(error.ErrorCode.Equals(expectedCode, StringComparison.Ordinal), "Unexpected error code. Expect: " + expectedCode + " Actual: " + error.ErrorCode); Assert.IsTrue(!string.IsNullOrEmpty(error.Message)); }
/// <summary> /// Parses a string response body and creates a LiveOperationResult object from it. /// </summary> internal static LiveOperationResult CreateOperationResultFrom(string responseBody, ApiMethod method) { if (string.IsNullOrEmpty(responseBody)) { if (method != ApiMethod.Delete) { var error = new LiveConnectException( ApiClientErrorCode, ResourceHelper.GetString("NoResponseData")); return new LiveOperationResult(error, false); } return new LiveOperationResult(null, responseBody); } return LiveOperationResult.FromResponse(responseBody); }
/// <summary> /// Process the error response. /// </summary> private async Task<LiveDownloadOperationResult> ProcessDownloadErrorResponse(Exception exception) { LiveDownloadOperationResult opResult; try { IInputStream responseStream = this.downloadOp.GetResultStreamAt(0); if (responseStream == null) { var error = new LiveConnectException( ApiOperation.ApiServerErrorCode, ResourceHelper.GetString("ConnectionError")); opResult = new LiveDownloadOperationResult(error, false); } else { var reader = new DataReader(responseStream); uint length = await reader.LoadAsync(TailoredDownloadOperation.MaxDownloadResponseLength); Exception error = CreateOperationResultFrom(reader.ReadString(length), this.Method).Error; if (error is FormatException) { // if we cannot understand the error response, // return the exception thrown by the background downloader. error = exception; } opResult = new LiveDownloadOperationResult(error, false); } } catch (COMException exp) { opResult = new LiveDownloadOperationResult(exp, false); } catch (FileNotFoundException exp) { opResult = new LiveDownloadOperationResult(exp, false); } return opResult; }
/// <summary> /// Called when a BackgroundTransferRequet's TransferStatus is set to Completed. /// This method will remove the request from the BackgroundTransferService and call /// the LiveOperationEventArgs event handler. /// </summary> /// <param name="request">request with a TransferStatus that is set to Completed</param> private void OnTransferStatusComplete(BackgroundTransferRequest request) { Debug.Assert(request.TransferStatus == TransferStatus.Completed); Debug.Assert(BackgroundTransferHelper.IsDownloadRequest(request)); this.OnBackgroundTransferRequestCompleted(request); // Remove the transfer request in order to make room in the queue for more transfers. // Transfers are not automatically removed by the system. // Cancelled requests have already been removed from the system and cannot be removed twice. if (!BackgroundTransferHelper.IsCanceledRequest(request)) { try { this.backgroundTransferService.Remove(request); } catch (Exception exception) { this.tcs.TrySetException(new LiveConnectException( ApiOperation.ApiClientErrorCode, ResourceHelper.GetString("BackgroundTransferServiceRemoveError"), exception)); return; } } if (request.TransferError != null) { var exception = new LiveConnectException(ApiOperation.ApiServerErrorCode, ResourceHelper.GetString("ServerError"), request.TransferError); this.tcs.TrySetException(exception); } else if (!BackgroundTransferHelper.IsSuccessfulStatusCode(request.StatusCode)) { var exception = new LiveConnectException(ApiOperation.ApiServerErrorCode, ResourceHelper.GetString("ServerError")); this.tcs.TrySetException(exception); } else { string jsonResponse = string.Format(JsonResponse, request.DownloadLocation.OriginalString.Replace("\\", "\\\\")); var jsonReader = new JsonReader(jsonResponse); var jsonObject = jsonReader.ReadValue() as IDictionary<string, object>; var result = new LiveOperationResult(jsonObject, jsonResponse); this.tcs.TrySetResult(result); } }
private async void OnGetUploadLinkCompleted(LiveOperationResult result) { if (this.Status == OperationStatus.Cancelled) { base.OnCancel(); return; } if (result.Error != null || result.IsCancelled) { this.OnOperationCompleted(result); return; } var uploadUrl = new Uri(result.RawResult, UriKind.Absolute); // NOTE: the GetUploadLinkOperation will return a uri with the overwite, suppress_response_codes, // and suppress_redirect query parameters set. Debug.Assert(uploadUrl.Query != null); Debug.Assert(uploadUrl.Query.Contains(QueryParameters.Overwrite)); Debug.Assert(uploadUrl.Query.Contains(QueryParameters.SuppressRedirects)); Debug.Assert(uploadUrl.Query.Contains(QueryParameters.SuppressResponseCodes)); var uploader = new BT.BackgroundUploader(); uploader.Group = LiveConnectClient.LiveSDKUploadGroup; if (this.LiveClient.Session != null) { uploader.SetRequestHeader( ApiOperation.AuthorizationHeader, AuthConstants.BearerTokenType + " " + this.LiveClient.Session.AccessToken); } uploader.SetRequestHeader(ApiOperation.LibraryHeader, Platform.GetLibraryHeaderValue()); uploader.Method = HttpMethods.Put; this.uploadOpCts = new CancellationTokenSource(); Exception webError = null; LiveOperationResult opResult = null; try { if (this.InputStream != null) { this.uploadOp = await uploader.CreateUploadFromStreamAsync(uploadUrl, this.InputStream); } else { this.uploadOp = uploader.CreateUpload(uploadUrl, this.InputFile); } var progressHandler = new Progress <BT.UploadOperation>(this.OnUploadProgress); this.uploadOp = await this.uploadOp.StartAsync().AsTask(this.uploadOpCts.Token, progressHandler); } catch (TaskCanceledException exception) { opResult = new LiveOperationResult(exception, true); } catch (Exception exp) { // This might be an server error. We will read the response to determine the error message. webError = exp; } if (opResult == null) { try { IInputStream responseStream = this.uploadOp.GetResultStreamAt(0); if (responseStream == null) { var error = new LiveConnectException( ApiOperation.ApiClientErrorCode, ResourceHelper.GetString("ConnectionError")); opResult = new LiveOperationResult(error, false); } else { var reader = new DataReader(responseStream); uint length = await reader.LoadAsync(MaxUploadResponseLength); opResult = this.CreateOperationResultFrom(reader.ReadString(length)); if (webError != null && opResult.Error != null && !(opResult.Error is LiveConnectException)) { // If the error did not come from the api service, // we'll just return the error thrown by the uploader. opResult = new LiveOperationResult(webError, false); } } } catch (COMException exp) { opResult = new LiveOperationResult(exp, false); } catch (FileNotFoundException exp) { opResult = new LiveOperationResult(exp, false); } } this.OnOperationCompleted(opResult); }
protected override void OnWebResponseReceived(WebResponse response) { // We are done with the HttpWebRequest so let's remove our reference to it. // If we hold on to it and Cancel is called, our parent class, WebOperation, will call this.Request.Abort // and this causes a Deadlock in the stream.BeginRead call in StreamCopyOperation. Not fun. this.Request = null; HttpStatusCode status = ((HttpWebResponse)response).StatusCode; if (status != HttpStatusCode.OK) { var result = this.CreateOperationResultFrom(response); if (result.Error is FormatException) { // We do expect non-JSON errors from other data providers for download requests. // If we can't understand the response body, we'll just return a generic error message. var error = new LiveConnectException( ApiOperation.ApiServerErrorCode, string.Format( CultureInfo.CurrentUICulture, ResourceHelper.GetString("ServerErrorWithStatus"), status.ToString())); result = new LiveOperationResult(error, false); } this.CompleteOperation(result.Error); } else if (((HttpWebResponse)response).StatusCode != HttpStatusCode.OK) { var result = this.CreateOperationResultFrom(response); this.CompleteOperation(result.Error); } else { this.response = response; Stream responseStream = this.response.GetResponseStream(); this.outputStream = new MemoryStream(); long totalBytesToReceive; string contentLength = response.Headers[DownloadOperation.HttpHeaderContentLength]; if (!string.IsNullOrEmpty(contentLength)) { if (!long.TryParse(contentLength, out totalBytesToReceive)) { totalBytesToReceive = DownloadOperation.UnknownFileSize; } } else { totalBytesToReceive = DownloadOperation.UnknownFileSize; } this.streamCopyOperation = new StreamCopyOperation( this.LiveClient, ApiMethod.Download, responseStream, this.outputStream, totalBytesToReceive, this.progress, this.Dispatcher, (isCancelled, error) => { if (isCancelled) { this.Cancel(); } this.CompleteOperation(error); }); Platform.RegisterForCancel(null, this.streamCopyOperation.Cancel); this.streamCopyOperation.Execute(); } }