Exemple #1
0
        /// <summary>
        /// Converts the current instance to a <see cref="MethodParameterSet"/>/
        /// </summary>
        /// <returns>
        /// A <see cref="MethodParameterSet"/>.
        /// </returns>
		public MethodParameterSet ToMethodParameterSet()
		{
			var result = new MethodParameterSet(parameters);

			if (State != PostCreationState.Published)
				result.Add("state", State.ToString().ToLowerInvariant());

			if (Tags != null)
				result.Add("tags", String.Join(",", Tags.ToArray()));

			if (!String.IsNullOrEmpty(Tweet))
				result.Add("tweet", Tweet);

			if (Date != null)
				result.Add("date", Date.Value.ToUniversalTime().ToString("R"));

			if (Format != PostFormat.Html)
				result.Add("format", Format.ToString().ToLowerInvariant());

			if (!String.IsNullOrEmpty(Slug))
				result.Add("slug", Slug);

			return result;
		}
		/// <summary>
		/// Asynchronously retrieves a specific post by id.
		/// </summary>
		/// <param name="id">
		/// The id of the post to retrieve.
		/// </param>
		/// <param name="includeReblogInfo">
		/// Whether or not to include reblog info with the posts.
		/// </param>
		/// <param name="includeNotesInfo">
		/// Whether or not to include notes info with the posts.
		/// </param>
		/// <returns>
		/// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will
		/// carry a <see cref="BasePost"/> instance representing the desired post. Otherwise <see cref="Task.Exception"/> will carry a 
		/// <see cref="TumblrException"/> if the post with the specified id cannot be found.
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="ArgumentOutOfRangeException">
		///	<paramref name="id"/> is less than 0.
		/// </exception>
		public Task<BasePost> GetPostAsync(long id, bool includeReblogInfo = false, bool includeNotesInfo = false)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (id < 0)
				throw new ArgumentOutOfRangeException("id", "id must be greater or equal to zero.");

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("api_key", apiKey);
			parameters.Add("id", id, 0);
			parameters.Add("reblog_info", includeReblogInfo, false);
			parameters.Add("notes_info", includeNotesInfo, false);

			return CallApiMethodAsync<Posts, BasePost>(
				new BlogMethod("dummy", "posts", null, HttpMethod.Get, parameters),
				p => p.Result.FirstOrDefault(),
				CancellationToken.None);
		}
		/// <summary>
		/// Asynchronously retrieves the current user's likes.
		/// </summary>
		/// <remarks>
		/// See: http://www.tumblr.com/docs/en/api/v2#m-ug-likes
		/// </remarks>
		/// <param name="startIndex">
		/// The offset at which to start retrieving the likes. Use 0 to start retrieving from the latest like.
		/// </param>
		/// <param name="count">
		/// The number of likes to retrieve. Must be between 1 and 20.
		/// </param>
		/// <returns>
		/// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will
		/// carry a <see cref="Likes"/> instance. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/>
		/// representing the error occurred during the call.
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// This <see cref="TumblrClient"/> instance does not have an OAuth token specified.
		/// </exception>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <list type="bullet">
		/// <item>
		///		<description>
		///			<paramref name="startIndex"/> is less than 0.
		///		</description>
		///	</item>
		///	<item>
		///		<description>
		///			<paramref name="count"/> is less than 1 or greater than 20.
		///		</description>
		///	</item>
		/// </list>
		/// </exception>
		public Task<Likes> GetUserLikesAsync(int startIndex = 0, int count = 20)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (startIndex < 0)
				throw new ArgumentOutOfRangeException("startIndex", "startIndex must be greater or equal to zero.");

			if (count < 1 || count > 20)
				throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20.");

			if (OAuthToken == null)
				throw new InvalidOperationException("GetBlogLikesAsync method requires an OAuth token to be specified.");

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("offset", startIndex, 0);
			parameters.Add("limit", count, 0);

			return CallApiMethodAsync<Likes>(
				new UserMethod("likes", OAuthToken, HttpMethod.Get, parameters),
				CancellationToken.None);
		}
		/// <summary>
		/// Asynchronously retrieves published posts from a blog.
		/// </summary>
		/// <remarks>
		/// See: http://www.tumblr.com/docs/en/api/v2#posts
		/// </remarks>
		/// <param name="blogName">
		/// The name of the blog.
		/// </param>
		/// <param name="startIndex">
		/// The offset at which to start retrieving the posts. Use 0 to start retrieving from the latest post.
		/// </param>
		/// <param name="count">
		/// The number of posts to retrieve. Must be between 1 and 20.
		/// </param>
		/// <param name="type">
		/// The <see cref="PostType"/> to retrieve.
		/// </param>
		/// <param name="includeReblogInfo">
		/// Whether or not to include reblog info with the posts.
		/// </param>
		/// <param name="includeNotesInfo">
		/// Whether or not to include notes info with the posts.
		/// </param>
		/// <param name="filter">
		/// A <see cref="PostFilter"/> to apply.
		/// </param>
		/// <param name="tag">
		/// A tag to filter by.
		/// </param>
		/// <returns>
		/// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will
		/// carry a <see cref="Posts"/> instance. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/>
		/// representing the error occurred during the call.
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="blogName"/> is <b>null</b>.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// <paramref name="blogName"/> is empty.
		/// </exception>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <list type="bullet">
		/// <item>
		///		<description>
		///			<paramref name="startIndex"/> is less than 0.
		///		</description>
		///	</item>
		///	<item>
		///		<description>
		///			<paramref name="count"/> is less than 1 or greater than 20.
		///		</description>
		///	</item>
		/// </list>
		/// </exception>
		public Task<Posts> GetPostsAsync(string blogName, long startIndex = 0, int count = 20, PostType type = PostType.All, bool includeReblogInfo = false, bool includeNotesInfo = false, PostFilter filter = PostFilter.Html, string tag = null)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (blogName == null)
				throw new ArgumentNullException("blogName");

			if (blogName.Length == 0)
				throw new ArgumentException("Blog name cannot be empty.", "blogName");

			if (startIndex < 0)
				throw new ArgumentOutOfRangeException("startIndex", "startIndex must be greater or equal to zero.");

			if (count < 1 || count > 20)
				throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20.");

			string methodName = null;
			switch (type)
			{
				case PostType.Text: methodName = "posts/text"; break;
				case PostType.Quote: methodName = "posts/quote"; break;
				case PostType.Link: methodName = "posts/link"; break;
				case PostType.Answer: methodName = "posts/answer"; break;
				case PostType.Video: methodName = "posts/video"; break;
				case PostType.Audio: methodName = "posts/audio"; break;
				case PostType.Photo: methodName = "posts/photo"; break;
				case PostType.Chat: methodName = "posts/chat"; break;
				case PostType.All:
				default: methodName = "posts"; break;
			}

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("api_key", apiKey);
			parameters.Add("offset", startIndex, 0);
			parameters.Add("limit", count, 0);
			parameters.Add("reblog_info", includeReblogInfo, false);
			parameters.Add("notes_info", includeNotesInfo, false);
			parameters.Add("filter", filter.ToString().ToLowerInvariant(), "html");
			parameters.Add("tag", tag);

			return CallApiMethodAsync<Posts>(
				new BlogMethod(blogName, methodName, null, HttpMethod.Get, parameters),
				CancellationToken.None);
		}
		/// <summary>
		/// Asynchronously retrieves posts from the current user's dashboard.
		/// </summary>
		/// See:  http://www.tumblr.com/docs/en/api/v2#m-ug-dashboard
		/// <param name="sinceId">
		///  Return posts that have appeared after the specified ID. Use this parameter to page through the results: first get a set 
		///  of posts, and then get posts since the last ID of the previous set.  
		/// </param>
		/// <param name="startIndex">
		/// The post number to start at.
		/// </param>
		/// <param name="count">
		/// The number of posts to return.
		/// </param>
		/// <param name="type">
		/// The <see cref="PostType"/> to return.
		/// </param>
		/// <param name="includeReblogInfo">
		/// Whether or not the response should include reblog info.
		/// </param>
		/// <param name="includeNotesInfo">
		/// Whether or not the response should include notes info.
		/// </param>
		/// <returns>
		/// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will
		/// carry an array of posts. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/>
		/// representing the error occurred during the call.
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// This <see cref="TumblrClient"/> instance does not have an OAuth token specified.
		/// </exception>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <list type="bullet">
		/// <item>
		///		<description>
		///			<paramref name="sinceId"/> is less than 0.
		///		</description>
		///	</item>
		/// <item>
		///		<description>
		///			<paramref name="startIndex"/> is less than 0.
		///		</description>
		///	</item>
		///	<item>
		///		<description>
		///			<paramref name="count"/> is less than 1 or greater than 20.
		///		</description>
		///	</item>
		/// </list>
		/// </exception>
		public Task<BasePost[]> GetDashboardPostsAsync(long sinceId = 0, long startIndex = 0, int count = 20, PostType type = PostType.All, bool includeReblogInfo = false, bool includeNotesInfo = false)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (sinceId < 0)
				throw new ArgumentOutOfRangeException("sinceId", "sinceId must be greater or equal to zero.");

			if (startIndex < 0)
				throw new ArgumentOutOfRangeException("startIndex", "startIndex must be greater or equal to zero.");

			if (count < 1 || count > 20)
				throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20.");

			if (OAuthToken == null)
				throw new InvalidOperationException("GetDashboardPostsAsync method requires an OAuth token to be specified.");

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("type", type.ToString().ToLowerInvariant(), "all");
			parameters.Add("since_id", sinceId, 0);
			parameters.Add("offset", startIndex, 0);
			parameters.Add("limit", count, 0);
			parameters.Add("reblog_info", includeReblogInfo, false);
			parameters.Add("notes_info", includeNotesInfo, false);

			return CallApiMethodAsync<PostCollection, BasePost[]>(
				new UserMethod("dashboard", OAuthToken, HttpMethod.Get, parameters),
				r => r.Posts,
				CancellationToken.None);
		}
        public Task<TagDiscoveryInfo> GetTagDiscovery(Token OAuthToken)
        {
            MethodParameterSet parameters = new MethodParameterSet();
            parameters.Add("api_key", apiKey);

            return CallApiMethodAsync<TagDiscoveryInfo>(
                new ApiMethod("http://api.tumblr.com/v2/tag_discovery", OAuthToken, HttpMethod.Get, parameters),
                CancellationToken.None);
        }
		/// <summary>
		/// Asynchronously retrieves submission posts.
		/// </summary>
		/// <remarks>
		/// See: http://www.tumblr.com/docs/en/api/v2#blog-submissions
		/// </remarks>
		/// <param name="blogName">
		/// The name of the blog for which to retrieve submission posts. 
		/// </param>
		/// <param name="startIndex">
		/// The post number to start at. Pass 0 to start from the first post.
		/// </param>
		/// <param name="filter">
		/// A <see cref="PostFilter"/> to apply.
		/// </param>
		/// <returns>
		/// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will
		/// carry an array of posts. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/>
		/// representing the error occurred during the call.
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="blogName"/> is <b>null</b>.
		///	</exception>
		/// <exception cref="ArgumentException">
		/// <paramref name="blogName"/> is empty.
		///	</exception>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <paramref name="startIndex"/> is less than 0.
		///	</exception>
		/// <exception cref="InvalidOperationException">
		/// This <see cref="TumblrClient"/> instance does not have an OAuth token specified.
		/// </exception>
		public Task<BasePost[]> GetSubmissionPostsAsync(string blogName, long startIndex = 0, PostFilter filter = PostFilter.Html)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (blogName == null)
				throw new ArgumentNullException("blogName");

			if (blogName.Length == 0)
				throw new ArgumentException("Blog name cannot be empty.", "blogName");

			if (startIndex < 0)
				throw new ArgumentOutOfRangeException("startIndex", "startIndex must be greater or equal to zero.");

			if (OAuthToken == null)
				throw new InvalidOperationException("GetSubmissionPostsAsync method requires an OAuth token to be specified.");

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("offset", startIndex);
			parameters.Add("filter", filter.ToString().ToLowerInvariant(), "html");

			return CallApiMethodAsync<PostCollection, BasePost[]>(
				new BlogMethod(blogName, "posts/submission", OAuthToken, HttpMethod.Get, parameters),
				r => r.Posts,
				CancellationToken.None);
		}
		/// <summary>
		/// Asynchronously reblogs a post.
		/// </summary>
		/// <remarks>
		/// See: http://www.tumblr.com/docs/en/api/v2#reblogging
		/// </remarks>
		/// <param name="blogName">
		/// The name of the blog where to reblog the psot (must be one of the current user's blogs).
		/// </param>
		/// <param name="postId">
		/// The identifier of the post to reblog.
		/// </param>
		/// <param name="reblogKey">
		/// The post reblog key.
		/// </param>
		/// <param name="comment">
		/// An optional comment to add to the reblog.
		/// </param>
		/// <returns>
		/// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will
		/// carry a <see cref="PostCreationInfo"/> instance. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/>
		/// representing the error occurred during the call.
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="ArgumentNullException">
		/// <list type="bullet">
		/// <item>
		///		<description>
		///			<paramref name="blogName"/> is <b>null</b>.
		///		</description>
		///	</item>
		///	<item>
		///		<description>
		///			<paramref name="reblogKey"/> is <b>null</b>.
		///		</description>
		///	</item>
		/// </list>
		/// </exception>
		/// <exception cref="ArgumentException">
		/// /// <list type="bullet">
		/// <item>
		///		<description>
		///			<paramref name="blogName"/> is empty.
		///		</description>
		///	</item>
		///	<item>
		///		<description>
		///			<paramref name="reblogKey"/> is empty.
		///		</description>
		///	</item>
		/// </list>
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// This <see cref="TumblrClient"/> instance does not have an OAuth token specified.
		/// </exception>
		public Task<PostCreationInfo> ReblogAsync(string blogName, long postId, string reblogKey, string comment = null)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (blogName == null)
				throw new ArgumentNullException("blogName");

			if (blogName.Length == 0)
				throw new ArgumentException("Blog name cannot be empty.", "blogName");

			if (postId <= 0)
				throw new ArgumentException("Post ID must be greater than 0.", "postId");

			if (reblogKey == null)
				throw new ArgumentNullException("reblogKey");

			if (reblogKey.Length == 0)
				throw new ArgumentException("reblogKey cannot be empty.", "reblogKey");

			if (OAuthToken == null)
				throw new InvalidOperationException("ReblogAsync method requires an OAuth token to be specified.");

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("id", postId);
			parameters.Add("reblog_key", reblogKey);
			parameters.Add("comment", comment, null);

			return CallApiMethodAsync<PostCreationInfo>(
				new UserMethod("post/reblog", OAuthToken, HttpMethod.Post, parameters),
				CancellationToken.None);
		}
		/// <summary>
		/// Asynchronously deletes a post.
		/// </summary>
		/// <remarks>
		/// See: http://www.tumblr.com/docs/en/api/v2#deleting-posts
		/// </remarks>
		/// <param name="blogName">
		/// The name of the blog to which the post to delete belongs.
		/// </param>
		/// <param name="postId">
		/// The identifier of the post to delete.
		/// </param>
		/// <returns>
		/// A <see cref="Task{T}"/> that can be used to track the operation. If the task fails, <see cref="Task.Exception"/> 
		/// will carry a <see cref="TumblrException"/> representing the error occurred during the call.
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="blogName"/> is <b>null</b>.
		///	</exception>
		/// <exception cref="ArgumentException">
		/// <paramref name="blogName"/> is empty.
		///	</exception>
		///	<exception cref="ArgumentOutOfRangeException">
		///	<paramref name="postId"/> is less than 0.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// This <see cref="TumblrClient"/> instance does not have an OAuth token specified.
		/// </exception>
		public Task DeletePostAsync(string blogName, long postId)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (blogName == null)
				throw new ArgumentNullException("blogName");

			if (blogName.Length == 0)
				throw new ArgumentException("Blog name cannot be empty.", "blogName");

			if (postId < 0)
				throw new ArgumentOutOfRangeException("postId", "Post ID must be greater or equal to zero.");

			if (OAuthToken == null)
				throw new InvalidOperationException("DeletePostAsync method requires an OAuth token to be specified.");

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("id", postId);

			return CallApiMethodNoResultAsync(
				new BlogMethod(blogName, "post/delete", OAuthToken, HttpMethod.Post, parameters),
				CancellationToken.None);
		}
