csharp/4egod/Bots/Twitter/Bots.Twitter/Api/BaseApiClient.cs

BaseApiClient.cs
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Bots.Twitter.Api
{
    using System.Net;

    internal abstract clast BaseApiClient
    {
        public readonly Version ApiVersion = new Version(1, 1);

        private HttpClient httpClient;

        public BaseApiClient(string consumerKey, string consumerSecret, string accessToken, string accessTokenSecret)
        {
            ConsumerKey = consumerKey;
            ConsumerSecret = consumerSecret;
            AccessToken = accessToken;
            AccessTokenSecret = accessTokenSecret;

            httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(ContentTypes.ApplicationJson));
        }

        public virtual string ApiUri => $"https://api.twitter.com/{ApiVersion}/";

        public string ConsumerKey { get; private set; }

        public string ConsumerSecret { get; private set; }

        public string AccessToken { get; private set; }

        public string AccessTokenSecret { get; private set; }

        protected async Task GetAsync(string uri)
        {
            string response;
            using (HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, uri))
            {
                req.Headers.Authorization = GetAuthorizationHeader(uri, HttpMethod.Get);
                response = await (await httpClient.SendAsync(req)).Content.ReadasttringAsync();
            }

            return Parse(response);
        }

        protected async Task PostAsync(object request, string uri)
        {
            string response;

            using (HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, uri))
            {
                req.Headers.Authorization = GetAuthorizationHeader(uri, HttpMethod.Post);
                if (request != null)
                {
#if DEBUG
                    string requestCmd = JsonConvert.SerializeObject(request, Formatting.Indented);
#else
                    string requestCmd = JsonConvert.SerializeObject(request);
#endif

                    req.Content = new StringContent(requestCmd, Encoding.UTF8, ContentTypes.ApplicationJson);
                }
                
                response = await (await httpClient.SendAsync(req)).Content.ReadasttringAsync();
            }

            return Parse(response);
        }

        protected async Task DeleteAsync(string uri)
        {
            HttpStatusCode code;
            using (HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Delete, uri))
            {
                req.Headers.Authorization = GetAuthorizationHeader(uri, HttpMethod.Delete);
                var res = await httpClient.SendAsync(req);
                code = res.StatusCode;
            }

            return code;
        }

        private T Parse(string response)
        {
            var errorContainer = JsonConvert.DeserializeObject(response);
            if (errorContainer.Errors != null)
            {
                if (errorContainer.Errors.Count == 1)
                {
                    throw new ApiException(errorContainer.Errors[0]);
                }
                else
                {
                    throw new ApiException(response);
                }
            }

            T res = JsonConvert.DeserializeObject(response);

            return res;
        }

        protected AuthenticationHeaderValue GetAuthorizationHeader(string uri, HttpMethod method)
        {
            string nonce = DateTime.Now.Ticks.ToString();
            string timestamp = DateTime.Now.ToUnixTimestamp().ToString();

            List authParams = new List();
            authParams.Add("oauth_consumer_key=" + ConsumerKey);
            authParams.Add("oauth_nonce=" + nonce);
            authParams.Add("oauth_signature_method=HMAC-SHA1");
            authParams.Add("oauth_timestamp=" + timestamp);
            authParams.Add("oauth_token=" + AccessToken);
            authParams.Add("oauth_version=1.0");

            SplitUri(uri, out string url, out string[] queryParams);

            List requestParams = new List(authParams);
            requestParams.AddRange(queryParams);
            requestParams.Sort();

            string signatureBaseString = string.Join("&", requestParams);
            signatureBaseString = string.Concat(method.Method.ToUpper(), "&", Uri.EscapeDataString(url), "&", Uri.EscapeDataString(signatureBaseString));

            string signature = GetSignature(signatureBaseString);

            string hv = string.Join(", ", authParams.Select(x => x.Replace("=", " = \"") + '"'));
            hv += $", oauth_signature=\"{Uri.EscapeDataString(signature)}\"";      

            return new AuthenticationHeaderValue("OAuth", hv);
        }

        protected string GetSignature(string signatureBaseString)
        {
            byte[] key = Encoding.ASCII.GetBytes(string.Concat(Uri.EscapeDataString(ConsumerSecret), "&", Uri.EscapeDataString(AccessTokenSecret)));

            string signature;
            using (HMACSHA1 hasher = new HMACSHA1(key))
            {
                signature = Convert.ToBase64String(hasher.ComputeHash(Encoding.ASCII.GetBytes(signatureBaseString)));
            }

            return signature;
        }

        protected void SplitUri(string uri, out string url, out string[] queryParams)
        {
            int pos = uri.IndexOf('?');
            if (pos == -1)
            {
                url = uri;
                queryParams = new string[0];
            }
            else
            {
                url = uri.Substring(0, pos);
                queryParams = uri.Substring(pos + 1).Split('&');
            }
        }
    }
}