【问题标题】:Calling an async api from a xamarin application从 xamarin 应用程序调用异步 api
【发布时间】:2020-11-22 23:55:17
【问题描述】:

我正在开发一个 xamarin 移动应用程序,在对公开的 api 进行异步调用时,我没有收到任何错误,但是当我在任务上执行 .Result 时,调用永远不会继续并且永远卡住。

Click here to see stringResourceResponse details 来自同一解决方案中的单独项目(Windows 服务)的相同 .Result 调用有效。

如果 .NET 标准导致执行异步任务受到限制,任何建议都会有所帮助,谢谢

下面添加的代码:

//This is code from app.xaml.cs

var stringResourceApi = new StringResourceApiTask();
Task.Run(() =>
{
    a = controller.CallStringResourceApi(stringResourceApi);
}).Wait();
public class MobileController
    {
        public string CallStringResourceApi(StringResourceApiTask stringResourceApiTask)
        {
            return stringResourceApiTask.Start(StringResourceUrl);
        }
    }
public override string Start(string URL)
{
    var stringResourceResponse = SendRequest(url, "", HttpMethod.Get);
    var result = stringResourceResponse.Result;
    return result;
}
protected async Task < string > SendRequest(string url, string uri, HttpMethod method, int attempt = 1, int maxAttempts = 5)
{
    return await SendRequest(
        url, uri, Key, Secret, method, string.Empty, attempt, maxAttempts)
        .ConfigureAwait(false);
} 
protected async Task<string> SendRequest(string url, string uri, string key, string secret, HttpMethod method,
            string requestBody = "", int attempt = 1, int maxAttempts = 5)
        {
            if (attempt > maxAttempts)
            {
                return null;
            }

            var client = InitialiseHttpClient(key, secret);

            var request = new HttpRequestMessage
            {
                RequestUri = string.IsNullOrEmpty(url) ? new Uri(uri) : new Uri(url),
                Method = method,
            };

            if (!string.IsNullOrWhiteSpace(requestBody))
            {
                request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
            }

            SetOutputText($"Attempting to communicate with {uri}...{Environment.NewLine}");

            using (var response = await client.SendAsync(request).ConfigureAwait(false))
            {
                using (var content = response.Content)
                {
                    try
                    {
                        response.EnsureSuccessStatusCode();                       
                    }
                    catch (HttpRequestException ex)
                    {
                        
                        if (attempt > maxAttempts)
                        {
                            SetOutputText(errorMessage);
                        }

                        return await SendRequest(url, uri, key, secret, method, requestBody, attempt + 1).ConfigureAwait(false);
                    }

                    var responseBody = await content.ReadAsStringAsync().ConfigureAwait(false);

                    var isSuccessResponseButEmptyBody = response.IsSuccessStatusCode &&
                                                        (string.IsNullOrEmpty(responseBody) ||
                                                         string.IsNullOrWhiteSpace(responseBody));
                    if (!isSuccessResponseButEmptyBody)
                    {
                        return responseBody;
                    }

                    
                    if (attempt > maxAttempts)
                    {
                        SetOutputText(errorMessage);
                    }

                    return await SendRequest(url, uri, key, secret, method, requestBody, attempt + 1).ConfigureAwait(false);
                }
            }
        }

【问题讨论】:

  • 请给一些代码。
  • 在 Url 中调用的 Web api 具有 hmac(基于哈希的身份验证),不确定这是否没有生成,即 xamarin 端的密钥等?我的意思是 xamarin 在支持基于 hmac 的经过身份验证的 api 等方面是否有限制?
  • 请不要将一堆未格式化的代码塞进评论中。我建议你删除这篇文章,然后用相关代码创建一个新的,格式正确,包含以及其他有用的信息
  • 请参考更新后的代码,谢谢
  • 您是否验证过您的网址可以从您的设备或模拟器访问?而且完全不清楚您发布的代码如何组合在一起 - 关键方法似乎是CallStringResourceApi,但没有显示该方法。

标签: xamarin web xamarin.forms xamarin.android webapi


【解决方案1】:

当我在任务上执行 .Result 时,调用永远不会继续,它会永远卡住。

是的。这是common deadlock situation。当 UI 线程上运行的代码阻塞异步代码时,通常会发生死锁。

来自同一解决方案中的单独项目(Windows 服务)的相同 .Result 调用有效。

这是因为 Win32 服务代码不在 UI 线程上运行。

正确的解决办法是去掉阻塞代码;请改用await。这反过来会导致调用方法变为async(例如,StringResourceApiTask.Start),它们也应该是awaited 等。asyncawait 的使用应该通过你的代码“增长” ;这是自然的。

或者,您可以阻塞在线程池线程中,例如Task.Run(() =&gt; a = controller.CallStringResourceApi(stringResourceApi)).GetAwaiter().GetResult();。这有点小技巧(消耗不必要的线程),但它是消除死锁的快速方法。请注意,此 hack 适用于 ASP.NET 应用程序;这是可以接受的,因为这是一个 UI 应用程序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-02
    • 2012-04-15
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 2020-05-05
    • 1970-01-01
    相关资源
    最近更新 更多