예제 #1
0
        /// <summary>
        /// Implementation of raw string-returning async API
        /// </summary>
        /// <param name="cd"></param>
        /// <param name="verb"></param>
        /// <param name="relativePath"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        private async Task <string> RestCallStringAsync(string verb, AvaTaxPath relativePath, object content = null, CallDuration cd = null)
        {
            if (cd == null)
            {
                cd = new CallDuration();
            }

            // Convert the JSON payload, if any
            object jsonPayload = null;
            string mimeType    = null;

            if (content != null && content is FileResult)
            {
                var fr = (FileResult)content;
                mimeType = fr.ContentType;
                MultipartFormDataContent mpfdc            = new MultipartFormDataContent("----dataBoundary");
                ByteArrayContent         byteArrayContent = new ByteArrayContent(fr.Data);
                byteArrayContent.Headers.Add("Content-Type", "application/octet-stream");
                mpfdc.Add(byteArrayContent, fr.Filename, fr.Filename);
                jsonPayload = mpfdc;
            }
            else if (content != null)
            {
                jsonPayload = JsonConvert.SerializeObject(content, SerializerSettings);
                mimeType    = "application/json";
            }

            // Call REST
            using (var result = await InternalRestCallAsync(cd, verb, relativePath, jsonPayload, mimeType).ConfigureAwait(false)) {
                // Read the result
                var responseString = await result.Content.ReadAsStringAsync().ConfigureAwait(false);

                // Determine server duration
                var sd = DetectDuration(result, "serverduration");
                var dd = DetectDuration(result, "dataduration");
                var td = DetectDuration(result, "serviceduration");
                cd.FinishReceive(sd, dd, td);

                // Capture information about this API call and make it available for logging
                var eventargs = new AvaTaxCallEventArgs()
                {
                    HttpVerb = verb.ToUpper(), Code = result.StatusCode, RequestUri = new Uri(_envUri, relativePath.ToString()), RequestBody = jsonPayload as string, ResponseString = responseString, Duration = cd
                };
                OnCallCompleted(eventargs);

                // Deserialize the result
                if (result.IsSuccessStatusCode)
                {
                    return(responseString);
                }
                else
                {
                    var err = JsonConvert.DeserializeObject <ErrorResult>(responseString);
                    cd.FinishParse();
                    this.LastCallTime = cd;
                    throw new AvaTaxError(err, result.StatusCode);
                }
            }
        }
        /// <summary>
        /// Implementation of raw file-returning async API
        /// </summary>
        /// <param name="verb"></param>
        /// <param name="relativePath"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        private async Task <FileResult> RestCallFileAsync(string verb, AvaTaxPath relativePath, object content = null)
        {
            CallDuration cd = new CallDuration();

            // Convert the JSON payload, if any
            string jsonPayload = null;

            if (content != null)
            {
                jsonPayload = JsonConvert.SerializeObject(content, SerializerSettings);
            }

            // Call REST
            using (var result = await InternalRestCallAsync(cd, verb, relativePath, jsonPayload).ConfigureAwait(false)) {
                // Read the result
                if (result.IsSuccessStatusCode)
                {
                    var fr = new FileResult()
                    {
                        ContentType = result.Content.Headers.GetValues("Content-Type").FirstOrDefault(),
                        Filename    = GetDispositionFilename(result.Content.Headers.GetValues("Content-Disposition").FirstOrDefault()),
                        Data        = await result.Content.ReadAsByteArrayAsync().ConfigureAwait(false)
                    };

                    // Capture timings
                    cd.FinishParse();
                    this.LastCallTime = cd;

                    // Capture information about this API call and make it available for logging
                    var eventargs = new AvaTaxCallEventArgs()
                    {
                        HttpVerb = verb.ToUpper(), Code = result.StatusCode, RequestUri = new Uri(_envUri, relativePath.ToString()), RequestBody = jsonPayload, ResponseBody = fr.Data, Duration = cd
                    };
                    OnCallCompleted(eventargs);
                    return(fr);

                    // Handle exceptions and convert them to AvaTax results
                }
                else
                {
                    var errorResponseString = await result.Content.ReadAsStringAsync().ConfigureAwait(false);

                    var err = JsonConvert.DeserializeObject <ErrorResult>(errorResponseString);
                    cd.FinishParse();
                    this.LastCallTime = cd;

                    // Capture information about this API call error and make it available for logging
                    var eventargs = new AvaTaxCallEventArgs()
                    {
                        HttpVerb = verb.ToUpper(), Code = result.StatusCode, RequestUri = new Uri(_envUri, relativePath.ToString()), RequestBody = jsonPayload, ResponseString = errorResponseString, Duration = cd
                    };
                    OnCallCompleted(eventargs);
                    throw new AvaTaxError(err, result.StatusCode);
                }
            }
        }
        /// <summary>
        /// Implementation of raw string-returning async API
        /// </summary>
        /// <param name="cd"></param>
        /// <param name="verb"></param>
        /// <param name="relativePath"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        private async Task <string> RestCallStringAsync(string verb, AvaTaxPath relativePath, object content = null, CallDuration cd = null)
        {
            if (cd == null)
            {
                cd = new CallDuration();
            }

            // Convert the JSON payload, if any
            string jsonPayload = null;

            if (content != null)
            {
                jsonPayload = JsonConvert.SerializeObject(content, SerializerSettings);
            }

            // Call REST
            using (var result = await InternalRestCallAsync(cd, verb, relativePath, jsonPayload).ConfigureAwait(false)) {
                // Read the result
                var responseString = await result.Content.ReadAsStringAsync().ConfigureAwait(false);

                // Determine server duration
                var sd = DetectDuration(result, "serverduration");
                var dd = DetectDuration(result, "dataduration");
                var td = DetectDuration(result, "serviceduration");
                cd.FinishReceive(sd, dd, td);

                // Capture information about this API call and make it available for logging
                var eventargs = new AvaTaxCallEventArgs()
                {
                    HttpVerb = verb.ToUpper(), Code = result.StatusCode, RequestUri = new Uri(_envUri, relativePath.ToString()), RequestBody = jsonPayload, ResponseString = responseString, Duration = cd
                };
                OnCallCompleted(eventargs);

                // Deserialize the result
                if (result.IsSuccessStatusCode)
                {
                    return(responseString);
                }
                else
                {
                    var err = JsonConvert.DeserializeObject <ErrorResult>(responseString);
                    cd.FinishParse();
                    this.LastCallTime = cd;
                    throw new AvaTaxError(err, result.StatusCode);
                }
            }
        }
        /// <summary>
        /// Direct implementation of client APIs to string values
        /// </summary>
        /// <param name="verb"></param>
        /// <param name="relativePath"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        private string RestCallString(string verb, AvaTaxPath relativePath, object content = null)
        {
            string path        = CombinePath(_envUri.ToString(), relativePath.ToString());
            string jsonPayload = null;
            string mimeType    = null;

            // Use HttpWebRequest so we can get a decent response
            var wr = (HttpWebRequest)WebRequest.Create(path);

            wr.Proxy = null;

            // Add headers
            foreach (var key in _clientHeaders.Keys)
            {
                wr.Headers.Add(key, _clientHeaders[key]);
            }

            // Convert the name-value pairs into a byte array
            wr.Method = verb;

            //Upload file.
            if (content != null && content is FileResult)
            {
                wr.KeepAlive = true;
                var fr = (FileResult)content;
                mimeType = fr.ContentType;
                content  = fr.Data;
                string dataBoundary = "----dataBoundary";
                wr.ContentType = "multipart/form-data; boundary=" + dataBoundary;
                byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + dataBoundary + "\r\n");
                Stream rs            = wr.GetRequestStream();
                rs.Write(boundaryBytes, 0, boundaryBytes.Length);
                string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
                string header         = string.Format(headerTemplate, fr.Filename, fr.Filename, fr.ContentType);
                byte[] headerBytes    = Encoding.UTF8.GetBytes(header);
                rs.Write(headerBytes, 0, headerBytes.Length);
                rs.Write(fr.Data, 0, fr.Data.Length);
                byte[] trailer = Encoding.ASCII.GetBytes("\r\n--" + dataBoundary + "--\r\n");
                rs.Write(trailer, 0, trailer.Length);
                rs.Close();
            }
            else if (content != null)
            {
                wr.ContentType = mimeType ?? Constants.JSON_MIME_TYPE;
                wr.ServicePoint.Expect100Continue = false;

                // Encode the payload
                jsonPayload = JsonConvert.SerializeObject(content, SerializerSettings);
                var    encoding = new UTF8Encoding();
                byte[] data     = encoding.GetBytes(jsonPayload);
                wr.ContentLength = data.Length;

                // Call the server
                using (var s = wr.GetRequestStream()) {
                    s.Write(data, 0, data.Length);
                    s.Close();
                }
            }

            // Transmit, and get back the response, save it to a temp file
            try {
                using (var response = wr.GetResponse()) {
                    using (var inStream = response.GetResponseStream()) {
                        using (var reader = new StreamReader(inStream)) {
                            var responseString = reader.ReadToEnd();

                            // Track the API call
                            var eventargs = new AvaTaxCallEventArgs()
                            {
                                Code = ((HttpWebResponse)response).StatusCode, Duration = null, HttpVerb = wr.Method, RequestBody = jsonPayload, ResponseString = responseString, RequestUri = new Uri(path)
                            };
                            OnCallCompleted(eventargs);

                            // Here's the results
                            return(responseString);
                        }
                    }
                }

                // Catch a web exception
            } catch (WebException webex) {
                HttpWebResponse httpWebResponse = webex.Response as HttpWebResponse;
                if (httpWebResponse != null)
                {
                    using (Stream stream = httpWebResponse.GetResponseStream()) {
                        using (StreamReader reader = new StreamReader(stream)) {
                            var errString = reader.ReadToEnd();

                            // Track the API call
                            var eventargs = new AvaTaxCallEventArgs()
                            {
                                Code = ((HttpWebResponse)httpWebResponse).StatusCode, Duration = null, HttpVerb = wr.Method, RequestBody = jsonPayload, ResponseString = errString, RequestUri = new Uri(path)
                            };
                            OnCallCompleted(eventargs);

                            // Here's the results
                            var err = JsonConvert.DeserializeObject <ErrorResult>(errString);
                            throw new AvaTaxError(err, httpWebResponse.StatusCode);
                        }
                    }
                }

                // If we can't parse it as an AvaTax error, just throw
                throw webex;
            }
        }
        /// <summary>
        /// Direct implementation of client APIs to string values
        /// </summary>
        /// <param name="verb"></param>
        /// <param name="relativePath"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        private FileResult RestCallFile(string verb, AvaTaxPath relativePath, object content = null)
        {
            string path        = CombinePath(_envUri.ToString(), relativePath.ToString());
            string jsonPayload = null;

            // Use HttpWebRequest so we can get a decent response
            var wr = (HttpWebRequest)WebRequest.Create(path);

            wr.Proxy = null;

            // Add headers
            foreach (var key in _clientHeaders.Keys)
            {
                wr.Headers.Add(key, _clientHeaders[key]);
            }

            // Convert the name-value pairs into a byte array
            wr.Method = verb;
            if (content != null)
            {
                wr.ContentType = Constants.JSON_MIME_TYPE;
                wr.ServicePoint.Expect100Continue = false;

                // Encode the payload
                jsonPayload = JsonConvert.SerializeObject(content, SerializerSettings);
                var    encoding = new UTF8Encoding();
                byte[] data     = encoding.GetBytes(jsonPayload);
                wr.ContentLength = data.Length;

                // Call the server
                using (var s = wr.GetRequestStream()) {
                    s.Write(data, 0, data.Length);
                    s.Close();
                }
            }

            // Transmit, and get back the response, save it to a temp file
            try {
                using (var response = wr.GetResponse()) {
                    using (var inStream = response.GetResponseStream()) {
                        const int BUFFER_SIZE = 1024;
                        var       chunks      = new List <byte>();
                        var       totalBytes  = 0;
                        var       bytesRead   = 0;

                        do
                        {
                            var buffer = new byte[BUFFER_SIZE];
                            bytesRead = inStream.Read(buffer, 0, BUFFER_SIZE);
                            if (bytesRead == BUFFER_SIZE)
                            {
                                chunks.AddRange(buffer);
                            }
                            else
                            {
                                for (int i = 0; i < bytesRead; i++)
                                {
                                    chunks.Add(buffer[i]);
                                }
                            }
                            totalBytes += bytesRead;
                        } while (bytesRead > 0);

                        if (totalBytes <= 0)
                        {
                            throw new IOException("Response contained no data");
                        }

                        // Here's your file result
                        var fr = new FileResult()
                        {
                            ContentType = response.Headers["Content-Type"].ToString(),
                            Filename    = GetDispositionFilename(response.Headers["Content-Disposition"].ToString()),
                            Data        = chunks.ToArray()
                        };

                        // Track the API call
                        var eventargs = new AvaTaxCallEventArgs()
                        {
                            Code = ((HttpWebResponse)response).StatusCode, Duration = null, HttpVerb = wr.Method, RequestBody = jsonPayload, ResponseBody = fr.Data, RequestUri = new Uri(path)
                        };
                        OnCallCompleted(eventargs);
                        return(fr);
                    }
                }

                // Catch a web exception
            } catch (WebException webex) {
                HttpWebResponse httpWebResponse = webex.Response as HttpWebResponse;
                if (httpWebResponse != null)
                {
                    using (Stream stream = httpWebResponse.GetResponseStream()) {
                        using (StreamReader reader = new StreamReader(stream)) {
                            var errString = reader.ReadToEnd();

                            // Track the API call
                            var eventargs = new AvaTaxCallEventArgs()
                            {
                                Code = ((HttpWebResponse)httpWebResponse).StatusCode, Duration = null, HttpVerb = wr.Method, RequestBody = jsonPayload, ResponseString = errString, RequestUri = new Uri(path)
                            };
                            OnCallCompleted(eventargs);

                            // Pass on the error
                            var err = JsonConvert.DeserializeObject <ErrorResult>(errString);
                            throw new AvaTaxError(err, httpWebResponse.StatusCode);
                        }
                    }
                }

                // If we can't parse it as an AvaTax error, just throw
                throw webex;
            }
        }
        /// <summary>
        /// Direct implementation of client APIs to string values
        /// </summary>
        /// <param name="verb"></param>
        /// <param name="relativePath"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        private string RestCallString(string verb, AvaTaxPath relativePath, object content = null)
        {
            string path        = CombinePath(_envUri.ToString(), relativePath.ToString());
            string jsonPayload = null;

            // Use HttpWebRequest so we can get a decent response
            var wr = (HttpWebRequest)WebRequest.Create(path);

            wr.Proxy = null;

            // Add headers
            foreach (var key in _clientHeaders.Keys)
            {
                wr.Headers.Add(key, _clientHeaders[key]);
            }

            // Convert the name-value pairs into a byte array
            wr.Method        = verb;
            wr.ContentLength = 0;
            if (content != null)
            {
                wr.ContentType = Constants.JSON_MIME_TYPE;
                wr.ServicePoint.Expect100Continue = false;

                // Encode the payload
                jsonPayload = JsonConvert.SerializeObject(content, SerializerSettings);
                var    encoding = new UTF8Encoding();
                byte[] data     = encoding.GetBytes(jsonPayload);
                wr.ContentLength = data.Length;

                // Call the server
                using (var s = wr.GetRequestStream()) {
                    s.Write(data, 0, data.Length);
                    s.Close();
                }
            }

            // Transmit, and get back the response, save it to a temp file
            try {
                using (var response = wr.GetResponse()) {
                    using (var inStream = response.GetResponseStream()) {
                        using (var reader = new StreamReader(inStream)) {
                            var responseString = reader.ReadToEnd();

                            // Track the API call
                            var eventargs = new AvaTaxCallEventArgs()
                            {
                                Code = ((HttpWebResponse)response).StatusCode, Duration = null, HttpVerb = wr.Method, RequestBody = jsonPayload, ResponseString = responseString, RequestUri = new Uri(path)
                            };
                            OnCallCompleted(eventargs);

                            // Here's the results
                            return(responseString);
                        }
                    }
                }

                // Catch a web exception
            } catch (WebException webex) {
                HttpWebResponse httpWebResponse = webex.Response as HttpWebResponse;
                if (httpWebResponse != null)
                {
                    using (Stream stream = httpWebResponse.GetResponseStream()) {
                        using (StreamReader reader = new StreamReader(stream)) {
                            var errString = reader.ReadToEnd();

                            // Track the API call
                            var eventargs = new AvaTaxCallEventArgs()
                            {
                                Code = ((HttpWebResponse)httpWebResponse).StatusCode, Duration = null, HttpVerb = wr.Method, RequestBody = jsonPayload, ResponseString = errString, RequestUri = new Uri(path)
                            };
                            OnCallCompleted(eventargs);

                            // Here's the results
                            var err = JsonConvert.DeserializeObject <ErrorResult>(errString);
                            throw new AvaTaxError(err, httpWebResponse.StatusCode);
                        }
                    }
                }

                // If we can't parse it as an AvaTax error, just throw
                throw webex;
            }
        }