I'm working with quite specific web API that uses TCP and SSL stream. The connection to API is persistent (should not be closed after each write/read), because this connection is used to receive event notifications from the server.
So I implemented a cycled reading method:
private void Listen()
{
int length;
do
{
var buffer = new byte[TcpClient.ReceiveBufferSize];
length = SslStream.Read(buffer, 0, TcpClient.ReceiveBufferSize);
if (length > 0)
{
// Process received data
Listen();
}
} while (length > 0);
//reconnect
}
Now I need to call some API methods. I want them to support TPL (async and await). The problem is that the asynchronous part of these methods are actually implemented in the reading method above (Listen). For example:
public async Task<bool> Authenticate(string clientId, string clientSecret)
{
await SendAuthMessageOverNetwork(clientId, clientSecret);
return await ReceiveAuthResponseFromServer();
// The problem is that there is no ReceiveAuthResponseFromServer method -
// the response is received in reading thread (Listen).
}
I'm not quite familiar with TPL yet. I solved this problem by using a Task which actually does not do anything but wait a signal (AutoResetEvent) from the reading thread:
private AutoResetEvent _loginEvent;
private bool _loginResult;
public async Task<bool> Authenticate(string clientId, string clientSecret)
{
await SendAuthMessageOverNetwork(clientId, clientSecret);
return await Task<bool>.Factory.StartNew(() => { _loginEvent.WaitOne(); return _loginResult; });
}
private void Listen()
{
...
if (msg.Type == MessageTypes.AuthenticationResponse)
{
_loginResult = true;
_loginEvent.Set();
}
...
}
But I don't quite like this solution. Maybe there is a simpler way to implement what I want to? Can this be done by using only Task functionality, without AutoResetEvent and intermediate global variable?