【问题标题】:HttpClient await hangs on PostAsync with async void methodHttpClient await 使用 async void 方法在 PostAsync 上挂起
【发布时间】:2013-10-02 17:34:38
【问题描述】:

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

在我的客户端,我创建了我的具​​体服务对象并在我的视图构造函数中调用Connect()(这是一个原型,所以我只是想获得一个概念证明)。在基于 OAuth 的服务中,连接调用需要检索访问令牌,因此它(尝试)异步执行此操作。但是,此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 的网络服务

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

我知道设计需要做一些工作,但我想弄清楚为什么会出现死锁。我猜这是因为 _webService.Connect() 没有被异步调用,但我也不能 await 那因为它不返回任何东西,程序的其余部分也不依赖它。

【问题讨论】:

  • 我想你会发现实际上Connect 返回了很多立即 - 因为它是一个异步方法。不幸的是,这是一个返回void 的异步方法,这通常是个坏主意。您是否在GetAuthorizationUriAsync 中设置了断点或诊断信息,以了解它的实际进展情况?
  • 如果 UI 仍然响应,我不确定您所说的“死锁”是什么意思。 GetAuthorizationUriAsync 是否返回? (顺便说一句,我有一些tips on my blog 用于避免在构造函数中使用async void)。
  • GetAuthorizationUriAsync() 获取第一个 await。它永远不会到达第二个。
  • 所以这很奇怪,但是如果我不设置 BaseAddress 而是将请求 url 设置为“webservicebaseaddress/method_path”,调用就会通过。

标签: c# oauth windows-phone-8 async-await dotnet-httpclient


【解决方案1】:

我不确定您为什么在这里使用事件,如果问题只是因为您无法使构造函数“异步”,那么只需将 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();

    }
}

【讨论】:

  • 该事件存在是因为 Connect 不会总是请求授权页面。例如,如果用户已经获得授权,则不会显示授权页面。
猜你喜欢
  • 1970-01-01
  • 2019-07-22
  • 1970-01-01
  • 2023-03-13
  • 2022-12-17
  • 2013-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多