/// <summary>
        /// Remote API method execution using HTTP "post" method with content type set to "multipart/form-data".
        /// </summary>
        private DataType ExecuteMultipartHttpRequest <ContractType, DataType>(ViddlerMethodAttribute methodAttribute, StringDictionary parameters, string fileName, Stream fileStream, Data.UploadEndPoint endPoint)
        {
            StringBuilder requestPath = new StringBuilder();

            if (endPoint != null && !string.IsNullOrEmpty(endPoint.Url))
            {
                requestPath.Append(endPoint.Url);
            }
            else
            {
                requestPath.Append((this.EnableSsl && methodAttribute.IsSecure) ? this.SecureBaseUrl : this.BaseUrl);
                requestPath.Append(methodAttribute.MethodName);
                requestPath.Append(".xml");
            }

            string boundary = string.Concat("-------------------------", DateTime.Now.Ticks.ToString("x", CultureInfo.InvariantCulture));

            byte[] boundaryBytes    = System.Text.Encoding.UTF8.GetBytes(string.Concat("\r\n--", boundary, "\r\n"));
            byte[] endBoundaryBytes = System.Text.Encoding.UTF8.GetBytes(string.Concat("\r\n--", boundary, "--\r\n"));

            List <byte> requestData = new List <byte>();

            // If we have endpoint uploadtoken that is ALL we send and we don't send session/apikey
            // If we send session/apikey and NOT uploadtoken, Viddler will do a prepareupload behind the scenes and use that uploadtoken.
            // This is why allow_replace fails w/out an uploadtoken because their prepareupload does NOT have allow_replace set.
            if (endPoint != null && !string.IsNullOrEmpty(endPoint.Token))
            {
                requestData.AddRange(boundaryBytes);
                requestData.AddRange(System.Text.Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "Content-Disposition: form-data; name=\"uploadtoken\"\r\n\r\n{0}", endPoint.Token)));
            }
            else
            {
                requestData.AddRange(boundaryBytes);
                requestData.AddRange(System.Text.Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "Content-Disposition: form-data; name=\"key\"\r\n\r\n{0}", this.ApiKey)));
                if (methodAttribute.IsSessionRequired)
                {
                    requestData.AddRange(boundaryBytes);
                    requestData.AddRange(System.Text.Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "Content-Disposition: form-data; name=\"sessionid\"\r\n\r\n{0}", this.SessionId)));
                }
            }

            if (parameters != null && parameters.Keys.Count > 0)
            {
                foreach (string key in parameters.Keys)
                {
                    //string queryData = string.Format(CultureInfo.InvariantCulture, "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}", key, ViddlerHelper.EncodeRequestData(parameters[key]));
                    string queryData = string.Format(CultureInfo.InvariantCulture, "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}", key, parameters[key]);
                    requestData.AddRange(boundaryBytes);
                    requestData.AddRange(System.Text.Encoding.UTF8.GetBytes(queryData));
                }
            }

            long fileSize = endBoundaryBytes.Length;

            if (fileStream != null)
            {
                fileStream.Position = 0;
                if (string.IsNullOrEmpty(fileName))
                {
                    fileName = DateTime.Now.Ticks.ToString("x", CultureInfo.InvariantCulture);
                }
                requestData.AddRange(boundaryBytes);
                requestData.AddRange(System.Text.Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "Content-Disposition: form-data; name=\"file\"; filename=\"{0}\"\r\nContent-Type: application/octet-stream\r\n\r\n", fileName)));
                fileSize += fileStream.Length;
            }

            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestPath.ToString());
                request.Method      = "POST";
                request.ContentType = string.Concat("multipart/form-data; boundary=", boundary);
                request.UserAgent   = string.Concat("Microsoft .NET, ", this.GetType().Assembly.FullName);
                request.AllowWriteStreamBuffering = false;
                request.Accept = "text/xml";
                request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
                request.KeepAlive        = true;
                request.Timeout          = int.MaxValue;
                request.ReadWriteTimeout = int.MaxValue;
                request.ContentLength    = requestData.Count + fileSize;

                Stream requestStream = request.GetRequestStream();
                bool   isCancel      = false;
                try
                {
                    requestStream.Write(requestData.ToArray(), 0, requestData.Count);
                    requestStream.Flush();
                    if (fileStream != null)
                    {
                        byte[] buffer    = new byte[32768];
                        int    bytesRead = 0;
                        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            requestStream.Write(buffer, 0, bytesRead);
                            requestStream.Flush();
                            if (this.Uploading != null)
                            {
                                ViddlerRequestUploadEventArgs uploadEventArgs = new ViddlerRequestUploadEventArgs(typeof(ContractType), fileStream.Length, fileStream.Position);
                                this.Uploading(this, uploadEventArgs);
                                if (uploadEventArgs.Cancel)
                                {
                                    isCancel = true;
                                    request.Abort();
                                    break;
                                }
                            }
                        }
                    }
                    if (!isCancel)
                    {
                        requestStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
                        requestStream.Flush();
                    }
                }
                finally
                {
                    if (!isCancel)
                    {
                        requestStream.Dispose();
                    }
                }
                if (isCancel)
                {
                    return(default(DataType));
                }
                else
                {
                    DataType responseObject = ViddlerService.HandleHttpResponse <ContractType, DataType>(request, methodAttribute, this.DumpFolder);
                    return(responseObject);
                }
            }
            catch (System.Net.WebException exception)
            {
                throw ViddlerService.HandleHttpError(exception);
            }
        }
        /// <summary>
        /// Remote API method execution.
        /// </summary>
        internal DataType ExecuteHttpRequest <ContractType, DataType>(StringDictionary parameters, string fileName, Stream fileStream, Data.UploadEndPoint endPoint)
        {
            ViddlerMethodAttribute methodAttribute = ViddlerHelper.GetMethodAttribute(typeof(ContractType));

            DataType responseObject = default(DataType);

            try
            {
                if (methodAttribute == null)
                {
                    throw new System.InvalidOperationException(string.Concat("ViddlerMethodAttribute missing for type \"", typeof(ContractType).ToString(), "\"."));
                }

                if (this.BeginRequest != null)
                {
                    this.BeginRequest(this, new ViddlerRequestEventArgs(typeof(ContractType), parameters, (fileStream != null)));
                }

                if (methodAttribute.IsSessionRequired && !this.IsAuthenticated)
                {
                    throw new System.InvalidOperationException("The current method requires authenticated user.");
                }
                if (fileStream != null && !fileStream.CanSeek)
                {
                    throw new System.ArgumentException("The file stream does not support seeking.", "fileStream");
                }

                switch (methodAttribute.RequestType)
                {
                case ViddlerRequestType.Post:
                {
                    responseObject = this.ExecutePostHttpRequest <ContractType, DataType>(methodAttribute, parameters);
                    break;
                }

                case ViddlerRequestType.Multipart:
                {
                    responseObject = this.ExecuteMultipartHttpRequest <ContractType, DataType>(methodAttribute, parameters, fileName, fileStream, endPoint);
                    break;
                }

                default:
                {
                    responseObject = this.ExecuteGetHttpRequest <ContractType, DataType>(methodAttribute, parameters);
                    break;
                }
                }

                if (this.EndRequest != null)
                {
                    this.EndRequest(this, new ViddlerRequestEventArgs(typeof(ContractType), parameters, (fileStream != null)));
                }
            }
            catch (Exception exception)
            {
                if (this.Error != null)
                {
                    this.Error(this, new ViddlerRequestErrorEventArgs(typeof(ContractType), parameters, (fileStream != null), exception));
                }
                else
                {
                    throw;
                }
            }

            return(responseObject);
        }
 /// <summary>
 /// Calls the remote Viddler API method: viddler.videos.upload
 /// </summary>
 public Data.Video Upload(string title, string tags, string description, bool?makePublic, string fileName, Stream fileStream, string videoid = null)
 {
     Data.UploadEndPoint endPoint = this.PrepareUpload(videoid);
     return(this.Upload(title, tags, description, makePublic, fileName, fileStream, endPoint, videoid));
 }
        /// <summary>
        /// Calls the remote Viddler API method: viddler.videos.upload
        /// </summary>
        public Data.Video Upload(string title, string tags, string description, bool?makePublic, string localPath, Data.UploadEndPoint endPoint, string videoid = null)
        {
            Data.Video responseObject;
            FileInfo   file = new FileInfo(localPath);

            if (file.Exists)
            {
                using (FileStream stream = file.OpenRead())
                {
                    responseObject = this.Upload(title, tags, description, makePublic, file.Name, stream, endPoint, videoid);
                }
            }
            else
            {
                responseObject = this.Upload(title, tags, description, makePublic, null, Stream.Null, endPoint, videoid);
            }
            return(responseObject);
        }
 /// <summary>
 /// Calls the remote Viddler API method: viddler.videos.upload
 /// </summary>
 public Data.Video Upload(string title, string tags, string description, bool?makePublic, string localPath, string videoid = null)
 {
     Data.UploadEndPoint endPoint = this.PrepareUpload(videoid);
     return(this.Upload(title, tags, description, makePublic, localPath, endPoint, videoid));
 }
        /// <summary>
        /// Calls the remote Viddler API method: viddler.videos.upload
        /// </summary>
        /// <param name="title"></param>
        /// <param name="tags"></param>
        /// <param name="description"></param>
        /// <param name="makePublic"></param>
        /// <param name="fileName"></param>
        /// <param name="fileStream"></param>
        /// <param name="endPoint">endPoint information to upload video to.  If this is blank, and new endpoint will be created for you</param>
        /// <param name="videoid">Optional: VideoID to replace if you are trying to replace.</param>
        /// <returns></returns>
        public Data.Video Upload(string title, string tags, string description, bool?makePublic, string fileName, Stream fileStream, Data.UploadEndPoint endPoint, string videoid = null)
        {
            if (endPoint == null)
            {
                endPoint = this.PrepareUpload(videoid);
            }

            StringDictionary parameters = new StringDictionary();

            if (!string.IsNullOrEmpty(videoid))
            {
                parameters.Add("video_id", videoid);
            }
            else
            {
                parameters.Add("title", title);
                if (tags != null)
                {
                    parameters.Add("tags", tags);
                }
                if (description != null)
                {
                    parameters.Add("description", description);
                }
                if (makePublic.HasValue)
                {
                    parameters.Add("make_public", makePublic.Value ? "1" : "0");
                }
            }
            Data.Video video;
            if (fileStream != null && !fileStream.CanSeek)
            {
                using (MemoryStream seekableStream = new MemoryStream())
                {
                    byte[] buffer    = new byte[4096];
                    int    bytesRead = 0;
                    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                    {
                        seekableStream.Write(buffer, 0, bytesRead);
                    }
                    seekableStream.Position = 0;

                    video = this.Service.ExecuteHttpRequest <Videos.Upload, Data.Video>(parameters, fileName, seekableStream, endPoint);
                }
            }
            else
            {
                video = this.Service.ExecuteHttpRequest <Videos.Upload, Data.Video>(parameters, fileName, fileStream, endPoint);
            }
            return(video);
        }