我通过将字符串解析为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);
}
}
答案 0 :(得分:3)
你还没有向我们展示_responseBytes
是什么,但有一个建议让人想起:如果它是异步填充的(例如通过异步Web请求),那么第一次尝试可能会在数据出现之前发生,但是当catch块执行时,数据已经到达。
(显然如果是这种情况,解决方案是不使用这种catch块但是要修复时间。)
编辑:好的,我想我可能会看到问题所在。就在这里:e.AsyncWaitHandle.WaitOne();
我怀疑它会等到读取在套接字级别发生,但在调用回调之前。您的代码假设它等待回调完成。
所发生的事情(这仍然只是猜测)是:
WaitOne()
在主线程中返回,同时在线程池线程上调用回调