IAsyncResult BeginUploadStream(string address, string method, string fileName, Stream inputStream, AsyncCallback completed, Action <IAsyncResult, LiveOperationProgress> progress, object userState)
        {
            var asyncResult = new LiveConnectClientAsyncResult <LiveOperationResult>(userState, this.SynchronizationContext);

            var task = (WaitCallback)(state =>
            {
                var ar = (LiveConnectClientAsyncResult <LiveOperationResult>)state;

                ar.CompletedSynchronously = false;

                try
                {
                    var request = (HttpWebRequest)WebRequest.Create(address);

                    request.Method = method;

                    if (inputStream != null)
                    {
                        var boundary = "AAA" + string.Join(string.Empty, Guid.NewGuid().ToByteArray().Select(_ => _.ToString("X")).ToArray()) + "AAA";

                        var head = StringFactory.Create(sb =>
                        {
                            sb.AppendLine(string.Format(@"--{0}", boundary));
                            sb.AppendLine(string.Format(@"Content-Disposition: form-data; name=""file""; filename=""{0}""", fileName));
                            sb.AppendLine(string.Format(@"Content-Type: application/octet-stream"));
                            sb.AppendLine();
                        });

                        var tail = StringFactory.Create(sb =>
                        {
                            sb.AppendLine();
                            sb.AppendLine(string.Format(@"--{0}--", boundary));
                        });

                        request.ContentType = string.Format(ContentTypes.Multipart, boundary);

                        using (var requestStream = request.GetRequestStream())
                        {
                            using (var stream = Encoding.UTF8.GetBytes(head).AsStream())
                            {
                                stream.CopyTo(requestStream);
                            }

                            var contentLength = -1;
                            var totalBytes = 0L;

                            ar.Sync(() =>
                            {
                                if (progress != null)
                                {
                                    ar.Sync(() => progress(ar, new LiveOperationProgress(totalBytes, contentLength)));
                                }
                            });

                            totalBytes = inputStream.CopyTo(requestStream, bytesTransferred =>
                            {
                                ar.ThrowIfCancellationRequested();

                                if (progress != null)
                                {
                                    ar.Sync(() => progress(ar, new LiveOperationProgress(bytesTransferred, contentLength)));
                                }
                            });

                            if (progress != null)
                            {
                                ar.Sync(() => progress(ar, new LiveOperationProgress(totalBytes, totalBytes)));
                            }

                            using (var stream = Encoding.UTF8.GetBytes(tail).AsStream())
                            {
                                stream.CopyTo(requestStream);
                            }
                        }
                    }

                    var rawResult = LiveConnectClient.DownloadString(request, bytesTransfeerd => ar.ThrowIfCancellationRequested());

                    var result = string.IsNullOrEmpty(rawResult) ? new Dictionary <string, object>() : Json.Parse(rawResult);

                    if (result.ContainsKey(Keys.Error))
                    {
                        var errorCode = (string)result[Keys.Error];
                        var message = (string)result[Keys.ErrorDescription];
                        var error = new LiveConnectException(errorCode, message);

                        ar.Result = new LiveOperationResult(error, false);
                    }
                    else
                    {
                        ar.Result = new LiveOperationResult(result, rawResult);
                    }
                }
                catch (Exception error)
                {
                    ar.Result = new LiveOperationResult(error, error is OperationCanceledException);
                }
                finally
                {
                    ar.IsCompleted = true;

                    if (completed != null)
                    {
                        ar.Sync(() => completed(ar));
                    }
                }
            });

            if (!ThreadPool.QueueUserWorkItem(task, asyncResult))
            {
                throw new OutOfMemoryException();
            }

            return(asyncResult);
        }
        LiveConnectClientAsyncResult <LiveOperationResult> BeginUploadString(string address, string method, string data, AsyncCallback asyncCallback, object userState)
        {
            var asyncResult = new LiveConnectClientAsyncResult <LiveOperationResult>(userState, this.SynchronizationContext);

            var task = (WaitCallback)(state =>
            {
                var ar = (LiveConnectClientAsyncResult <LiveOperationResult>)state;

                ar.CompletedSynchronously = false;

                try
                {
                    var request = (HttpWebRequest)WebRequest.Create(address);

                    request.Method = method;

                    if (!string.IsNullOrEmpty(data))
                    {
                        request.ContentType = ContentTypes.Json;

                        using (var inputStream = new MemoryStream(Encoding.UTF8.GetBytes(data)))
                            using (var requestStream = request.GetRequestStream())
                            {
                                inputStream.CopyTo(requestStream, bytesTranferrd => ar.ThrowIfCancellationRequested());
                            }
                    }

                    var rawResult = LiveConnectClient.DownloadString(request, bytesTransferred => ar.ThrowIfCancellationRequested());

                    var result = string.IsNullOrEmpty(rawResult)
                        ? new Dictionary <string, object>()
                        : Json.Parse(rawResult);

                    if (result.ContainsKey(Keys.Error))
                    {
                        var errorCode = (string)result[Keys.Error];
                        var message = (string)result[Keys.ErrorDescription];
                        var error = new LiveConnectException(errorCode, message);

                        ar.Result = new LiveOperationResult(error, false);
                    }
                    else
                    {
                        ar.Result = new LiveOperationResult(result, rawResult);
                    }
                }
                catch (Exception error)
                {
                    ar.Result = new LiveOperationResult(error, error is OperationCanceledException);
                }
                finally
                {
                    ar.IsCompleted = true;

                    if (asyncCallback != null)
                    {
                        ar.Sync(() => asyncCallback(ar));
                    }
                }
            });

            if (!ThreadPool.QueueUserWorkItem(task, asyncResult))
            {
                throw new OutOfMemoryException();
            }

            return(asyncResult);
        }