下载图像时异步/等待死锁

K.A*_*.A. 6 .net c# asynchronous async-await windows-phone-8.1

我正在开发一个Windows Phone 8.1应用程序.我有一个屏幕,上面有一些带有缩略图的新闻标题.

首先,我正在制作异步http请求以获取JSON中的新闻集合(满足NotifyTaskCompletion模式)

NewsCategories = new NotifyTaskCompletion<ObservableCollection<NewsCategory>>(_newsService.GetNewsCategoriesAsync());
Run Code Online (Sandbox Code Playgroud)

新闻分类:

public class NewsCategory : ObservableObject
{
    ...
    public string Title { get;  set; }
    public ObservableCollection<News> Items { get;  set; }
}
Run Code Online (Sandbox Code Playgroud)

新闻:

public class News : ObservableObject
{
    ...
    public string Title { get; set; }
    public string ImagePath { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止它工作得很好,但是一旦我得到了ImagePath属性,我想下载并显示给定的图像.我找到了一个在这里异步执行的解决方案:WP 8.1绑定来自http请求的图像 - 这样当xaml获取图像路径时,它BinaryToImageSourceConverter也会使用NotifyTaskCompletion模式调用转换器类().

问题出现在以下方法中:

private async Task<BitmapImage> GetImage(string path)
{
    HttpClient webCLient = new HttpClient();
    var responseStream = await webCLient.GetStreamAsync(path);
    var memoryStream = new MemoryStream();
    await responseStream.CopyToAsync(memoryStream);
    memoryStream.Position = 0;
    var bitmap = new BitmapImage();
    await bitmap.SetSourceAsync(memoryStream.AsRandomAccessStream());
    return bitmap;
}
Run Code Online (Sandbox Code Playgroud)

await调用第一行时,调试器永远不会到达下一行,并且方法永远不会返回.该string path变量有适当的内容.

到目前为止,我已尝试使用ConfigureAwait(false),但它在我的情况下不起作用.

我也在主题中发现:使用异步等待时的死锁,即:

当你使用时ConfigureAwait(false),你告诉你的程序你不介意上下文.它可以解决一些死锁问题,但通常不是正确的解决方案.正确的解决方案很可能永远不会以阻塞的方式等待任务,并且一直是异步的.

我不知道在哪里可以阻挡这些东西.造成这种僵局的原因是什么?

如果这是关于错误的方法,你知道任何更适合将缩略图下载到一组项目的模式吗?

谢谢您的帮助.


更新:如何GetImage调用:它类似于主题:WP 8.1绑定来自http请求的图像

public class WebPathToImage : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (value == null) return null;
        return new NotifyTaskCompletion<BitmapImage>(GetImage((String)value));
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    { throw new NotImplementedException(); }

    private async Task<BitmapImage> GetImage(string path)
    {
        using (var webCLient = new HttpClient())
        {
            webCLient.DefaultRequestHeaders.Add("User-Agent", "bot");
            var responseStream =  await webCLient.GetStreamAsync(path).ConfigureAwait(false);
            var memoryStream = new MemoryStream();
            await responseStream.CopyToAsync(memoryStream);
            memoryStream.Position = 0;
            var bitmap = new BitmapImage();
            await bitmap.SetSourceAsync(memoryStream.AsRandomAccessStream());
            return bitmap;  
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

并在xaml中:

<Image 
DataContext="{Binding ImagePath, Converter={StaticResource WebPathToImage}}"
Source="{Binding Result}" 
Stretch="UniformToFill" 
Height="79" Width="79"/>
Run Code Online (Sandbox Code Playgroud)

Kri*_*sic 0

首先,如果您使用的是 Windows Phone 8.1,则建议使用HttpClientfrom 命名空间Windows.Web.Http而不是 from System.Net.Http此链接解释了一些原因。

我的答案使用新的,Windows.Web.Http.HttpClient所以你的GetImage方法可以如下所示:

        private async Task<BitmapImage> GetImage(string path)
        {
            using (var webCLient = new Windows.Web.Http.HttpClient())
            {
                webCLient.DefaultRequestHeaders.Add("User-Agent", "bot");
                var responseStream = await webCLient.GetBufferAsync(new Uri(path));
                var memoryStream = new MemoryStream(responseStream.ToArray());
                memoryStream.Position = 0;
                var bitmap = new BitmapImage();
                await bitmap.SetSourceAsync(memoryStream.AsRandomAccessStream());
                return bitmap;
            }
        }
Run Code Online (Sandbox Code Playgroud)

我已经在示例 URL 上测试了此方法,它在控件中正确显示Image

其次,为什么不让Image控件在BitmapImage没有转换器的情况下处理下载,以便您的 XAML 看起来像这样:

<Image
    Source="{Binding ImagePath}" 
    Stretch="UniformToFill" 
    Height="79" 
    Width="79" />
Run Code Online (Sandbox Code Playgroud)

这样您ImagePath就可以成为从互联网和本地资源到资源的路径。