Example #1
0
        /// <summary>
        /// helper method to make a get request to basecamp. checks cache first if you've already received that response and checks with basecamp if you
        /// need to update your cache.
        /// </summary>
        /// <param name="url">the api method endpoint being called</param>
        /// <exception cref="Exceptions.UnauthorizedException">Will be thrown if you cannot refresh the basecamp token when it has expired</exception>
        /// <exception cref="ArgumentException">URLs must end in .json</exception>
        /// <exception cref="Exceptions.RateLimitExceeded">Thrown when you exceed the ratelimit - will contain information on when you can retry</exception>
        private dynamic _getJSONFromURL(string url)
        {
            // ensure url ends with .json or .json?xxx
            if (!url.ToLower().EndsWith(".json") &&
                !(url.Contains("?") && url.ToLower().Substring(0, url.IndexOf("?")).EndsWith(".json")))
            {
                throw new ArgumentException("Invalid URL. URLs must end in .json", url);
            }

            string unique_id_to_hash = (_accessToken.access_token + url.ToLower());
            var    cacheKey          = unique_id_to_hash.CalculateMD5();

            try
            {
                //if in cache, check with server and if not modified then return original results
                string cached_results = (string)_cache.Get(cacheKey);
                if (cached_results != null)
                {
                    string if_none_match     = (string)_cache.Get(cacheKey + "etag");
                    string if_modified_since = (string)_cache.Get(cacheKey + "lastModified");

                    System.Net.HttpWebRequest wr = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(url);
                    wr.Method = "HEAD";
                    wr.Headers.Add(System.Net.HttpRequestHeader.Authorization, string.Format("Bearer {0}", _accessToken.access_token));
                    wr.UserAgent = _appNameAndContact;
                    if (!string.IsNullOrWhiteSpace(if_modified_since))
                    {
                        wr.IfModifiedSince = DateTime.Parse(if_modified_since);
                    }
                    if (!string.IsNullOrWhiteSpace(if_none_match))
                    {
                        wr.Headers["If-None-Match"] = if_none_match;
                    }
                    var resp = (System.Net.HttpWebResponse)wr.BetterGetResponse();//use extension to properly handle 304
                    if (resp.StatusCode == System.Net.HttpStatusCode.NotModified)
                    {
                        return(Json.Decode(cached_results));
                    }
                }
            }
            catch
            {
                //if cache check fails just make the real request to basecamp
            }

            try
            {
                System.Net.HttpWebRequest wr = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(url);
                wr.Method = "GET";
                wr.Headers.Add(System.Net.HttpRequestHeader.Authorization, string.Format("Bearer {0}", _accessToken.access_token));
                wr.UserAgent = _appNameAndContact;

                var resp = (System.Net.HttpWebResponse)wr.BetterGetResponse();
                if (resp.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    using (var sw = new System.IO.StreamReader(resp.GetResponseStream()))
                    {
                        var strResp            = sw.ReadToEnd();
                        var json_results       = Json.Decode(strResp);
                        var resp_etag          = resp.Headers["ETag"] != null ? resp.Headers["ETag"] : null;
                        var resp_last_modified = resp.Headers["Last-Modified"] != null ? resp.Headers["Last-Modified"] : null;

                        if (resp_etag != null || resp_last_modified != null)
                        {
                            //cache it
                            if (!string.IsNullOrWhiteSpace(resp_etag))
                            {
                                _cache.Set(cacheKey + "etag", resp_etag);
                            }
                            if (!string.IsNullOrWhiteSpace(resp_last_modified))
                            {
                                _cache.Set(cacheKey + "lastModified", resp_last_modified);
                            }
                            if (!string.IsNullOrWhiteSpace(strResp))
                            {
                                _cache.Set(cacheKey, strResp);
                            }
                        }
                        return(json_results);
                    }
                }
                else if (resp.StatusCode == (System.Net.HttpStatusCode) 429)//too many requests
                {
                    throw new Exceptions.RateLimitExceededException(int.Parse(resp.Headers["Retry-After"]));
                }
                else if (resp.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                {
                    if (resp.Headers[System.Net.HttpResponseHeader.WwwAuthenticate] != null)
                    {
                        string www_auth    = resp.Headers[System.Net.HttpResponseHeader.WwwAuthenticate];
                        int    error_start = www_auth.LastIndexOf("error=\"token_expired\"");
                        if (error_start > -1)
                        {       //need to refresh token
                            throw new Exceptions.TokenExpired();
                        }
                    }

                    //throw an unauthorized exception if you get here
                    throw new Exceptions.UnauthorizedException();
                }
                else
                {
                    throw new Exceptions.GeneralAPIException("Try again later. Status code returned was " + (int)resp.StatusCode, (int)resp.StatusCode);
                }
            }
            catch (Exceptions.BaseException)
            {
                throw;
            }
            catch
            {
                return(null);
            }
        }