Exemple #10
0
		/// <summary>
		/// Gets the authorized access token that can be used to make OAuth calls.
		/// </summary>
		/// <param name="requestToken">
		/// The request token sent from the server to the <b>callback url</b>.
		/// </param>
		/// <param name="verifierUrl">
		/// The verifier url returned from the server.
		/// </param>
		/// <returns>
		/// The access token.
		/// </returns>
		/// <exception cref="ArgumentNullException">
		/// <list type="bullet">
		/// <item>
		///		<description>
		///			<paramref name="requestToken"/> is <b>null</b>.
		///		</description>
		///	</item>
		///	<item>
		///		<description>
		///			<paramref name="verifierUrl"/> is <b>null</b>.
		///		</description>
		///	</item>
		/// </list>
		/// </exception>
		/// <exception cref="ArgumentException">
		/// <paramref name="verifierUrl"/> is empty.
		/// </exception>
		/// <exception cref="OAuthException">
		/// <list type="bullet">
		/// <item>
		///		<description>
		///			Could not determine oauth_token and oauth_token_secret from server response.
		///		</description>
		///	</item>
		///	<item>
		///		<description>
		///			An exception occurred during the method call.
		///		</description>
		///	</item>
		/// </list>
		/// </exception>
		public async Task<Token> GetAccessTokenAsync(Token requestToken, string verifierUrl)
		{
			if (requestToken == null)
				throw new ArgumentNullException("requestToken");

			if (verifierUrl == null)
				throw new ArgumentNullException("verifierUrl");

			if (verifierUrl.Length == 0)
				throw new ArgumentException("Verifier URL cannot be empty.", "verifierUrl");

			Uri uri = new Uri(verifierUrl, UriKind.RelativeOrAbsolute);
			string verifierString = (uri.IsAbsoluteUri) ? uri.Query : verifierUrl;

			System.Text.RegularExpressions.Match m = oauthVerifierRegEx.Match(verifierString);
			if (m.Success)
			{
				string token = m.Groups["token"].Value;
				string verifier = m.Groups["verifier"].Value;

				MethodParameterSet authorizationHeaderParameters = new MethodParameterSet();
				authorizationHeaderParameters.Add("oauth_token", token);
				authorizationHeaderParameters.Add("oauth_verifier", verifier);

				var requestParameters = new Dictionary<string, string>() 
				{
					{ "oauth_token", token },
					{ "oauth_verifier", verifier },
				};

                using (var client = new HttpClient(new OAuthMessageHandler(hashProvider, consumerKey, consumerSecret, requestToken)))
				{
					var request = new HttpRequestMessage(HttpMethod.Post, accessTokenUrl);
					request.Content = new FormUrlEncodedContent(requestParameters);

					using (var response = await client.SendAsync(request).ConfigureAwait(false))
					{
						if (response.IsSuccessStatusCode)
						{
							string tokenString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

							System.Text.RegularExpressions.Match m1 = xauthTokensRegEx.Match(tokenString);
							if (m1.Success)
							{
								return new Token(m1.Groups["token"].Value, m1.Groups["secret"].Value);
							}
							else
							{
								throw new OAuthException("Could not determine oauth_token and oauth_token_secret from server response.");
							}
						}
						else
						{
							throw new OAuthException(String.Format("GetAccessTokenAsync failed. Status Code: {0}, Message: {1}", response.StatusCode, response.ReasonPhrase));
						}
					}
				}
			}
			else
			{
				throw new OAuthException("Could not parse response to callback URL");
			}
		}
