【问题标题】:HttpClient PostAsync() not workingHttpClient PostAsync()不起作用
【发布时间】:2016-12-22 12:10:54
【问题描述】:

在我的 Xamarin Forms 应用中

我正在尝试将 Json 字符串发布到我的 web 服务,它是 RestFul API 当我使用以下代码时:

public static async Task<bool> SaveRolAsync(Methods Method, Role Rol)
    {
        try
        {
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            var uri = ("http://myservice.com/roles/");
            HttpResponseMessage response = null;

            try
            {
                var jSettings = new JsonSerializerSettings();
                jSettings.NullValueHandling = NullValueHandling.Ignore;
                jSettings.MissingMemberHandling = MissingMemberHandling.Ignore;

                var JsonData = JsonConvert.SerializeObject(Rol);
                var RoleContent = new StringContent(JsonData, Encoding.UTF8, "application/json");

                if (Method == Methods.PUT || Method == Methods.PATCH)
                {
                    response = await client.PutAsync(uri, RoleContent);
                }

                if (Method == Methods.POST)
                {
                    response = await client.PostAsync(uri, RoleContent);
                }

                if (Method == Methods.DELETE)
                {
                    throw new NotImplementedException();
                }

                return response.IsSuccessStatusCode;

            }
            catch (JsonException jse)
            {
                return false;
            }
        }
        catch (Exception ex)
        {
            // Exceptions Throws here
            // @T This line i got The request requires buffering data to succeed
            return false;
        }
    }

异常抛出:

请求需要缓冲数据才能成功

堆栈跟踪:

{System.Net.WebException: 请求需要缓冲数据以 成功。在 System.Net.HttpWebRequest.EndGetResponse (System.IAsyncResult asyncResult) [0x00064] 在 :0 在 System.Threading.Tasks.TaskFactory1[TResult].FromAsyncCoreLogic (System.IAsyncResult iar, System.Func2[T,TResult] endFunction, System.Action1[T] endAction, System.Threading.Tasks.Task1[TResult] 承诺,System.Boolean requiresSynchronization) [0x00014] in :0 --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] 在 :0 处 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task 任务) [0x0004e] in :0 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task 任务) [0x0002e] in :0 在 System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task 任务) [0x0000b] in :0 在 System.Runtime.CompilerServices.ConfiguredTaskAwaitable1+ConfiguredTaskAwaiter[TResult].GetResult () [0x00000] in <a66f207c1e5949e9a252c01e27bbd34e>:0 at System.Net.Http.HttpClientHandler+<SendAsync>c__async0.MoveNext () [0x0041e] in <566d6cf6576345098cb5e08ad43d5e78>:0 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <a66f207c1e5949e9a252c01e27bbd34e>:0 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0004e] in <a66f207c1e5949e9a252c01e27bbd34e>:0 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in <a66f207c1e5949e9a252c01e27bbd34e>:0 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in <a66f207c1e5949e9a252c01e27bbd34e>:0 at System.Runtime.CompilerServices.ConfiguredTaskAwaitable1+ConfiguredTaskAwaiter[TResult].GetResult () [0x00000] 在 :0 处 System.Net.Http.HttpClient+c__async0.MoveNext() [0x000f3] 在 :0 --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] 在 :0 处 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task 任务) [0x0004e] in :0 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task 任务) [0x0002e] in :0 在 System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task 任务) [0x0000b] in :0 在 System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] 在 :0 处 MyAPP.Webservice+d__4.MoveNext() [0x000d0] in C:\MyProject\Classes\Webservice.cs:140 }

**也尝试过:SendAsync() Ty M. Wiśnicki **

