PATCH Async requests with Windows.Web.Http.HttpClient class

Solution 1:

I found how to do a "custom" PATCH request with the previous System.Net.Http.HttpClient class here, and then fiddled with until I made it work in the Windows.Web.Http.HttpClient class, like so:

public async Task<HttpResponseMessage> PatchAsync(HttpClient client, Uri requestUri, IHttpContent iContent) {
    var method = new HttpMethod("PATCH");

    var request = new HttpRequestMessage(method, requestUri) {
        Content = iContent
    };

    HttpResponseMessage response = new HttpResponseMessage();
    // In case you want to set a timeout
    //CancellationToken cancellationToken = new CancellationTokenSource(60).Token;

    try {
         response = await client.SendRequestAsync(request);
         // If you want to use the timeout you set
         //response = await client.SendRequestAsync(request).AsTask(cancellationToken);
    } catch(TaskCanceledException e) {
        Debug.WriteLine("ERROR: " + e.ToString());
    }

    return response;
}

Solution 2:

Update: See SSX-SL33PY's answer below for an even better solution, that does the same thing.

You can write the very same method as extension method, so you can invoke it directly on the HttpClient object:

public static class HttpClientExtensions
{
   public static async Task<HttpResponseMessage> PatchAsync(this HttpClient client, Uri requestUri, HttpContent iContent)
   {
       var method = new HttpMethod("PATCH");
       var request = new HttpRequestMessage(method, requestUri)
       {
           Content = iContent
       };

       HttpResponseMessage response = new HttpResponseMessage();
       try
       {
           response = await client.SendAsync(request);
       }
       catch (TaskCanceledException e)
       {
           Debug.WriteLine("ERROR: " + e.ToString());
       }

       return response;
   }
}

Usage:

var responseMessage = await httpClient.PatchAsync(new Uri("testUri"), httpContent);

Solution 3:

I'd like to extend on @alexander-pacha's answer and suggest adding following extension class somewhere in a common library. Wether this be a common library for a project / client / framework/... is something you'll have to make out on your own.

    public static class HttpClientExtensions
    {
        /// <summary>
        /// Send a PATCH request to the specified Uri as an asynchronous operation.
        /// </summary>
        /// 
        /// <returns>
        /// Returns <see cref="T:System.Threading.Tasks.Task`1"/>.The task object representing the asynchronous operation.
        /// </returns>
        /// <param name="client">The instantiated Http Client <see cref="HttpClient"/></param>
        /// <param name="requestUri">The Uri the request is sent to.</param>
        /// <param name="content">The HTTP request content sent to the server.</param>
        /// <exception cref="T:System.ArgumentNullException">The <paramref name="client"/> was null.</exception>
        /// <exception cref="T:System.ArgumentNullException">The <paramref name="requestUri"/> was null.</exception>
        public static Task<HttpResponseMessage> PatchAsync(this HttpClient client, string requestUri, HttpContent content)
        {
            return client.PatchAsync(CreateUri(requestUri), content);
        }

        /// <summary>
        /// Send a PATCH request to the specified Uri as an asynchronous operation.
        /// </summary>
        /// 
        /// <returns>
        /// Returns <see cref="T:System.Threading.Tasks.Task`1"/>.The task object representing the asynchronous operation.
        /// </returns>
        /// <param name="client">The instantiated Http Client <see cref="HttpClient"/></param>
        /// <param name="requestUri">The Uri the request is sent to.</param>
        /// <param name="content">The HTTP request content sent to the server.</param>
        /// <exception cref="T:System.ArgumentNullException">The <paramref name="client"/> was null.</exception>
        /// <exception cref="T:System.ArgumentNullException">The <paramref name="requestUri"/> was null.</exception>
        public static Task<HttpResponseMessage> PatchAsync(this HttpClient client, Uri requestUri, HttpContent content)
        {
            return client.PatchAsync(requestUri, content, CancellationToken.None);
        }
        /// <summary>
        /// Send a PATCH request with a cancellation token as an asynchronous operation.
        /// </summary>
        /// 
        /// <returns>
        /// Returns <see cref="T:System.Threading.Tasks.Task`1"/>.The task object representing the asynchronous operation.
        /// </returns>
        /// <param name="client">The instantiated Http Client <see cref="HttpClient"/></param>
        /// <param name="requestUri">The Uri the request is sent to.</param>
        /// <param name="content">The HTTP request content sent to the server.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <exception cref="T:System.ArgumentNullException">The <paramref name="client"/> was null.</exception>
        /// <exception cref="T:System.ArgumentNullException">The <paramref name="requestUri"/> was null.</exception>
        public static Task<HttpResponseMessage> PatchAsync(this HttpClient client, string requestUri, HttpContent content, CancellationToken cancellationToken)
        {
            return client.PatchAsync(CreateUri(requestUri), content, cancellationToken);
        }

        /// <summary>
        /// Send a PATCH request with a cancellation token as an asynchronous operation.
        /// </summary>
        /// 
        /// <returns>
        /// Returns <see cref="T:System.Threading.Tasks.Task`1"/>.The task object representing the asynchronous operation.
        /// </returns>
        /// <param name="client">The instantiated Http Client <see cref="HttpClient"/></param>
        /// <param name="requestUri">The Uri the request is sent to.</param>
        /// <param name="content">The HTTP request content sent to the server.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <exception cref="T:System.ArgumentNullException">The <paramref name="client"/> was null.</exception>
        /// <exception cref="T:System.ArgumentNullException">The <paramref name="requestUri"/> was null.</exception>
        public static Task<HttpResponseMessage> PatchAsync(this HttpClient client, Uri requestUri, HttpContent content, CancellationToken cancellationToken)
        {
            return client.SendAsync(new HttpRequestMessage(new HttpMethod("PATCH"), requestUri)
            {
                Content = content
            }, cancellationToken);
        }

        private static Uri CreateUri(string uri)
        {
            return string.IsNullOrEmpty(uri) ? null : new Uri(uri, UriKind.RelativeOrAbsolute);
        }
    }

This way you're not awaiting and holding up execution in some static extension class, but you handle that as if you were really doing a PostAsync or a PutAsync call. You also have the same overloads at your disposal and you're letting the HttpClient handle everything it was designed to handle.