Exemple #11
0
        /// <summary>
        /// Gets the authorized access token that can be used to make OAuth calls.
        /// </summary>
        /// <param name="requestToken">
        /// The request token sent from the server to the <b>callback url</b>.
        /// </param>
        /// <param name="verifierUrl">
        /// The verifier url returned from the server.
        /// </param>
        /// <returns>
        /// The access token.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <list type="bullet">
        /// <item>
        ///		<description>
        ///			<paramref name="requestToken"/> is <b>null</b>.
        ///		</description>
        ///	</item>
        ///	<item>
        ///		<description>
        ///			<paramref name="verifierUrl"/> is <b>null</b>.
        ///		</description>
        ///	</item>
        /// </list>
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="verifierUrl"/> is empty.
        /// </exception>
        /// <exception cref="OAuthException">
        /// <list type="bullet">
        /// <item>
        ///		<description>
        ///			Could not determine oauth_token and oauth_token_secret from server response.
        ///		</description>
        ///	</item>
        ///	<item>
        ///		<description>
        ///			An exception occurred during the method call.
        ///		</description>
        ///	</item>
        /// </list>
        /// </exception>
        public async Task <Token> GetAccessTokenAsync(Token requestToken, string verifierUrl)
        {
            if (requestToken == null)
            {
                throw new ArgumentNullException("requestToken");
            }

            if (verifierUrl == null)
            {
                throw new ArgumentNullException("verifierUrl");
            }

            if (verifierUrl.Length == 0)
            {
                throw new ArgumentException("Verifier URL cannot be empty.", "verifierUrl");
            }

            Uri    uri            = new Uri(verifierUrl, UriKind.RelativeOrAbsolute);
            string verifierString = (uri.IsAbsoluteUri) ? uri.Query : verifierUrl;

            System.Text.RegularExpressions.Match m = oauthVerifierRegEx.Match(verifierString);
            if (m.Success)
            {
                string token    = m.Groups["token"].Value;
                string verifier = m.Groups["verifier"].Value;

                MethodParameterSet authorizationHeaderParameters = new MethodParameterSet();
                authorizationHeaderParameters.Add("oauth_token", token);
                authorizationHeaderParameters.Add("oauth_verifier", verifier);

                var requestParameters = new Dictionary <string, string>()
                {
                    { "oauth_token", token },
                    { "oauth_verifier", verifier },
                };

                using (var client = new HttpClient(new OAuthMessageHandler(hashProvider, consumerKey, consumerSecret, requestToken)))
                {
                    var request = new HttpRequestMessage(HttpMethod.Post, accessTokenUrl);
                    request.Content = new FormUrlEncodedContent(requestParameters);

                    using (var response = await client.SendAsync(request).ConfigureAwait(false))
                    {
                        if (response.IsSuccessStatusCode)
                        {
                            string tokenString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                            System.Text.RegularExpressions.Match m1 = xauthTokensRegEx.Match(tokenString);
                            if (m1.Success)
                            {
                                return(new Token(m1.Groups["token"].Value, m1.Groups["secret"].Value));
                            }
                            else
                            {
                                throw new OAuthException("Could not determine oauth_token and oauth_token_secret from server response.");
                            }
                        }
                        else
                        {
                            throw new OAuthException(String.Format("GetAccessTokenAsync failed. Status Code: {0}, Message: {1}", response.StatusCode, response.ReasonPhrase));
                        }
                    }
                }
            }
            else
            {
                throw new OAuthException("Could not parse response to callback URL");
            }
        }