public static async Task<bool> SaveRolAsync(MediwareLib.Methods Method, Role Rol)
    {
        try
        {
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            var uri = (BaseRequestUrl + "roles/");
            HttpResponseMessage response = null;
            var request = new HttpRequestMessage();

            try
            {
                var jSettings = new JsonSerializerSettings();
                jSettings.NullValueHandling = NullValueHandling.Ignore;
                jSettings.MissingMemberHandling = MissingMemberHandling.Ignore;

                var JsonData = JsonConvert.SerializeObject(Rol);

                var RoleContent = new StringContent(JsonData, Encoding.UTF8, "application/json");

                if (Method == MediwareLib.Methods.PUT || Method == MediwareLib.Methods.PATCH)
                {
                    request = new HttpRequestMessage(HttpMethod.Put, uri);
                    request.Content = RoleContent;

                    response = await client.SendAsync(request,
                    HttpCompletionOption.ResponseHeadersRead);
                }

                if (Method == MediwareLib.Methods.POST)
                {
                    request = new HttpRequestMessage(HttpMethod.Post, uri);
                    request.Content = RoleContent;

                    response = await client.SendAsync(request,
                    HttpCompletionOption.ResponseHeadersRead);
                }

                if (Method == MediwareLib.Methods.DELETE)
                {
                    throw new NotImplementedException();
                    // response = await client.DeleteAsync(uri + Rol.Id);
                }

                return response.IsSuccessStatusCode;

            }
            catch (JsonException jse)
            {
                Globals.Log("SaveRolAsync: " + jse.ToString());
                return false;
            }
        }
        catch (Exception ex)
        {
            Globals.Log("SaveRolAsync: " + ex.ToString());
            return false;
        }

    }

【问题讨论】:

  • 那么您的研究表明了什么?你读过The request requires buffering data to succeed HttpClientHead request with HttpClient 吗?您是否注意到即使if (Method == Methods.POST) 也在发送 PUT?您的服务是否通过重定向响应?
  • Ofc 我确实阅读了其他 stackoverflow 帖子,但我想发送一个 json 字符串而不是谷歌请求。
  • 一个HTTP请求就是一个HTTP请求,无论是包含搜索结果还是JSON数据。
  • 很高兴知道在哪一行抛出异常:)
  • 请附上完整的堆栈跟踪。

标签: c# xamarin xamarin.forms httpclient


【解决方案1】:

由于您使用的是.Result.Waitawait,这最终会在您的代码中导致死锁

您可以在async 方法中使用ConfigureAwait(false)防止死锁

像这样:

response = await client.PostAsync(uri, RoleContent).ConfigureAwait(false);

您可以尽可能使用ConfigureAwait(false) 来表示不要阻塞异步代码。

【讨论】:

    【解决方案2】:

    您可以将SendAsync()HttpCompletionOption.ResponseHeadersRead 一起使用,而不是PostAsync(),问题在于读取响应,它在未准备好时正在读取。

    var request = new HttpMessageRequest(yourUrl);
    request.Content = yourContent;
    var response = await client.SendAsync(request, 
    HttpCompletionOption.ResponseHeadersRead);
    

    使用HttpCompletionOption.ResponseHeadersRead

    一旦响应可用并读取标头,该操作就应该完成。内容尚未阅读。

    编辑 您可以使用HttpWebRequest 代替HttpClient

       public async Task<string> PostTest(object sampleData, string uri)
        {
            var request = (HttpWebRequest) WebRequest.Create(new Uri(uri));
            request.ContentType = "application/json";
            request.Method = "POST";
            request.Timeout = 4000; //ms
            var itemToSend = JsonConvert.SerializeObject(sampleData);
            using (var streamWriter = new StreamWriter(await request.GetRequestStreamAsync()))
            {
                streamWriter.Write(itemToSend);
                streamWriter.Flush();
                streamWriter.Dispose();
            }
    
            // Send the request to the server and wait for the response:  
            using (var response = await request.GetResponseAsync())
            {
                // Get a stream representation of the HTTP web response:  
                using (var stream = response.GetResponseStream())
                {
                    var reader = new StreamReader(stream);
                    var message = reader.ReadToEnd();
                    return message;
                }
            }
        }
    

    【讨论】:

    • 同样的错误:(System.Net.WebException:请求需要缓冲数据才能成功。
    • @StefanvandeLaarschot 你使用new HttpRequestMessage(HttpMethod.Post, uri);,但我没有写HttpMethod,只使用uri。
    • 它不能期望 HttpMethod、uri 或 String 作为 Uri
    • 相同:System.Net.WebException:请求需要缓冲数据才能成功。
    • 我认为问题出在 try catch 块上。确保你没有阻塞异步代码。还可以尝试使用client.PostAsync(uri, RoleContent).Result; 而不使用await 运行帖子。在这里你可以找到文章为什么不能阻止异步blog.stephencleary.com/2012/07/dont-block-on-async-code.html
    猜你喜欢
    • 2020-11-15
    • 2018-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多