问题描述
我昨天问this question。
本质上,我试图从URL解析XML,但是如果尝试读取XML时连接断开,我的代码将永远挂起。
我仍然遇到相同的问题,但是我更改了代码,以至于如果中断与URL的连接,我会防止程序冻结。有人可以解释为什么我的解决方案不起作用以及如何解决吗?谢谢!
这是我正在使用的两个功能。 CanReach
只是检查连接以确保URL在那里,并且GetTags
获取XML文件的所有父标记。如果连接中断,我希望它断开。我试图通过加载xml文件而不是直接从URL解析并使用try
和catch
来捕获错误来做到这一点。 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;
}
}