2011-01-14 32 views
1

我觀察到一個奇怪的行爲,通過解析字符串到XElement。C# - 解析XElement時的奇怪行爲

首先,這裏是我想要解析XML:

<return value="0"> 
    <resultset> 
     <meta> 
      <column type="char(30)"></column> 
     </meta> 
     <datarow> 
      <datacol> 
       <![CDATA[master]]> 
      </datacol> 
     </datarow> 
    </resultset> 
</return> 

現在代碼:

  try 
      { 
       xmlResult = XElement.Parse(
        _UTF8Encoder.GetString(_responseBytes.GetBuffer(), 0, (int)_responseBytes.Length), 
        LoadOptions.PreserveWhitespace); 
      } 
      catch 
      { 
       xmlResult = XElement.Parse(
        _UTF8Encoder.GetString(_responseBytes.GetBuffer(), 0, (int)_responseBytes.Length), 
        LoadOptions.PreserveWhitespace); 
      } 

我做同樣的事情在try和catch塊。

有時候,try塊會引發XmlException(「Root元素丟失」),但catch塊(完全一樣的東西)不會拋出它並正確解析字符串。

有人能告訴我爲什麼嗎?

謝謝!

[編輯]

這裏是整個方法的代碼:

private TcpClient _client; 
private NetworkStream _clientStream; 
private MemoryStream _responseBytes; 
private readonly UTF8Encoding _UTF8Encoder = new UTF8Encoding(); 
private const int BUFFER_SIZE = 1024; 

    private XElement Receive() 
    { 
     byte[] buffer = new byte[BUFFER_SIZE]; 

     XElement xmlResult; 
     Encoding serverEncoding = this.Task.Server.Encoding; 

     // Reading result 
     while (true) 
     { 
      _responseBytes = new MemoryStream(); 

      try 
      { 
       IAsyncResult e = _clientStream.BeginRead(buffer, 
        0,            // Begin 
        BUFFER_SIZE,         // Length 
        new AsyncCallback(OnBeginRead),     // Callback used 
        new SocketAsyncState(_clientStream, buffer)); // Passing buffer to callback 

       e.AsyncWaitHandle.WaitOne(); // Wait until data are in pipe 

       if (((SocketAsyncState)e.AsyncState).HasError) 
       { 
        throw new ObjectDisposedException(); 
       } 

       // Try to convert to a XElement, if fail, redo all process. 
       _responseBytes.Position = 0; 

       try 
       { 
        xmlResult = XElement.Parse(
         _UTF8Encoder.GetString(_responseBytes.GetBuffer(), 0, (int)_responseBytes.Length), 
         LoadOptions.PreserveWhitespace); 
       } 
       catch 
       { 
        xmlResult = XElement.Parse(
         _UTF8Encoder.GetString(_responseBytes.GetBuffer(), 0, (int)_responseBytes.Length), 
         LoadOptions.PreserveWhitespace); 
       } 

       // Result 100% retrieved : quit loop 
       break; 
      } 
      catch (Exception ex) 
      { 

       if (ex is ObjectDisposedException 
        || ex is XmlException) 
       { 
        while (!IsConnected) { Wait(); } // Wait that the network comes back 
        SendSyn();       // Relaunch process 
       } 
      } 
     } 

     // Result 100% retrieved : send ACK to Socket 
     SendAck(); 

     return xmlResult; 
    } 

    private void OnBeginRead(IAsyncResult ar) 
    { 
     SocketAsyncState state = ar.AsyncState as SocketAsyncState; 
     byte[] nextBuffer = new byte[BUFFER_SIZE]; 
     int numberOfBytesReaded; 
     Encoding serverEncoding = this.Task.Server.Encoding; 

     try 
     { 
      numberOfBytesReaded = state.Stream.EndRead(ar); 
     } 
     catch(Exception) 
     { 
      ((SocketAsyncState)ar.AsyncState).HasError = true; 
      // Quit 
      return; 
     } 

     // While data are available, read next buffer (recursive call to this method) 
     if (state.Stream.DataAvailable && state.Stream.CanRead) 
     { 
      state.Stream.BeginRead(nextBuffer, 
       0, 
       BUFFER_SIZE, 
       new AsyncCallback(OnBeginRead), 
       new SocketAsyncState(state.Stream, nextBuffer)); 
     } 

     // Default C# strings are in UTF-8, so convert stream only if needed 
     if (serverEncoding.CodePage != _UTF8Encoder.CodePage) 
     { 
      byte[] buffer = Encoding.Convert(serverEncoding, 
       _UTF8Encoder, 
       state.Data.TakeWhile((b) => b != '\0').ToArray()); 

      _responseBytes.Write(buffer, 0, buffer.Length); 
     } 
     else 
     { 
      _responseBytes.Write(state.Data, 0, numberOfBytesReaded); 

     } 
    } 

回答

3

你還沒有告訴我們什麼_responseBytes是,但一個建議彈簧記:如果它被異步填充(例如,通過一個異步Web請求),那麼可能第一次嘗試發生在數據存在之前,但在catch塊執行時,數據已經到達。

(顯然,如果是這樣的話,解決的辦法是使用這種catch塊,但以固定的時間。)

編輯:好的,我想我可能看到的問題。它在這裏:

e.AsyncWaitHandle.WaitOne(); 

我懷疑會等到讀已在套接字級別發生,但回調之前被調用。你的代碼假設它等到回調有完成

所以發生了什麼(這仍然只是一個猜測)是:

  • 在你的主線程,您揭開序幕的操作,並等待它完成
  • 的數據讀取
  • WaitOne()在主線程中返回,同時在線程池線程上調用回調
  • 您試圖從主線程中解析內存流中的數據...
  • ... an d 然後回調實際上是將數據寫入內存流
  • ...和然後你有第二次嘗試解析,其成功,因爲數據是現在有
+0

請參閱編輯。你是對的,所有的都是異步完成的,但是似乎很奇怪MemoryStream沒有被填充...... – 2011-01-14 11:56:44