简体   繁体   English

HttpClient在Windows Phone中不返回

[英]HttpClient doesn't return in Windows Phone

Simple enough, here's my code: 很简单,这是我的代码:

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

it prints the first string but there's no way to get to second one, and this means that the client.GetStringAsync doesn't return. 它输出第一个字符串,但无法到达第二个字符串,这意味着client.GetStringAsync不返回。

The URL is ok, it loads fine. URL正常,可以正常加载。

What's my problem? 我怎么了

EDIT 2: (Removed as useless now) 编辑2:(现已删除为无用)

EDIT 3: 编辑3:

I'm adding the methods that I'm using to let you know what's the flow of my data. 我添加了正在使用的方法,以使您知道数据的流向。

Page.xaml Page.xaml

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

UpcomingMovies is bound to this property 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;
        }
}

the _serviceRT.FindUpcomingMoviesList() method: _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;
}

Finally, the GetJsonResponse() is at the beginning of the question. 最后, GetJsonResponse()在问题的开头。

Now, having the full data flow, how can I bind this property and still make the download complete? 现在,有了完整的数据流,我如何绑定此属性并仍然使下载完成?

I predict that further up in your call stack, you are calling Wait or Result on a Task returned from an async method. 我预测在您的调用堆栈中,您正在通过async方法返回的Task调用WaitResult This can easily cause deadlock , as I describe on my blog. 正如我在博客中所述, 这很容易导致死锁

This happens because await will by default capture a "context" which it uses to resume the async method. 发生这种情况是因为await默认情况下将捕获“上下文”,它将用于恢复async方法。 In your example, this is most likely a UI context, which always has exactly one thread (the UI thread). 在您的示例中,这很可能是一个UI上下文,它始终只有一个线程(UI线程)。 So if you block the UI thread by calling Wait or Result , then the async method cannot re-enter the UI context to complete its execution (and you end up waiting for a Task that cannot complete). 因此,如果通过调用WaitResult阻止UI线程,则async方法无法重新输入UI上下文以完成其执行(并且最终将等待无法完成的Task )。

Edit: 编辑:

Since you're databinding, I recommend using the NotifyTaskCompletion type here (which will soon be part of my AsyncEx library): 由于您是NotifyTaskCompletion数据绑定,因此我建议在此处使用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;
}

Then you can safely bind to INotifyTaskCompletion<T>.Result like this: 然后可以安全地绑定到INotifyTaskCompletion<T>.Result像这样:

{Binding UpcomingMovies.Result}

Note that until you load the movies, the result will be null so your view will be empty. 请注意,在加载影片之前,结果将为null因此视图将为空。 Also, if there is an error loading the movies, your view will always be empty. 另外,如果加载电影时出错,则视图将始终为空。 I recommend that you handle these situations by databinding to the other INotifyTaskCompletion<T> properties, eg: 我建议您通过对其他INotifyTaskCompletion<T>属性进行数据绑定来处理这些情况,例如:

  • {Binding UpcomingMovies.IsCompleted} , which will start out false and become true when the loading completes (either successfully or in error) {Binding UpcomingMovies.IsCompleted} ,它将以false开头,并在加载完成时(成功或错误)变为true
  • {Binding UpcomingMovies.IsSuccessfullyCompleted} , which becomes true only if/when the loading completes successfully {Binding UpcomingMovies.IsSuccessfullyCompleted} ,仅当/当加载成功完成时,它才为true
  • {Binding UpcomingMovies.IsFaulted} , which becomes true only if/when the loading completes with an error {Binding UpcomingMovies.IsFaulted} ,仅当/当加载完成并出现错误时,此选项才为true
  • {Binding UpcomingMovies.ErrorMessage} , which extracts the error message (and is null if there is no error) {Binding UpcomingMovies.ErrorMessage} ,它提取错误消息(如果没有错误,则为null

HttpClient has limitations according to platform it is called from (like other network-related APIs on Windows Phone if compared with "big windows"). HttpClient根据所调用的平台而有所限制(与Windows Phone上其他与网络相关的API相比,如果与“大窗口”进行比较,则类似)。 Maybe, this how-to will help: http://blogs.msdn.com/b/bclteam/archive/2013/02/18/portable-httpclient-for-net-framework-and-windows-phone.aspx 也许,此操作方法将有所帮助: 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM