/// <summary> /// Requests the specified request method. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="requestMethod">The request method.</param> /// <param name="url">The URL.</param> /// <param name="requestData">The request data.</param> /// <param name="options">The options.</param> /// <returns>System.Threading.Tasks.Task<T>.</returns> /// <exception cref="System.Exception">ClientId and ClientSecret is not set</exception> /// <exception cref="PodioInvalidGrantException"></exception> /// <exception cref="PodioBadRequestException"></exception> /// <exception cref="PodioAuthorizationException"></exception> /// <exception cref="PodioForbiddenException"></exception> /// <exception cref="PodioNotFoundException"></exception> /// <exception cref="PodioConflictException"></exception> /// <exception cref="PodioGoneException"></exception> /// <exception cref="PodioRateLimitException"></exception> /// <exception cref="PodioServerException"></exception> /// <exception cref="PodioUnavailableException"></exception> /// <exception cref="PodioException"></exception> private async Task <T> RequestAsync <T>(RequestMethod requestMethod, string url, dynamic requestData, dynamic options = null) where T : new() { Dictionary <string, string> requestHeaders = new Dictionary <string, string>(); var data = new List <string>(); string httpMethod = string.Empty; string originalUrl = url; url = this.ApiUrl + url; //To use url other than api.podio.com, ex file download from files.podio.com if (options != null && options.ContainsKey("url")) { url = options["url"]; } if (string.IsNullOrEmpty(ClientId) || string.IsNullOrEmpty(ClientSecret)) { throw new Exception("ClientId and ClientSecret is not set"); } switch (requestMethod.ToString()) { case "GET": httpMethod = "GET"; requestHeaders["Content-type"] = "application/x-www-form-urlencoded"; if (requestData != null) { string query = EncodeAttributes(requestData); url = url + "?" + query; } requestHeaders["Content-length"] = "0"; break; case "DELETE": httpMethod = "DELETE"; requestHeaders["Content-type"] = "application/x-www-form-urlencoded"; if (requestData != null) { string query = EncodeAttributes(requestData); url = url + "?" + query; } requestHeaders["Content-length"] = "0"; break; case "POST": httpMethod = "POST"; if (options != null && options.ContainsKey("upload") && options["upload"]) { requestHeaders["Content-type"] = "multipart/form-data"; data.Add("file"); } else if (options != null && options.ContainsKey("oauth_request") && options["oauth_request"]) { data.Add("oauth"); requestHeaders["Content-type"] = "application/x-www-form-urlencoded"; } else { requestHeaders["Content-type"] = "application/json"; data.Add("post"); } break; case "PUT": httpMethod = "PUT"; requestHeaders["Content-type"] = "application/json"; data.Add("put"); break; } if (OAuth != null && !string.IsNullOrEmpty(OAuth.AccessToken)) { requestHeaders["Authorization"] = "OAuth2 " + OAuth.AccessToken; if (options != null && options.ContainsKey("oauth_request") && options["oauth_request"]) { requestHeaders.Remove("Authorization"); } } else { requestHeaders.Remove("Authorization"); } if (options != null && options.ContainsKey("file_download") && options["file_download"]) { requestHeaders["Accept"] = "*/*"; } else { requestHeaders["Accept"] = "application/json"; } var request = (HttpWebRequest)WebRequest.Create(url); request.Method = httpMethod; PodioResponse podioResponse = new PodioResponse(); var responseHeaders = new Dictionary <string, string>(StringComparer.CurrentCultureIgnoreCase); var responseObject = new T(); if (requestHeaders.Any()) { if (requestHeaders.ContainsKey("Accept")) { request.Accept = requestHeaders["Accept"]; } if (requestHeaders.ContainsKey("Content-type")) { request.ContentType = requestHeaders["Content-type"]; } if (requestHeaders.ContainsKey("Authorization")) { request.Headers["Authorization"] = requestHeaders["Authorization"]; } } if (data.Any()) { foreach (string item in data) { if (item == "file") { await AddFileToRequestStream(requestData.filePath, requestData.fileName, requestData.mimeType, request); } else if (item == "oauth") { await WriteToRequestStream(EncodeAttributes(requestData), request); } else { await WriteToRequestStream(requestData, request); } } } try { WebResponse webResponse = await Task.Factory.FromAsync <WebResponse>(request.BeginGetResponse, request.EndGetResponse, request); using (webResponse) { podioResponse.Status = (int)((HttpWebResponse)webResponse).StatusCode; foreach (string key in webResponse.Headers.AllKeys) { responseHeaders.Add(key, webResponse.Headers[key]); } if (options != null && options.ContainsKey("file_download")) { using (var memoryStream = new MemoryStream()) { var fileResponse = new FileResponse(); webResponse.GetResponseStream().CopyTo(memoryStream); fileResponse.FileContents = memoryStream.ToArray(); fileResponse.ContentType = webResponse.ContentType; fileResponse.ContentLength = webResponse.ContentLength; return((T)fileResponse.ChangeType <T>()); } } else if (options != null && options.ContainsKey("return_raw")) { using (StreamReader sr = new StreamReader(webResponse.GetResponseStream())) { podioResponse.Body = sr.ReadToEnd(); return(podioResponse.Body); } } else { using (StreamReader sr = new StreamReader(webResponse.GetResponseStream())) { podioResponse.Body = sr.ReadToEnd(); } } podioResponse.Headers = responseHeaders; } } catch (WebException e) { using (WebResponse response = e.Response) { podioResponse.Status = (int)((HttpWebResponse)response).StatusCode; foreach (string key in response.Headers.AllKeys) { responseHeaders.Add(key, response.Headers[key]); } using (StreamReader sr = new StreamReader(response.GetResponseStream())) { podioResponse.Body = sr.ReadToEnd(); } podioResponse.Headers = responseHeaders; } } if (podioResponse.Headers.ContainsKey("X-Rate-Limit-Remaining")) { RateLimitRemaining = int.Parse(podioResponse.Headers["X-Rate-Limit-Remaining"]); } if (podioResponse.Headers.ContainsKey("X-Rate-Limit-Limit")) { RateLimit = int.Parse(podioResponse.Headers["X-Rate-Limit-Limit"]); } PodioError podioError = new PodioError(); if (podioResponse.Status >= 400) { podioError = JSONSerializer.Deserilaize <PodioError>(podioResponse.Body); } switch (podioResponse.Status) { case 200: case 201: responseObject = JSONSerializer.Deserilaize <T>(podioResponse.Body); break; case 204: responseObject = default(T); break; case 400: if (podioError.Error == "invalid_grant") { //Reset auth info OAuth = new PodioOAuth(); throw new PodioInvalidGrantException(podioResponse.Status, podioError); } else { throw new PodioBadRequestException(podioResponse.Status, podioError); } case 401: if (podioError.ErrorDescription == "expired_token" || podioError.Error == "invalid_token") { if (!string.IsNullOrEmpty(OAuth.RefreshToken)) { //Refresh access token var authInfo = await RefreshAccessTokenAsync(); if (authInfo != null && !string.IsNullOrEmpty(authInfo.AccessToken)) { responseObject = await RequestAsync <T>(requestMethod, originalUrl, requestData, options); } } else { throw new PodioAuthorizationException(podioResponse.Status, podioError); } } break; case 403: throw new PodioForbiddenException(podioResponse.Status, podioError); case 404: throw new PodioNotFoundException(podioResponse.Status, podioError); case 409: throw new PodioConflictException(podioResponse.Status, podioError); case 410: throw new PodioGoneException(podioResponse.Status, podioError); case 420: throw new PodioRateLimitException(podioResponse.Status, podioError); case 500: throw new PodioServerException(podioResponse.Status, podioError); case 502: case 503: case 504: throw new PodioUnavailableException(podioResponse.Status, podioError); default: throw new PodioException(podioResponse.Status, podioError); } return(responseObject); }