URL中的XML中断时C#挂起代码

问题描述

我昨天问this question

本质上,我试图从URL解析XML,但是如果尝试读取XML时连接断开,我的代码将永远挂起。

我仍然遇到相同的问题,但是我更改了代码,以至于如果中断与URL的连接,我会防止程序冻结。有人可以解释为什么我的解决方案不起作用以及如何解决吗?谢谢!

这是我正在使用的两个功能CanReach只是检查连接以确保URL在那里,并且GetTags获取XML文件的所有父标记。如果连接中断,我希望它断开。我试图通过加载xml文件而不是直接从URL解析并使用trycatch来捕获错误来做到这一点。 xmlLocation是URL。

public static bool CanReach(string xmlLocation)
{
    WebRequest request = WebRequest.Create(xmlLocation);                                    
    request.Timeout = 1000;
    try                                                                                     
    {
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        response.dispose();                                                                 
        request.Abort();                                                                    
        return true;                                                                        
    }
    catch (System.Net.WebException)                                                          
    {
        request.Abort();                                                                    
        return false;                                                                       
    }
}

public static List<string> GetTopTags(string xmlLocation)
{
    bool canBeReached = CanReach(xmlLocation);
    if (canBeReached)
    {
        try
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlLocation);                                 
            XmlReader reader = new XmlNodeReader(xmlDoc);
            List<string> dataList = new List<string>();            
            while (reader.Read())                                                                   
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Text:                                                          
                        dataList.Add(reader.Name);                                                   
                        break;                                                                      
                }
            }
            reader.dispose();
            return topTags;                                                                       
        }
        catch
        {
            return null;
        }
    }
    else
    {
        return null;
    }
    
}

解决方法

我们可以从另一个线程开始读取XML文件,而当前方法可以连续检查连接是否处于活动状态。如果无法再访问URL,则可以取消该操作并返回null。如果读取操作完成,则设置isFinished标志,我们可以返回returnValue

尝试一下:

public static List<string> GetTopTags(string xmlLocation)
{
    bool canBeReached = CanReach(xmlLocation);

    if (!canBeReached)
        return null;

    List<string> returnValue = null;
    CancellationTokenSource cts = new CancellationTokenSource();
    bool isFinished = false;

    Task.Factory.StartNew(() =>
    {
        try
        {
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlLocation);
            using var reader = new XmlNodeReader(xmlDoc);
            List<string> dataList = new List<string>();

            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Text:
                        dataList.Add(reader.Name);
                        break;
                }
            }

            if (reader.ReadState == ReadState.Error)
                returnValue = null;
            else
                returnValue = topTags;
        }
        catch
        {
            returnValue = null;
        }

        isFinished = true;
    },cts.Token,TaskCreationOptions.LongRunning,TaskScheduler.Default);

    while (!isFinished)
        if (!CanReach(xmlLocation))
            cts.Cancel();

    return returnValue;
}
,

我对XmlDocument.Load()并为它传递一个URL并不陌生。您将交出过多的控制权,这使您难以调试。我将把网络和XML阅读分开。在网络分离的情况下,您无需使用CanReach()功能。任何与网络相关的东西都需要在单独的线程中运行。根据您的来源,我可能会从以下内容开始。

public static async Task<List<string>> GetTopTags(string xmlLocation)
{
    string xmlText = null;

    try
    {
        // You are free to use WebRequest here,I've used WebClient for simplicity.
        using (var webClient = new WebClient())
        {
            xmlText = await webClient.DownloadStringTaskAsync(xmlLocation);
        }
    }
    catch (Exception)
    {
        // Handle network related issues.
    }

    if (string.IsNullOrWhiteSpace(xmlText))
    {
        // We weren't able to download the XML,or the downloaded XML is not valid,// "CanReach()" is false.
        return null;
    }

    // We downloaded the XML successfully if you get here,now just read it.

    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.Load(new StringReader(xmlText));

    using (XmlReader reader = new XmlNodeReader(xmlDoc))
    {
        List<string> dataList = new List<string>();

        while (reader.Read())
        {
            switch (reader.NodeType)
            {
                case XmlNodeType.Text:
                    dataList.Add(reader.Name);
                    break;
            }
        }

        return dataList;
    }
}