使用Windows.Web.Http.HttpClient类进行异步PATCH请求

84

我需要使用 Windows.Web.Http.HttpClient 类进行 PATCH 请求,但是没有官方的文档说明如何实现。我该怎么做呢?

5个回答

96

我在这里找到了如何使用以前的System.Net.Http.HttpClient类来进行“自定义”PATCH请求的方法,然后进行了调整,直到我将其应用于Windows.Web.Http.HttpClient类并使其起作用:

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;
}

使用以下代码替换:var response = default(HttpResponseMessage); - Wilmer
你可能想在 SendAsync 后面使用 .ConfigureAwait(continueOnCapturedContext: false);,像这样:response = await client.SendAsync(request).ConfigureAwait(continueOnCapturedContext: false);,以避免悬挂请求的潜在问题。 - Arsen Khachaturyan

62

更新:请查看下面 SSX-SL33PY的回答,那里提供了一种更好的解决方案,实现相同的功能。

你可以将此方法编写为扩展方法,这样你就可以直接在 HttpClient 对象上调用它:

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;
   }
}

使用方法:

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

你如何传递内容? - Luis Valencia
5
你看到第二个参数了吗?尝试像这样做:对于字符串内容,可以使用类似以下的代码:HttpContent httpContent = new StringContent("你的JSON字符串", Encoding.UTF8, "application/json"); - Alexander Pacha
请纠正我,但PATCH方法意味着您仅修改JSON中的特定数据。如果要修改产品名称,该怎么办?如果“Your JSON-String”指整个JSON,则我感到困惑。我尝试添加单个属性,例如HttpContent content = new StringContent("{\"name\":\"John Doe\"", Encoding.UTF8, "application/json");,但内容未添加到请求中。 - Caloyski
你可能需要在SendAsync之后使用.ConfigureAwait(continueOnCapturedContext:false);,像这样:response = await client.SendAsync(request).ConfigureAwait(continueOnCapturedContext: false);,以避免出现挂起请求的潜在问题。 - Arsen Khachaturyan

43

我希望在@alexander-pacha的回答上进行扩展,并建议在公共库中添加以下扩展类。无论这是项目/客户/框架的公共库,您需要自己决定。

    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);
        }
    }

这样你就不需要在某些静态扩展类中等待和阻塞执行,而是像真正进行PostAsyncPutAsync调用一样处理它。你还可以使用相同的重载,并让HttpClient处理它设计的所有内容。


3
看起来很不错。你应该考虑在.NET Framework的官方存储库中创建一个Pull-Request,因为他们欢迎贡献:https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/HttpClient.cs - Alexander Pacha
编辑:有人比我更快,它已经被其他人添加到了您链接的存储库中。 - Jif

7
为了使其工作,您需要像这样传递内容:
HttpContent httpContent = new StringContent("Your JSON-String", Encoding.UTF8, "application/json-patch+json");

0

步骤1:创建一个静态类(我已经创建为扩展类)

public static class Extention
{
    public static Task<HttpResponseMessage> PatchAsJsonAsync<T>(this HttpClient 
    client, string requestUri, T value)
    {
        var content = new ObjectContent<T>(value, new JsonMediaTypeFormatter());
        var request = new HttpRequestMessage(new HttpMethod("PATCH"), requestUri) 
        { Content = content };

        return client.SendAsync(request);
    }
}

步骤2:在您的API请求中调用此方法

private static HttpClient client = new HttpClient();
var response = Extention.PatchAsJsonAsync<UserUpdateAPIModel>(client, "https://api.go1.com/v2/users/5886043", data);

问题已解决,如果这是常见的URL,则可以通过实践来解决。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接