Exemple #12
0
        public Task<Likes> GetUserLikesBeforeAsync(DateTime? before = null, int count = 20)
        {
            if (disposed)
                throw new ObjectDisposedException("TumblrClient");

            if (count < 1 || count > 20)
                throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20.");

            if (OAuthToken == null)
                throw new InvalidOperationException("GetBlogLikesBeforeAsync method requires an OAuth token to be specified.");

            MethodParameterSet parameters = new MethodParameterSet();
            parameters.Add("before", before.HasValue ? DateTimeHelper.ToTimestamp(before.Value).ToString() : null, null);
            parameters.Add("limit", count, 0);

            return CallApiMethodAsync<Likes>(
                new UserMethod("likes", OAuthToken, HttpMethod.Get, parameters),
                CancellationToken.None);
        }
Exemple #13
0
        /// <summary>
        /// Asynchronously retrieves posts that have been tagged with a specific <paramref name="tag"/>.
        /// </summary>
        /// <remarks>
        /// See: http://www.tumblr.com/docs/en/api/v2#m-up-tagged
        /// </remarks>
        /// <param name="tag">
        /// The tag on the posts to retrieve.
        /// </param>
        /// <param name="before">
        /// The timestamp of when to retrieve posts before. 
        /// </param>
        /// <param name="count">
        /// The number of posts to retrieve.
        /// </param>
        /// <param name="filter">
        /// A <see cref="PostFilter"/>.
        /// </param>
        /// <returns>
        /// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will
        /// carry an array of posts. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/>
        /// representing the error occurred during the call.
        /// </returns>
        /// <exception cref="ObjectDisposedException">
        /// The object has been disposed.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="tag"/> is <b>null</b>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="tag"/> is empty.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// This <see cref="TumblrClient"/> instance does not have an OAuth token specified.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="count"/> is less than 1 or greater than 20.
        /// </exception>
        public Task<BasePost[]> GetTaggedPostsAsync(string tag, DateTime before, int count = 20, PostFilter filter = PostFilter.Html)
        {
            if (disposed)
                throw new ObjectDisposedException("TumblrClient");

            if (tag == null)
                throw new ArgumentNullException("tag");

            if (tag.Length == 0)
                throw new ArgumentException("Tag cannot be empty.", "tag");

            if (count < 1 || count > 20)
                throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20.");

            MethodParameterSet parameters = new MethodParameterSet();
            parameters.Add("api_key", apiKey);
            parameters.Add("tag", tag);

            return CallApiMethodAsync<BasePost[]>(
                new ApiMethod("http://api.tumblr.com/v2/tagged", OAuthToken, HttpMethod.Get, parameters),
                CancellationToken.None, new List<JsonConverter>() { new PostArrayConverter() });
        }
		/// <summary>
		/// Asynchronously retrieves the publicly exposed likes from a blog.
		/// </summary>
		/// <remarks>
		/// See: http://www.tumblr.com/docs/en/api/v2#blog-likes
		/// </remarks>
		/// <param name="blogName">
		/// The name of the blog.
		/// </param>
		/// <param name="startIndex">
		/// The offset at which to start retrieving the likes. Use 0 to start retrieving from the latest like.
		/// </param>
		/// <param name="count">
		/// The number of likes to retrieve. Must be between 1 and 20.
		/// </param>
		/// <returns>
		/// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will
		/// carry a <see cref="Likes"/> instance. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/>
		/// representing the error occurred during the call.
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="blogName"/> is <b>null</b>.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// <paramref name="blogName"/> is empty.
		/// </exception>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <list type="bullet">
		/// <item>
		///		<description>
		///			<paramref name="startIndex"/> is less than 0.
		///		</description>
		///	</item>
		///	<item>
		///		<description>
		///			<paramref name="count"/> is less than 1 or greater than 20.
		///		</description>
		///	</item>
		/// </list>
		/// </exception>
		public Task<Likes> GetBlogLikesAsync(string blogName, int startIndex = 0, int count = 20)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (blogName == null)
				throw new ArgumentNullException("blogName");

			if (blogName.Length == 0)
				throw new ArgumentException("Blog name cannot be empty.", "blogName");

			if (startIndex < 0)
				throw new ArgumentOutOfRangeException("startIndex", "startIndex must be greater or equal to zero.");

			if (count < 1 || count > 20)
				throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20.");

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("api_key", apiKey);
			parameters.Add("offset", startIndex, 0);
			parameters.Add("limit", count, 0);

			return CallApiMethodAsync<Likes>(
				new BlogMethod(blogName, "likes", null, HttpMethod.Get, parameters),
				CancellationToken.None);
		}
		/// <summary>
		/// Asynchronously unlikes a post.
		/// </summary>
		/// <remarks>
		/// See: http://www.tumblr.com/docs/en/api/v2#m-up-unlike
		/// </remarks>
		/// <param name="postId">
		/// The identifier of the post to like.
		/// </param>
		/// <param name="reblogKey">
		/// The reblog key for the post.
		/// </param>
		/// <returns>
		/// A <see cref="Task{T}"/> that can be used to track the operation. If the task fails, <see cref="Task.Exception"/> 
		/// will carry a <see cref="TumblrException"/>
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="reblogKey"/> is <b>null</b>.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// <paramref name="reblogKey"/> is empty.
		/// </exception>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <paramref name="postId"/> is less than 0.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// This <see cref="TumblrClient"/> instance does not have an OAuth token specified.
		/// </exception>
		public Task UnlikeAsync(long postId, string reblogKey)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (postId <= 0)
				throw new ArgumentException("Post ID must be greater than 0.", "postId");

			if (reblogKey == null)
				throw new ArgumentNullException("reblogKey");

			if (reblogKey.Length == 0)
				throw new ArgumentException("reblogKey cannot be empty.", "reblogKey");

			if (OAuthToken == null)
				throw new InvalidOperationException("UnlikeAsync method requires an OAuth token to be specified.");

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("id", postId);
			parameters.Add("reblog_key", reblogKey);

			return CallApiMethodNoResultAsync(
				new UserMethod("unlike", OAuthToken, HttpMethod.Post, parameters),
				CancellationToken.None);
		}
		/// <summary>
		/// Asynchronously retrieves a blog's followers.
		/// </summary>
		/// <remarks>
		/// See: http://www.tumblr.com/docs/en/api/v2#blog-followers
		/// </remarks>
		/// <param name="blogName">
		/// The name of the blog.
		/// </param>
		/// <param name="startIndex">
		/// The offset at which to start retrieving the followers. Use 0 to start retrieving from the latest follower.
		/// </param>
		/// <param name="count">
		/// The number of followers to retrieve. Must be between 1 and 20.
		/// </param>
		/// <returns>
		///  A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will
		/// carry a <see cref="Followers"/> instance. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/>
		/// A <see cref="Followers"/> instance.
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="blogName"/> is <b>null</b>.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// <paramref name="blogName"/> is empty.
		/// </exception>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <list type="bullet">
		/// <item>
		///		<description>
		///			<paramref name="startIndex"/> is less than 0.
		///		</description>
		///	</item>
		///	<item>
		///		<description>
		///			<paramref name="count"/> is less than 1 or greater than 20.
		///		</description>
		///	</item>
		/// </list>
		/// </exception>
		public Task<Followers> GetFollowersAsync(string blogName, int startIndex = 0, int count = 20)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (blogName == null)
				throw new ArgumentNullException("blogName");

			if (blogName.Length == 0)
				throw new ArgumentException("Blog name cannot be empty.", "blogName");

			if (startIndex < 0)
				throw new ArgumentOutOfRangeException("startIndex", "startIndex must be greater or equal to zero.");

			if (count < 1 || count > 20)
				throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20.");

			if (OAuthToken == null)
				throw new InvalidOperationException("GetFollowersAsync method requires an OAuth token to be specified.");

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("offset", startIndex, 0);
			parameters.Add("limit", count, 0);

			return CallApiMethodAsync<Followers>(
				new BlogMethod(blogName, "followers", OAuthToken, HttpMethod.Get, parameters),
				CancellationToken.None);
		}
		/// <summary>
		/// Asynchronously unfollows a blog.
		/// </summary>
		/// <remarks>
		/// See: http://www.tumblr.com/docs/en/api/v2#m-up-unfollow
		/// </remarks>
		/// <param name="blogUrl">
		/// The url of the blog to unfollow.
		/// </param>
		/// <returns>
		/// A <see cref="Task{T}"/> that can be used to track the operation. If the task fails, <see cref="Task.Exception"/> 
		/// will carry a <see cref="TumblrException"/>
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="blogUrl"/> is <b>null</b>.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// <paramref name="blogUrl"/> is empty.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// This <see cref="TumblrClient"/> instance does not have an OAuth token specified.
		/// </exception>
		public Task UnfollowAsync(string blogUrl)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (blogUrl == null)
				throw new ArgumentNullException("blogUrl");

			if (blogUrl.Length == 0)
				throw new ArgumentException("Blog url cannot be empty.", "blogUrl");

			if (OAuthToken == null)
				throw new InvalidOperationException("UnfollowAsync method requires an OAuth token to be specified.");

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("url", blogUrl);

			return CallApiMethodNoResultAsync(
				new UserMethod("unfollow", OAuthToken, HttpMethod.Get, parameters),
				CancellationToken.None);
		}
		/// <summary>
		/// Asynchronously retrieves general information about the blog, such as the title, number of posts, and other high-level data.
		/// </summary>
		/// <remarks>
		/// See: http://www.tumblr.com/docs/en/api/v2#blog-info.
		/// </remarks>
		/// <param name="blogName">
		/// The name of the blog.
		/// </param>
		/// <returns>
		/// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will
		/// carry a <see cref="BlogInfo"/> instance. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/>
		/// representing the error occurred during the call.
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="blogName"/> is <b>null</b>.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// <paramref name="blogName"/> is empty.
		/// </exception>
		public Task<BlogInfo> GetBlogInfoAsync(string blogName)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (blogName == null)
				throw new ArgumentNullException("blogName");

			if (blogName.Length == 0)
				throw new ArgumentException("Blog name cannot be empty.", "blogName");

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("api_key", apiKey);

			return CallApiMethodAsync<BlogInfoResponse, BlogInfo>(
				new BlogMethod(blogName, "info", OAuthToken, HttpMethod.Get, parameters),
				r => r.Blog,
				CancellationToken.None);
		}
		/// <summary>
		/// Asynchronously retrieves posts that have been tagged with a specific <paramref name="tag"/>.
		/// </summary>
		/// <remarks>
		/// See: http://www.tumblr.com/docs/en/api/v2#m-up-tagged
		/// </remarks>
		/// <param name="tag">
		/// The tag on the posts to retrieve.
		/// </param>
		/// <param name="before">
		/// The timestamp of when to retrieve posts before. 
		/// </param>
		/// <param name="count">
		/// The number of posts to retrieve.
		/// </param>
		/// <param name="filter">
		/// A <see cref="PostFilter"/>.
		/// </param>
		/// <returns>
		/// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will
		/// carry an array of posts. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/>
		/// representing the error occurred during the call.
		/// </returns>
		/// <exception cref="ObjectDisposedException">
		/// The object has been disposed.
		/// </exception>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="tag"/> is <b>null</b>.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// <paramref name="tag"/> is empty.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// This <see cref="TumblrClient"/> instance does not have an OAuth token specified.
		/// </exception>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <paramref name="count"/> is less than 1 or greater than 20.
		/// </exception>
		public Task<BasePost[]> GetTaggedPostsAsync(string tag, DateTime? before = null, int count = 20, PostFilter filter = PostFilter.Html)
		{
			if (disposed)
				throw new ObjectDisposedException("TumblrClient");

			if (tag == null)
				throw new ArgumentNullException("tag");

			if (tag.Length == 0)
				throw new ArgumentException("Tag cannot be empty.", "tag");

			if (count < 1 || count > 20)
				throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20.");

			MethodParameterSet parameters = new MethodParameterSet();
			parameters.Add("api_key", apiKey);
			parameters.Add("tag", tag);
			parameters.Add("before", before.HasValue ? DateTimeHelper.ToTimestamp(before.Value).ToString() : null, null);
			parameters.Add("limit", count, 0);
			parameters.Add("filter", filter.ToString().ToLowerInvariant(), "html");

			return CallApiMethodAsync<BasePost[]>(
				new ApiMethod("https://api.tumblr.com/v2/tagged", OAuthToken, HttpMethod.Get, parameters),
				CancellationToken.None,
				new JsonConverter[] { new PostArrayConverter() });
		}
		public async Task<HttpResponseMessage> NewSendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
		{
			MethodParameterSet requestParameters = null;
			if (request.Content is FormUrlEncodedContent)
			{
				var formUrlEncoded = request.Content as FormUrlEncodedContent;
				string content = await formUrlEncoded.ReadAsStringAsync().ConfigureAwait(false);

				requestParameters = new MethodParameterSet(content);
			}
			else if (request.Content is MultipartFormDataContent)
			{
				requestParameters = new MethodParameterSet();

				var multiPart = request.Content as MultipartFormDataContent;
				foreach (var c in ((MultipartFormDataContent)request.Content))
				{
					var stringContent = c as StringContent;
					if (stringContent != null)
						requestParameters.Add(c.Headers.ContentDisposition.Name, await c.ReadAsStringAsync().ConfigureAwait(false));
				}
			}

			//NOLONGERAPPLICABLE, REMOVED BY JLAUER - if we have an api_key parameter we can skip the oauth
			//if (requestParameters.FirstOrDefault(c => c.Name == "api_key") == null)
			//{
				var authorizationHeaderParameters = new MethodParameterSet(requestParameters);

				if (oAuthToken != null) authorizationHeaderParameters.Add("oauth_token", oAuthToken.Key);
				authorizationHeaderParameters.Add("oauth_consumer_key", consumerKey);
				authorizationHeaderParameters.Add("oauth_nonce", Guid.NewGuid().ToString());
				authorizationHeaderParameters.Add("oauth_timestamp", DateTimeHelper.ToTimestamp(DateTime.UtcNow).ToString());
				authorizationHeaderParameters.Add("oauth_signature_method", "HMAC-SHA1");
				authorizationHeaderParameters.Add("oauth_version", "1.0");

				string urlParameters = authorizationHeaderParameters.ToFormUrlEncoded();

				var requestUriNoQueryString = request.RequestUri.OriginalString;
				if (!String.IsNullOrEmpty(request.RequestUri.Query))
					requestUriNoQueryString = request.RequestUri.OriginalString.Replace(request.RequestUri.Query, String.Empty);

				string signatureBaseString = String.Format("{0}&{1}&{2}", request.Method.ToString(), UrlEncoder.Encode(requestUriNoQueryString), UrlEncoder.Encode(urlParameters));
				string signatureHash = hashProvider.ComputeHash(consumerSecret, (oAuthToken != null) ? oAuthToken.Secret : null, signatureBaseString);

				authorizationHeaderParameters.Add("oauth_signature", signatureHash);

				//NOLONGERAPPLICABLE, REMOVED BY JLAUER - if we have an api_key parameter we can skip the oauth
				//foreach (IMethodParameter p in requestParameters)
				//{
				//	//remove non-oauth parameters from the authorization header
				//	if (!p.Name.StartsWith("oauth"))
				//		authorizationHeaderParameters.Remove(p);
				//}

				request.Headers.Authorization = new AuthenticationHeaderValue("OAuth", authorizationHeaderParameters.ToAuthorizationHeader());
			//}

			if (request.Method == HttpMethod.Get)
				request.Content = null; //we don't have to send a body with get requests

			return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
		}
