【问题标题】:Calling a WebAPI asynchronously from a Xamarin.Android event handler deadlocks从 Xamarin.Android 事件处理程序死锁异步调用 WebAPI
【发布时间】:2017-08-11 12:51:09
【问题描述】:

我已经为这个问题苦苦挣扎了一段时间,现在是时候在这里提出我的问题了。所以,情况是这样的:

我有一个 WebAPI、一个 Xamarin.Android 应用程序和一个 IdentityServer4 实现。 Xamarin.Android 应用需要调用 WebAPI 以获取基于搜索的用户列表。这是通过 TextChanged 事件处理程序中的异步调用完成的。发生的情况是,当等待对 WebAPI 的调用时,它永远不会返回,并且在某些时候任务会被取消。我已经尝试使用 ConfigureAwait(false),我已经使事件处理程序方法异步无效,我已经阅读了关于类似问题的其他几个问题 - 没有一个选项对我有用。但这里有一些代码让你了解我在做什么:

TextChanged 处理程序:

protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        SetContentView(Resource.Layout.SearchPeopleLayout);

        this.searchUsersElement = FindViewById<EditText>(Resource.Id.searchUsersField);
        this.usersListElement = FindViewById<ListView>(Resource.Id.usersSearchResult);

        using (var scope = App.Container.BeginLifetimeScope())
        {
            this.apiClient = App.Container.Resolve<IUsersApiClient>();
        }

        this.searchUsersElement.TextChanged += SearchUsersElement_TextChanged;
    }

    public async void SearchUsersElement_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
    {
        var length = e.Start + e.AfterCount;
        if (length <= MinUsernameLength)
        {
            return;
        }

        var searchName = string.Join(string.Empty, e.Text);

        var users = await this.apiClient.GetUsers(searchName, Persistor.ApiClient);

        RunOnUiThread(() =>
        {
            var usersAdapter = new UsersAdapter(this, users.ToList());

            this.usersListElement.Adapter = usersAdapter;
        });
    }

这是 UsersApiClient 的实现:

public async Task<IEnumerable<UserModel>> GetUsers(string username, HttpClient client)
    {
        try
        {
            var content = await client.GetStringAsync($"{apiUrl}/users?name={username}").ConfigureAwait(false);

            var result = JsonConvert.DeserializeObject<IEnumerable<UserModel>>(content);

            return result;
        }
        catch (Exception ex)
        {
            throw ex;
        }

    }

死锁发生在 GetStringAsync() 调用上。我已经测试了它通过 Postman 拨打的电话,它给了我正确的回应。只有我还没有尝试过的事情是实现 ITextWatcher 接口而不是添加事件处理程序,并更改代码所以我不使用单独的方法而是使用匿名委托 - 我在某些地方读到了可能证明是一个问题。

我真的希望你们中的一些人能帮助我解决这个问题,让我了解如何正确地执行此类异步调用。

最好的问候。

【问题讨论】:

  • GetStringAsync 中删除.ConfigureAwait(false); 会发生什么?
  • 我把它放在那里是为了解决这个问题——它不会改变任何东西。无论 ConfigureAwait(false) 是否存在,问题都存在。看了这篇文章我加了:link
  • 这意味着调用堆栈中的某些位置混合了异步和阻塞调用。到目前为止,您显示的代码似乎没有。
  • 这应该就是全部了——我已经用 TextChanged 事件处理程序设置和包含异步调用的 UserApiClient 为你提供了 onCreate() 覆盖——这就是全部。我猜我在调用 API 的整个异步 void 事件处理程序中遗漏了一些东西。
  • 创建时是否立即调用文本更改?可能是每次您键入它都会调用处理程序,并且与受限制的调用相比,一次调用过多

标签: c# asp.net-web-api xamarin.android event-handling async-await


【解决方案1】:

好的,所以我不确定是什么解决了这个问题,但这就是我所做的 - 有另一个 StackOverflow 问题有一个类似的问题,在重新部署之前手动从模拟器中卸载应用程序解决了这个问题。我还删除了 ConfigureAwait(false) 调用。突然间,一切正常。不知道它是怎么发生的,但在这里 - 手动卸载应用程序并在没有 ConfigureAwait(false) 的情况下调用 API。

【讨论】:

    猜你喜欢
    • 2016-12-22
    • 1970-01-01
    • 1970-01-01
    • 2015-12-19
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多