Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#Xamarin未收到来自HttpClient的响应_C#_Xamarin_Task Parallel Library_Dotnet Httpclient - Fatal编程技术网

C#Xamarin未收到来自HttpClient的响应

C#Xamarin未收到来自HttpClient的响应,c#,xamarin,task-parallel-library,dotnet-httpclient,C#,Xamarin,Task Parallel Library,Dotnet Httpclient,我在C#Xamarin中使用以下方法进行身份验证: private async Task<HttpResponseMessage> _SendAsync(HttpMethod method, string url, object obj) { HttpRequestMessage request = new HttpRequestMessage(method, url); request.Content = new StringContent(

我在C#Xamarin中使用以下方法进行身份验证:

private async Task<HttpResponseMessage> _SendAsync(HttpMethod method, string url, object obj)
    {
        HttpRequestMessage request = new HttpRequestMessage(method, url);
        request.Content = new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");
        if (!string.IsNullOrEmpty(this._AuthToken))
        {
            request.Headers.Add("Authorization", this._AuthToken);
        }
        return await this._Client.SendAsync(request);
    }
private async Task\u sendaync(HttpMethod方法、字符串url、对象obj)
{
HttpRequestMessage请求=新的HttpRequestMessage(方法,url);
request.Content=newstringcontent(JsonConvert.SerializeObject(obj),Encoding.UTF8,“application/json”);
如果(!string.IsNullOrEmpty(this.\u AuthToken))
{
添加(“授权”,this.\u AuthToken);
}
返回等待此操作。_Client.sendaync(请求);
}
服务器收到请求,身份验证成功(显示在服务器日志中)。基于wireshark,许多响应从服务器返回,但函数不返回。应用程序冻结

有什么想法吗? 此方法在普通控制台客户端上运行,没有任何问题

没有错误消息,只是一个冻结的客户端


谢谢你的回答

您在这里遇到的是死锁的经典案例。在评论中,我建议简单地删除
async
wait
关键字,并简单地返回
Task
HttpClient.sendaync方法返回的结果。为什么这会改变什么?让我解释一下

就在您等待异步方法之前,当前的同步上下文被捕获。在您的情况下,它可能是UI线程

然后,当实际的
SendAsync
方法完成其工作时,它将尝试返回到该
SynchronizationContext
。这通常是好的。但是,这实际上取决于您实际如何调用封装方法

如果您从UI线程执行类似以下操作:
\u SendAsync(..).Result
,这很可能会导致死锁。由于
.Result
是一个阻塞调用,UI线程将等待
.Result
完成。由于UI线程正在等待,因此在等待的
SendAsync
方法完成后返回UI线程
SynchronizationContext
将不起作用,因为UI线程被阻塞

那么,在这种情况下,简单地返回任务有什么作用呢?由于您没有等待该任务,并且该方法没有标记为async,因此上下文切换的责任将被上移到调用
\u SendAsync
的堆栈中。在这里调用
.Result
不会进行上下文切换,只会进行一次阻塞调用,从而失去执行async/await的所有好处

或者,您也可以将
.ConfigureAwait(false)
添加到等待的
this.\u Client.SendAsync()
调用中。这样做的目的是不返回到capture
SynchronizationContext
,而是返回到执行它的线程池线程

在任何一种情况下,使用
.Result
.GetAwaiter().GetResult()
都要非常小心,在大多数情况下都应该避免使用

任务通常应该等待。或者,如果您并不真正关心结果,您可以使用
Task.Run()
启动并忘记

大多数不需要返回到捕获上下文的服务调用和异步调用大多可以通过
ConfigureAwait(false)
进行后期修复。不使用它的主要原因是,如果您想在之后更新UI

你可以阅读更多关于

我强烈建议您阅读有关的优秀文档

TL;博士:

或者:

private async Task<HttpResponseMessage> _SendAsync(HttpMethod method, string url, object obj)
{
    HttpRequestMessage request = new HttpRequestMessage(method, url);
    request.Content = new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");
    if (!string.IsNullOrEmpty(this._AuthToken))
    {
        request.Headers.Add("Authorization", this._AuthToken);
    }
    return await this._Client.SendAsync(request).ConfigureAwait(false);
}
private async Task\u sendaync(HttpMethod方法、字符串url、对象obj)
{
HttpRequestMessage请求=新的HttpRequestMessage(方法,url);
request.Content=newstringcontent(JsonConvert.SerializeObject(obj),Encoding.UTF8,“application/json”);
如果(!string.IsNullOrEmpty(this.\u AuthToken))
{
添加(“授权”,this.\u AuthToken);
}
返回wait this.\u Client.SendAsync(请求).configurewait(false);
}
或者:

private Task<HttpResponseMessage> _SendAsync(HttpMethod method, string url, object obj)
{
    HttpRequestMessage request = new HttpRequestMessage(method, url);
    request.Content = new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");
    if (!string.IsNullOrEmpty(this._AuthToken))
    {
        request.Headers.Add("Authorization", this._AuthToken);
    }
    return this._Client.SendAsync(request);
}
private Task\u sendsync(HttpMethod方法、字符串url、对象obj)
{
HttpRequestMessage请求=新的HttpRequestMessage(方法,url);
request.Content=newstringcontent(JsonConvert.SerializeObject(obj),Encoding.UTF8,“application/json”);
如果(!string.IsNullOrEmpty(this.\u AuthToken))
{
添加(“授权”,this.\u AuthToken);
}
返回此。\u Client.SendAsync(请求);
}
来解决这个问题


并避免对任务调用
.Result
。始终等待它们。

您在这里遇到的是死锁的经典案例。在评论中,我建议简单地删除
async
wait
关键字,并简单地返回
Task
HttpClient.sendaync方法返回的结果。为什么这会改变什么?让我解释一下

就在您等待异步方法之前,当前的同步上下文被捕获。在您的情况下,它可能是UI线程

然后,当实际的
SendAsync
方法完成其工作时,它将尝试返回到该
SynchronizationContext
。这通常是好的。但是,这实际上取决于您实际如何调用封装方法

如果您从UI线程执行类似以下操作:
\u SendAsync(..).Result
,这很可能会导致死锁。由于
.Result
是一个阻塞调用,UI线程将等待
.Result
完成。由于UI线程正在等待,因此在等待的
SendAsync
方法完成后返回UI线程
SynchronizationContext
将不起作用,因为UI线程被阻塞

那么,在这种情况下,简单地返回任务有什么作用呢?由于您没有等待该任务,并且该方法没有标记为async,因此上下文切换的责任将被上移到调用
\u SendAsync
的堆栈中。在此处调用
.Result
不会进行上下文切换,但会执行JU