Exemple #21
0
        protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            MethodParameterSet requestParameters = null;

            if (request.Content is FormUrlEncodedContent)
            {
                var    formUrlEncoded = request.Content as FormUrlEncodedContent;
                string content        = await formUrlEncoded.ReadAsStringAsync().ConfigureAwait(false);

                requestParameters = new MethodParameterSet(content);
            }
            else if (request.Content is MultipartFormDataContent)
            {
                requestParameters = new MethodParameterSet();

                var multiPart = request.Content as MultipartFormDataContent;
                foreach (var c in ((MultipartFormDataContent)request.Content))
                {
                    var stringContent = c as StringContent;
                    if (stringContent != null)
                    {
                        requestParameters.Add(c.Headers.ContentDisposition.Name, await c.ReadAsStringAsync().ConfigureAwait(false));
                    }
                }
            }

            //if we have an api_key parameter we can skip the oauth
            if (requestParameters.FirstOrDefault(c => c.Name == "api_key") == null)
            {
                var authorizationHeaderParameters = new MethodParameterSet(requestParameters);

                if (oAuthToken != null)
                {
                    authorizationHeaderParameters.Add("oauth_token", oAuthToken.Key);
                }
                authorizationHeaderParameters.Add("oauth_consumer_key", consumerKey);
                authorizationHeaderParameters.Add("oauth_nonce", Guid.NewGuid().ToString());
                authorizationHeaderParameters.Add("oauth_timestamp", DateTimeHelper.ToTimestamp(DateTime.UtcNow).ToString());
                authorizationHeaderParameters.Add("oauth_signature_method", "HMAC-SHA1");
                authorizationHeaderParameters.Add("oauth_version", "1.0");

                string urlParameters = authorizationHeaderParameters.ToFormUrlEncoded();

                var requestUriNoQueryString = request.RequestUri.OriginalString;
                if (!String.IsNullOrEmpty(request.RequestUri.Query))
                {
                    requestUriNoQueryString = request.RequestUri.OriginalString.Replace(request.RequestUri.Query, String.Empty);
                }

                string signatureBaseString = String.Format("{0}&{1}&{2}", request.Method.ToString(), UrlEncoder.Encode(requestUriNoQueryString), UrlEncoder.Encode(urlParameters));
                string signatureHash       = hashProvider.ComputeHash(consumerSecret, (oAuthToken != null) ? oAuthToken.Secret : null, signatureBaseString);

                authorizationHeaderParameters.Add("oauth_signature", signatureHash);

                foreach (IMethodParameter p in requestParameters)
                {
                    //remove non-oauth parameters from the authorization header
                    if (!p.Name.StartsWith("oauth"))
                    {
                        authorizationHeaderParameters.Remove(p);
                    }
                }

                request.Headers.Authorization = new AuthenticationHeaderValue("OAuth", authorizationHeaderParameters.ToAuthorizationHeader());
            }

            if (request.Method == HttpMethod.Get)
            {
                request.Content = null;                 //we don't have to send a body with get requests
            }
            return(await base.SendAsync(request, cancellationToken).ConfigureAwait(false));
        }