C# - 并发I / O操作异常

时间:2011-08-16 21:00:31

标签: c# windows-phone-7 viewmodel webclient

我有一个刷新按钮来更新我的WP7应用程序中的新闻。当我双击或三次点击刷新按钮时,我收到错误

"WebClient does not support concurrent I/O operations" .

我认为那是因为它发送请求三次并使其崩溃。这是我的点击代码。

    private void NewsRefresh_Click(object sender, RoutedEventArgs e)
    {
        var vm = this.DataContext as MainPageViewModel;
        if (vm != null)
        {
            vm.UpdateNews();
        }
    }

如何将其变为“如果忙于取消过程”。

2 个答案:

答案 0 :(得分:2)

WebClient不是很灵活,但如果您真的想使用它,您可以使用IsBusy属性,然后取消正在进行的操作。然后,一旦它被取消,你可以重新启动它。同步存在重要问题。由检查IsBusy和调用CancelAsync组成的操作不是原子操作。幸运的是,DownloadStringCompleted被分派到UI线程,所以你不需要打扰同步。下面的代码段显示了如何实现它。为简单起见,它是Windows窗体。

public partial class Form1 : Form
{
    WebClient _WebClient;
    bool _UpdateNews;

    public Form1()
    {
        InitializeComponent();
        _WebClient = new WebClient();
        _WebClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(_WebClient_DownloadStringCompleted);
        _UpdateNews = false;
    }

    void _WebClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        if (_UpdateNews)
        {
            _UpdateNews = false;
            UpdateNews();
        }
        else if (e.Error != null)
        {
            // Report error 
        }
        else
        {
            MessageBox.Show(e.Result);
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (_WebClient.IsBusy)
        {
            _WebClient.CancelAsync();
            _UpdateNews = true;
        }
        else
        {
            UpdateNews();
        }
    }

    private void UpdateNews()
    {
        _WebClient.DownloadStringAsync(new Uri("http://stackoverflow.com/questions/7084948/c-concurrent-i-o-operations-exception"));
    }
}

答案 1 :(得分:1)

'简单'的方式(虽然不是防弹):

private void NewsRefresh_Click(object sender, RoutedEventArgs e)
{
    try
    {
        NewsRefresh.Enabled = false;
        var vm = this.DataContext as MainPageViewModel;
        if (vm != null)
        {
            vm.UpdateNews();
        }
    }
    finally
    {
        NewsRefresh.Enabled = true;
    }
}

更难的方法需要有关MainPageViewModel究竟是什么以及UpdateNews()的更多细节。基本上,您需要在存储WebClient实例的任何位置存储状态值。在使用WebClient之前,您需要检查是否已经在使用它。当多个线程可能在单个实例上运行时,或者如果您执行多个操作(UpdateNews除外),则会出现此问题。当涉及多个线程时,最简单的方法是使用Mutex围绕WebClient的使用。

当然,另一个选择是不重用WebClient实例,而是为每个新请求创建一个新实例。

<强>更新

嗯,使用DownloadStringAsync肯定会让事情变得有趣。以上代码除非您移动重新启用的代码,否则禁用UI将无效。最简单的方法是使用我的上一个建议,然后创建一个新的WebClient实例。我自己并不喜欢WebClient,而更喜欢使用WebRequest.Create