异步REST API调用永远不会返回,但其他异步操作按预期工作

时间:2018-02-01 20:32:07

标签: c# asynchronous xamarin.forms async-await dotnet-httpclient

我的搜索对我的确切问题并不是很有成效;我似乎无法让异步REST调用在我的Xamarin Forms应用程序中正常工作。举个例子:

public async Task<GPIOFunctions> GetGPIOFunction(int gpioNumber)
{
    var response = await _client.GetAsync(GetFullUrl($"/GPIO/{gpioNumber}/function"));
    response.EnsureSuccessStatusCode();
    return GetFunctionFromString(await response.Content.ReadAsStringAsync());
}

我的单元测试调用此函数,并始终正常工作。然而,当我的应用程序调用它时,它永远不会从第一个等待返回。如果我向.GetAwaiter().GetResult()添加GetAsync,那么它会返回,甚至正确执行最后一个ReadAsStringAsync(),返回给调用者,一切都会继续。

现在,如果我在末尾添加GetAsync(),我可以让我的.ConfigureAwait(false)正常工作,但是第二次等待永远不会完成,并且添加.ConfigureAwait(false)并不能解决问题

我已经启用了所有异常,已经看过调试输出,但都没有提供任何其他信息。此外,我已经调试了Fiddler运行的应用程序,从未见过请求,所以我不认为这是我的模拟器/设备无法访问API的问题(是的,INTERNET权限在我的清单中启用。)

这是Xamarin Forms的已知限制吗?

修改

下面的函数调用层次结构,从我的视图模型的构造函数开始:

public MainViewModel()
{
    _client = new HttpEndpoint(Url, User, Pass);
    TriggerDoorCommand = new Command(async () => await ExecuteTriggerDoorCommand());
    _currentDoorFunc = GetCurrentDoorFunction().Result;
}

private async Task<GPIOFunctions> GetCurrentDoorFunction()
{
    return await _client.GetGPIOFunction(DOOR_TOGGLE_PIN);
}

其他信息,类HttpEndpoint位于单独的类库中,并包装HttpClient和所有API调用。共享项目和此类库都是.NET Standard 2.0。

1 个答案:

答案 0 :(得分:2)

请勿将async/await.Result之类的阻止调用混在一起,这会导致死锁。

您可以创建事件和事件处理程序作为解决方法

public MainViewModel() {
    _client = new HttpEndpoint(Url, User, Pass);
    TriggerDoorCommand = new Command(async () => await ExecuteTriggerDoorCommand());
    //Subscribe to event
    GetData += GetDataHandler;
    //Raise event
    GetData(this, EventArgs.Empty);
}

private event EventHandler GetData = delegate { }; 

private async void GetDataHandler(object sender, EventArgs args) {
    _currentDoorFunc = await GetCurrentDoorFunction();
}

private async Task<GPIOFunctions> GetCurrentDoorFunction() {
    return await _client.GetGPIOFunction(DOOR_TOGGLE_PIN);
}

参考Async/Await - Best Practices in Asynchronous Programming