I've got a method, CheckForValue()
, that uses named pipes to send a message to another process running locally, and then receive a message from that process, returning a bool indicating if it is equivalent with some value.
I'm concerned that I am not handling CancellationToken
s and errors correctly. If there any errors (or timeouts), I just want this method to return false
.
Again, I am not concerned with different methods of IPC, or using a single duplex named pipe, etc. My concern is the error handling and the usage of CancellationToken
s here.
CheckForValue
public async Task<bool> CheckForValue()
{
int timeout = 300; //300ms should be plenty of time
try
{
using (var getValueCancellationTokenSource = new CancellationTokenSource())
{
var valueTask = GetValueUsingNamedPipe(getValueCancellationTokenSource);
using (var timeoutCancellationTokenSource = new CancellationTokenSource())
{
var completedTask = await Task.WhenAny(valueTask, Task.Delay(timeout, timeoutCancellationTokenSource.Token));
if (completedTask == valueTask)
{
if (timeoutCancellationTokenSource.Token.CanBeCanceled)
{
timeoutCancellationTokenSource.Cancel();
}
var result = valueTask.Result;
return (result == "WhatIWant");
}
if (getValueCancellationTokenSource.Token.CanBeCanceled)
{
getValueCancellationTokenSource.Cancel ();
}
return false;
}
}
}
catch (Exception)
{
return false;
}
}
GetValueUsingNamedPipe
public async Task<string> GetValueUsingNamedPipe(CancellationTokenSource ct)
{
var response = "";
try
{
Task sendMsg = SendMessage ("MyMessage", ct);
await sendMsg;
response = await Listen(ct);
}
catch (Exception)
{
return "";
}
return response;
}
SendMessage
public async Task SendMessage(string message, CancellationTokenSource ct)
{
try
{
using (var _pipeClientStream = new NamedPipeClientStream(".", "MyPipe", PipeDirection.Out, PipeOptions.Asynchronous))
{
await _pipeClientStream.ConnectAsync (1000, ct.Token);
var writer = new StreamWriter (_pipeClientStream) { AutoFlush = true };
await writer.WriteLineAsync (message);
await writer.WriteLineAsync (MessageFooter);
}
}
catch (Exception)
{
await Task.FromCanceled(ct.Token);
}
}
Listen
public async Task<string> Listen(CancellationTokenSource ct)
{
try
{
if (ct.Token.IsCancellationRequested)
{
ct.Token.ThrowIfCancellationRequested ();
}
using (var _pipeClientStream = new NamedPipeClientStream(".", "MyListenPipe", PipeDirection.In, PipeOptions.Asynchronous, TokenImpersonationLevel.Impersonation))
{
await _pipeClientStream.ConnectAsync (ct.Token);
if (!ct.IsCancellationRequested)
{
var sb = new StringBuilder ();
var reader = new StreamReader (_pipeClientStream);
do
{
string line = await reader.ReadLineAsync ();
if (line == MessageFooter || line == null)
{
break;
}
sb.AppendLine (line);
} while (true);
return sb.ToString ();
}
return "";
}
}
catch (Exception e)
{
return "";
}
}
timeoutCancellationTokenSource
in your code? This wholeTask.WhenAny
andTask.Delay
is unnecessary. You could specify a timeout at thector
of the CTS or by calling theCancelAfter
\$\endgroup\$Task.Delay..
technique: stackoverflow.com/questions/4238345/… \$\endgroup\$