Asynchronous Logon/Logout
In addition to synchronous LogonAsInitiator(string, int, int, bool, IMessage, bool) / Logout(bool) methods, there are corresponding asynchronous LogonAsInitiatorAsync(string, int, int, bool, IMessage) / LogoutAsync() methods. These asynchronous methods can be used when you need to avoid blocking the current thread by the long synchronous operation. For example, it is required when Logon/Logout method is called from an inbound callback. These methods return immediately without waiting for the acknowledgment Logon/Logout message. They return the Task object that can be used to wait for the result of the asynchronous Logon/Logout methods. Then, one can use any necessary method — wait for the task to be completed synchronously, check for completion when needed, run a separate task to wait, or not wait at all:
const string SenderCompId = "SenderCompID";
const string SargetCompId = "TargetCompID";
const ProtocolVersion Version = ProtocolVersion.Fix44;
int CounterpartyPort = Engine.Instance.Settings.ListenPorts[0];
TimeSpan Timeout = TimeSpan.FromSeconds(10);
using Session initiator = new(SargetCompId, SenderCompId, Version);
// Let's assume that in this place we need to avoid blocking the current thread.
// Sends the Logon message and returns immediately without waiting the acknowledgment Logon message.
var logonTask = initiator.LogonAsInitiatorAsync("localhost", CounterpartyPort);
// Continue to perform some important work in the current thread.
// Let's assume that in this place we can wait for the result of asynchronous Logon.
try
{
logonTask.Wait(Timeout);
}
catch (AggregateException aggEx)
{
aggEx.Handle(ex =>
{
switch (ex)
{
case FirstMessageNotLogonException firstMessageNotLogon:
Console.WriteLine($"FirstMessageNotLogonException: {firstMessageNotLogon.Message}");
return true;
case LinkErrorException linkError:
Console.WriteLine($"LinkErrorException: {linkError.Message}");
return true;
case LogonReplyTimeoutException logonReplyTimeout:
Console.WriteLine($"LogonReplyTimeoutException: {logonReplyTimeout.Message}");
return true;
case UnexpectedSequenceNumberException unexpectedSequenceNumber:
Console.WriteLine($"UnexpectedSequenceNumberException: {unexpectedSequenceNumber.Message}");
return true;
default:
Console.WriteLine($"Unhandled exception: {ex.GetType()}: {ex.Message}");
return false;
}
});
}
Console.WriteLine("Logon is performed successfully.");
// Let's assume that in this place we need to avoid blocking the current thread.
// Sends the Logout message and returns immediately without waiting the acknowledgment Logout message.
var logoutTask = initiator.LogoutAsync();
// Continue to perform some important work in the current thread.
// Let's assume that in this place we can wait for the result of asynchronous Logout.
try
{
logoutTask.Wait(Timeout);
}
catch (AggregateException aggEx)
{
aggEx.Handle(ex =>
{
switch (ex)
{
case LinkErrorException linkError:
Console.WriteLine($"LinkErrorException: {linkError.Message}");
return true;
case LogoutReplyTimeoutException logoutReplyTimeout:
Console.WriteLine($"LogoutReplyTimeoutException: {logoutReplyTimeout.Message}");
return true;
default:
Console.WriteLine($"Unhandled exception: {ex.GetType()}: {ex.Message}");
return false;
}
});
}
Console.WriteLine("Logout is performed successfully.");
Note
Using the await construction with the asynchronous Logon/Logout methods is not recommended. When the session's receiving thread receives the confirmation Logon/Logout, the Task object is set to the completed state, and the code continuation is run in the context of the receiving thread. It can lead to unexpected results and can block the receiving thread if the code continuation performs a synchronous code.