ASP.Net在尝试读取XML文件时,出现“尝试对不存在的网络连接进行操作”的错误。

12
string url = "http://www.example.com/feed.xml";
var settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.IgnoreProcessingInstructions = true;
settings.IgnoreWhitespace = true;
settings.XmlResolver = null;
settings.DtdProcessing = DtdProcessing.Parse;
settings.CheckCharacters = false;
var request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 900000;
request.KeepAlive = true;
request.IfModifiedSince = lastModified;
var response = (HttpWebResponse)request.GetResponse();
Stream stream;
stream = response.GetResponseStream();
stream.ReadTimeout = 600000;
var xmlReader = XmlReader.Create(stream, settings);

while (!xmlReader.EOF)
{
...
当我尝试在一个非常缓慢的大型xml文件上运行时,我的Azure Web应用程序会在几分钟后抛出空白页面。 我在Azure的故障请求跟踪日志中看到了这个: ModuleName:DynamicCompressionModule Notification:SEND_RESPONSE HttpStatus:500 HttpReason:Internal Server Error HttpSubStatus:19 ErrorCode:An operation was attempted on a nonexistent network connection. (0x800704cd) 可以看到,我一直在“玩弄”超时设置。也尝试捕捉所有异常,但没有捕捉到任何异常。 此外,在我的计算机上本地调试Web应用程序时,这个问题没有任何问题。可能是我办公室的互联网连接比Azure更好,导致XML文件被快速读取,没有任何问题。 有什么可能的解决方法吗? 编辑:我想保持XML文件的流式传输(我避免下载整个文件,因为用户可以选择只阅读源的前N个条目)。如果无法避免上述问题,我将很高兴有人帮助我向用户显示有意义的消息,而不是空白页。

1
我肯定会打赌,大小和下载时间会影响某些内容代理在Azure云内重置您的连接。 - dresende
这也可能是由于服务器超时引起的,即您的代码连接到的那个服务器(在这里它将是“http://www.example.com/feed.xml”)。 - Simon Mourier
是的,@SimonMourier,我相信你可能是对的。但当我无法捕获异常并向用户提供有意义的消息时,这非常令人沮丧。 - Paul0PT
你可以尝试使用 ServiceStack 库。查看这个其他的 SO 线程 https://dev59.com/B2kw5IYBdhLWcg3wPIF7 - Chuck Savage
你要下载的这个 XML 文件有多大? - Thiago Lunardi
3个回答

2
尝试使用WebClient类获取xml文件。
string xmlAsString;
using (var xmlWebClient = new WebClient())
            {
                xmlWebClient.Encoding = Encoding.UTF8;
                xmlAsString = xmlWebClient.DownloadString(url);
            }

XmlDocument currentXml = new XmlDocument();
currentXml.Load(xmlAsString);

1
谢谢Andrei!这似乎是一个不错的替代方案,但我尽量避免使用它,因为我不想下载1GB以上的XML文件并将它们加载到内存中,所以我更喜欢流式传输。如果我找不到更好的解决方案,我会记住这个的。 - Paul0PT

1
你可以直接使用


string url = "http://www.example.com/feed.xml";
using(var reader = XmlReader.Create(url){

我希望它能够工作,因为支持url(请参见此处)。然后可以通过yield return x使用流。这可能是最好的选择,因为您可以让本机组件以其想要的方式处理流式传输。您甚至可以通过ReadValueChunk方法对文件进行分块。

另一个考虑因素,也是我猜测的问题,就是Azure实例的大小。除非在最高层,否则Azure实例的内存量很少。

我还没有看到您释放任何流的情况,这也可能导致内存泄漏和过度内存使用。

考虑到它在您的设备上运行良好,并且大多数个人计算机至少与A3实例(顶部下面一层)一样强大,以及拥有清理本地内存泄漏的IDE,似乎Azure实例可能是问题所在。

一个潜在的解决方案是使用文件流。在某个大小之后,内存流和文件流非常相似。一个使用文件系统,而另一个使用sys文件(我记得是pagefile.sys),因此将其转换为文件流对性能影响很小,但缺点是在完成后必须清理文件。但在考虑成本时,磁盘流在Azure世界中更便宜。


0
尝试这个。
    static IEnumerable<XElement> StreamCustomerItem(string uri)
   {
    using (XmlReader reader = XmlReader.Create(uri))
    {
        XElement name = null;
        XElement item = null;

        reader.MoveToContent();

        // Parse the file, save header information when encountered, and yield the
        // Item XElement objects as they are created.

        // loop through Customer elements
        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element
                && reader.Name == "Customer")
            {
                // move to Name element
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element &&
                        reader.Name == "Name")
                    {
                        name = XElement.ReadFrom(reader) as XElement;
                        break;
                    }
                }

                // loop through Item elements
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.EndElement)
                        break;
                    if (reader.NodeType == XmlNodeType.Element
                        && reader.Name == "Item")
                    {
                        item = XElement.ReadFrom(reader) as XElement;
                        if (item != null)
                        {
                            XElement tempRoot = new XElement("Root",
                                new XElement(name)
                            );
                            tempRoot.Add(item);
                            yield return item;
                        }
                    }
                }
            }
        }
    }
}

static void Main(string[] args)
{
    XStreamingElement root = new XStreamingElement("Root",
        from el in StreamCustomerItem("Source.xml")
        select new XElement("Item",
            new XElement("Customer", (string)el.Parent.Element("Name")),
            new XElement(el.Element("Key"))
        )
    );
    root.Save("Test.xml");
    Console.WriteLine(File.ReadAllText("Test.xml"));
}

基于以下 XML

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <Item>
    <Customer>A. Datum Corporation</Customer>
    <Key>0001</Key>
  </Item>
  <Item>
    <Customer>A. Datum Corporation</Customer>
    <Key>0002</Key>
  </Item>
  <Item>
    <Customer>A. Datum Corporation</Customer>
    <Key>0003</Key>
  </Item>
  <Item>
    <Customer>A. Datum Corporation</Customer>
    <Key>0004</Key>
  </Item>
  <Item>
    <Customer>Fabrikam, Inc.</Customer>
    <Key>0005</Key>
  </Item>
  <Item>
    <Customer>Fabrikam, Inc.</Customer>
    <Key>0006</Key>
  </Item>
  <Item>
    <Customer>Fabrikam, Inc.</Customer>
    <Key>0007</Key>
  </Item>
  <Item>
    <Customer>Fabrikam, Inc.</Customer>
    <Key>0008</Key>
  </Item>
  <Item>
    <Customer>Southridge Video</Customer>
    <Key>0009</Key>
  </Item>
  <Item>
    <Customer>Southridge Video</Customer>
    <Key>0010</Key>
  </Item>
</Root>

了解更多细节


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接