[英]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
调用Wait
或Result
。 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). 因此,如果通过调用
Wait
或Result
阻止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.