C# HttpClient Wait在使用异步void方法的PostAsync上挂起

C# HttpClient Wait在使用异步void方法的PostAsync上挂起,c#,oauth,windows-phone-8,async-await,dotnet-httpclient,C#,Oauth,Windows Phone 8,Async Await,Dotnet Httpclient,我仍在试图理解async,我想知道为什么下面的代码会导致死锁。我的用例是这样的:我有一个服务接口,它试图抽象出服务是如何实现的。其中一个服务是基于OAuth的web服务。服务接口有一个方法Connect(),任何使用接口的人在使用它之前都必须这样做 在客户端,我创建了具体的服务对象,并在视图构造函数中调用Connect()(这是一个原型,所以我只是想得到一个概念证明)。在基于OAuth的服务中,connect调用需要检索访问令牌,因此它(尝试)异步执行此操作。但是,这个Connect()调用永远

我仍在试图理解async,我想知道为什么下面的代码会导致死锁。我的用例是这样的:我有一个服务接口,它试图抽象出服务是如何实现的。其中一个服务是基于OAuth的web服务。服务接口有一个方法
Connect()
,任何使用接口的人在使用它之前都必须这样做

在客户端,我创建了具体的服务对象,并在视图构造函数中调用
Connect()
(这是一个原型,所以我只是想得到一个概念证明)。在基于OAuth的服务中,connect调用需要检索访问令牌,因此它(尝试)异步执行此操作。但是,这个
Connect()
调用永远不会返回,并且应用程序处于死锁状态(但UI处于活动状态)。我猜我搞砸了,试图在某个地方同步使用我的客户机,但我不确定在哪里

控制

public class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        _webService = new OAuthBasedWebService();
        _webService.ShowAuthorizationPage += _webService_ShowAuthorizationPage; // this is defined on the concrete object -- i know, bad design
        _webService.Connect();
    }
}
基于OAuth的Web服务

public class OAuthBasedWebService()
{
    private OAuthWrapper _wrapper;

    public async void Connect()
    {
        var uri = await _wrapper.GetAuthorizationUri();
        OnShowAuthorizationPage(uri);
    }
}

internal class OAuthWrapper
{
    public async Task<Uri> GetAuthorizationUri()
    {
        var uri = await _consumer.GetAuthorizationUriAsync();
        return uri;
    }
}

internal class OAuthConsumer
{
    public async Task<Uri> GetAuthorizationUriAsync()
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = "webservicebaseaddress";
            var content = new FormUrlEncodedContent(new []
            {
                CreateParameter("oauth_consumer_key", "consumerkey"),
                CreateParameter("oauth_consumer_secret", "consumersecret")
                // etc., etc.
            });

            var response = await client.PostAsync("/method_path", content).ConfigureAwait(false);
            var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

            // parse authorization uri from responseContent
            return authorizationUri;
        }
    }
}
公共类OAuthBasedWebService()
{
专用振打器包装;
公共异步void Connect()
{
var uri=await_wrapper.GetAuthorizationUri();
OnShowAuthorizationPage(uri);
}
}
内部类说唱机
{
公共异步任务GetAuthorizationUri()
{
var uri=wait_consumer.GetAuthorizationUriAsync();
返回uri;
}
}
内部类OAuthConsumer
{
公共异步任务GetAuthorizationUriAsync()
{
使用(var client=new HttpClient())
{
client.BaseAddress=“webservicebaseaddress”;
var content=newformurlencodedcontent(new[]
{
CreateParameter(“oauth_consumer_key”,“consumerkey”),
CreateParameter(“oauth_consumer_secret”、“consumersecret”)
//等等等等。
});
var response=await client.PostAsync(“/method\u path”,content.).ConfigureAwait(false);
var responseContent=await response.Content.ReadAsStringAsync().ConfigureAwait(false);
//从responseContent解析授权uri
返回授权URI;
}
}
}

我知道设计需要一点工作,但我正试图弄明白为什么这是死锁。我猜这是因为
\u webService.Connect()
没有被异步调用,但我也不能等待它,因为它不返回任何东西,程序的其余部分也不依赖它。

如果问题只是因为无法使构造函数“异步”,我不确定为什么要在这里使用事件然后将conect调用移动到另一个方法:

public class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        Init();
    }

    public async void Init(){

        _webService = new OAuthBasedWebService();

        Uri uri=await _webService.Connect();
         _webService_ShowAuthorizationPage(uri);
    }
}


public class OAuthBasedWebService()
{
    private OAuthWrapper _wrapper;

    public async Task<Uri> Connect()
    {
        return await _wrapper.GetAuthorizationUri();

    }
}
公共类主窗口
{
公共主窗口()
{
初始化组件();
Init();
}
公共异步void Init(){
_webService=新的OAuthBasedWebService();
Uri=wait_webService.Connect();
_webService\u ShowAuthorizationPage(uri);
}
}
公共类OAuthBasedWebService()
{
专用振打器包装;
公共异步任务连接()
{
返回wait_wrapper.GetAuthorizationUri();
}
}

我想你会发现实际上
Connect
会立即返回,因为它是一种异步方法。不幸的是,这是一个返回
void
的异步方法,这通常是个坏主意。您是否在
GetAuthorizationUriAsync
中设置断点或诊断,以了解它实际达到的程度?如果UI仍然响应,我不确定您所说的“死锁”是什么意思。
GetAuthorizationUriAsync
是否返回?(顺便说一句,我有一些方法可以避免构造函数中的
async void
GetAuthorizationUriAsync()
到达第一个
wait
。它永远不会到达第二个。这很奇怪,但是如果我不设置
BaseAddress
,而是将请求url设置为“webservicebaseaddress/method\u path”,调用就会通过。事件存在是因为Connect不会始终请求授权页。例如,如果用户已经授权,则不会显示授权页面。