我有一个运行后台线程的应用程序,它可以与多个设备通信。设备根据我无法控制的外部触发器向我发送数据。我必须等待设备向我发送数据并对其进行操作。如果发生异常,我需要在UI上显示该异常。
我试图通过网络流连续读取数据。当数据到来时,我需要将其作为事件提升,然后再次开始阅读。如果抛出异常,我需要能够处理,例如设备被断开。
在基地,我有一个异步读取的网络流
public Task<string> ReadLinesAsync(CancellationToken token)
{
_readBuffer = new byte[c_readBufferSize];
// start asynchronously reading data
Task<int> streamTask = _networkstream.ReadAsync(_readBuffer, 0, c_readBufferSize, token);
// wait for data to arrive
Task<String> resultTask = streamTask.ContinueWith<String>(antecedent =>
{
// resize the result to the size of the data that was returned
Array.Resize(ref _readBuffer, streamTask.Result);
// convert returned data to string
var result = Encoding.ASCII.GetString(_readBuffer);
return result; // return read string
}, token);
return resultTask;
}
所以我尝试这样做的方法是在启动时,我通过运行Start()方法启动一个正在读取的线程。但是当抛出一个异常时它会杀死我的程序,即使我在它周围设置了一些错误。我一直试图将它捕获到不同的地方,只是为了看看会发生什么,但我无法找到正确的方法来做到这一点,以便我可以将错误提升到用户界面而不会轰炸我的应用程序。
async public override void Start()
{
try
{
await _client.ReadLinesAsync(_cts.Token).ContinueWith(ReadLinesOnContinuationAction, _cts.Token);
}
catch (AggregateException ae)
{
ae.Handle((exc) =>
{
if (exc is TaskCanceledException)
{
_log.Info(Name + " - Start() - AggregateException"
+ " - OperationCanceledException Handled.");
return true;
}
else
{
_log.Error(Name + " - Start() - AggregateException - Unhandled Exception"
+ exc.Message, ae);
return false;
}
});
}
catch (Exception ex)
{
_log.Error(Name + " - Start() - unhandled exception.", ex);
}
}
async private void ReadLinesOnContinuationAction(Task<String> text)
{
try
{
DataHasBeenReceived = true;
IsConnected = true;
_readLines.Append(text.Result);
if (OnLineRead != null) OnLineRead(Name, _readLines.ToString());
_readLines.Clear();
await _client.ReadLinesAsync(_cts.Token).ContinueWith(ReadLinesOnContinuationAction, _cts.Token);
}
catch (Exception)
{
_log.Error(Name + " - ReadLinesOnContinuationAction()");
}
}
调试器通常会停在线上:
_readLines.Append(text.Result);
我试着把它放在检查文本.IsFaulted标志,然后我轰炸了.ContinueWith。
有没有人对我需要解决的问题有任何想法,以便我可以正确捕获错误并将偶数提升到UI?这段代码有各种难闻的气味,但我正在学习这个。感谢您提供任何帮助。
答案 0 :(得分:1)
轰炸了ContinueWith?你看到至少有两个。
就个人而言,我不会将async / await与ContinueWith混合使用。 await已经为您提供了一个方便的方法来执行ContinueWith,所以就这样使用它。例如:
public async Task<string> ReadLinesAsync(CancellationToken token)
{
_readBuffer = new byte[c_readBufferSize];
// start asynchronously reading data
int readResult = await _networkstream.ReadAsync(_readBuffer, 0, c_readBufferSize, token);
// after data arrives...
// resize the result to the size of the data that was returned
Array.Resize(ref _readBuffer, streamTask.Result);
// convert returned data to string
return Encoding.ASCII.GetString(_readBuffer);
}
async public override void Start()
{
try
{
string text = await _client.ReadLinesAsync(_cts.Token);
await ReadLinesOnContinuationAction(text);
}
catch (AggregateException ae)
{
ae.Handle((exc) =>
{
if (exc is TaskCanceledException)
{
_log.Info(Name + " - Start() - AggregateException"
+ " - OperationCanceledException Handled.");
return true;
}
else
{
_log.Error(Name + " - Start() - AggregateException - Unhandled Exception"
+ exc.Message, ae);
return false;
}
});
}
catch (Exception ex)
{
_log.Error(Name + " - Start() - unhandled exception.", ex);
}
}
async private Task ReadLinesOnContinuationAction(Task<String> text)
{
try
{
DataHasBeenReceived = true;
IsConnected = true;
_readLines.Append(text.Result);
if (OnLineRead != null) OnLineRead(Name, _readLines.ToString());
_readLines.Clear();
string text = await _client.ReadLinesAsync(_cts.Token);
await ReadLinesOnContinuationAction(text);
}
catch (Exception)
{
_log.Error(Name + " - ReadLinesOnContinuationAction()");
}
}
或类似的东西。上面显然没有编译,可能需要一点点按摩才能正确。但希望总体思路足够明确。