HttpClient 不会在 Windows Phone 中返回

本文关键字:Phone 返回 Windows HttpClient | 更新日期: 2023-09-27 18:32:59

很简单,这是我的代码:

/// <summary>
/// Fetches the JSON string from the URL.
/// </summary>
/// <param name="url">URL to download the JSON from.</param>
/// <returns>JSON formatted string</returns>
private static string GetJsonResponse(string url)
{
    var result = DownloadString(url).Result;
    System.Diagnostics.Debug.WriteLine("Downloaded from {0} with result = {1}", url, result);
    return result;
}
private static async Task<string> DownloadString(string feedUrl)
{
    var result = "";
    System.Diagnostics.Debug.WriteLine("Downloading from {0}", feedUrl);
    using (var client = new HttpClient())
    {
        result = await client.GetStringAsync(new Uri(feedUrl, UriKind.Absolute));
        result.Trim();
        System.Diagnostics.Debug.WriteLine("Finished download from {0}", feedUrl);
    }
    return result;
}

它打印第一个字符串,但无法到达第二个字符串,这意味着client.GetStringAsync不会返回。

网址没问题,加载正常。

我的问题是什么?

编辑2:(现在删除为无用(

编辑3:

正在添加我正在使用的方法,让您知道我的数据流是什么。

Page.xaml

<phone:LongListSelector Grid.Row="1" x:Name="UpcomingResultsList" ItemsSource="{Binding UpcomingMovies}" ItemTemplate="{StaticResource MovieListDataTemplate}" Margin="0, 10, 0, 0" />

UpcomingMovies绑定到此属性

public List<MovieViewModel> UpcomingMovies
    {
        get
        {
            System.Diagnostics.Debug.WriteLine("UpcomingMovies - Begin");             
            var apiMovies = _serviceRT.FindUpcomingMoviesList().Result; // We get the movies in RT API's format
            var movies = apiMovies.Select(result => new MovieViewModel(result)).ToList();
            System.Diagnostics.Debug.WriteLine("UpcomingMovies - End");
            return movies;
        }
}

_serviceRT.FindUpcomingMoviesList()方法:

/// <summary>
/// Gets a list of upcoming movies.
/// </summary>
/// <returns>MovieSearchResults</returns>
public async Task<MovieSearchResults> FindUpcomingMoviesList()
{
    var url = string.Format(LIST_UPCOMING, ApiKey);
    var jsonResponse = await GetJsonResponse(url);
    var results = Parser.ParseMovieSearchResults(jsonResponse);
    return results;
}

最后,GetJsonResponse()在问题的开头。

现在,有了完整的数据流,如何绑定此属性并仍然完成下载?

HttpClient 不会在 Windows Phone 中返回

我预测在您的调用堆栈中,您正在从async方法返回的Task上调用WaitResult。正如我在博客上描述的那样,这很容易导致死锁。

发生这种情况是因为默认情况下await将捕获用于恢复async方法的"上下文"。在您的示例中,这很可能是一个 UI 上下文,它始终只有一个线程(UI 线程(。因此,如果通过调用 WaitResult 来阻止 UI 线程,则 async 方法无法重新进入 UI 上下文以完成其执行(并且您最终会等待无法完成的Task(。

编辑:

由于您是数据绑定,我建议在此处使用 NotifyTaskCompletion 类型(它很快就会成为我的 AsyncEx 库的一部分(:

public MyViewModel()
{
    UpcomingMovies = NotifyTaskCompletion.Create(LoadUpcomingMoviesAsync());
}
public INotifyTaskCompletion<List<MovieViewModel>> UpcomingMovies { get; private set; }
private async Task<List<MovieViewModel>> LoadUpcomingMoviesAsync()
{
    System.Diagnostics.Debug.WriteLine("UpcomingMovies - Begin");             
    var apiMovies = await _serviceRT.FindUpcomingMoviesList();
    var movies = apiMovies.Select(result => new MovieViewModel(result)).ToList();
    System.Diagnostics.Debug.WriteLine("UpcomingMovies - End");
    return movies;
}

然后,您可以安全地绑定到如下所示的INotifyTaskCompletion<T>.Result

{Binding UpcomingMovies.Result}

请注意,在加载影片之前,结果将是null,因此您的视图将为空。此外,如果加载影片时出错,您的视图将始终为空。我建议您通过数据绑定到其他INotifyTaskCompletion<T>属性来处理这些情况,例如:

  • {Binding UpcomingMovies.IsCompleted} ,它将从false开始,并在加载完成(成功或错误(时变得true
  • {Binding UpcomingMovies.IsSuccessfullyCompleted} ,仅当/当加载成功完成时才会true
  • {Binding UpcomingMovies.IsFaulted} ,仅当/当加载完成并出现错误时,才会变为true
  • {Binding UpcomingMovies.ErrorMessage} ,提取错误消息(如果没有错误,则null(

HttpClient 根据调用它的平台而受到限制(如果与"大窗口"相比,则与 Windows Phone 上的其他网络相关 API 一样(。也许,这个操作方法会有所帮助:http://blogs.msdn.com/b/bclteam/archive/2013/02/18/portable-httpclient-for-net-framework-and-windows-phone.aspx

HttpClientHandler handler = new HttpClientHandler();
httpClient = new HttpClient(handler);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, resourceAddress);
request.Content = streamContent;
if (handler.SupportsTransferEncodingChunked())
{
    request.Headers.TransferEncodingChunked = true;
}
HttpResponseMessage response = await httpClient.SendAsync(request);