I wrote a Client/Server async classes which works fine in the console. I created a WinForm project for the server which subscribes to an event thrown by the server when there is a .Pending()
connection and writes some messages into a textbox - which causes a Cross-Thread exception. The exception does not surprise me, however I am looking for a way to invoke that event without causing this exception, without handling it on the GUI/Control with .InvokeRequired
and .Invoke
- if that is even possible?
The server is started like that:
Server server = new Server(PORT);
server.RunAsync();
in .RunAsync()
i just iterate over the network devices and set them to listening and invoke an event that the server has started, this also writes into the GUI however without any issue.
public async Task RunAsync()
{
GetNetworkDevicesReady(Port);
await Task.Factory.StartNew(() =>
{
Parallel.ForEach(networkListeners, (listener) =>
{
Write.Info($"LISTENING ON {listener.LocalEndpoint}");
listener.Start();
});
});
IsRunning = true;
OnServerStarted?.Invoke(this, networkListeners.Where(l=>l.Active).ToList());
}
The code below is registered on the Form.Load
event and does not cause a Cross-Thread exception when writing "SERVER STARTED" in the textbox.
server.OnServerStarted += (s, a) =>
{
consoleWindow1.Event("SERVER STARTED", $"{Environment.NewLine}\t{string.Join($"{Environment.NewLine}\t", a.Select(x=>x.LocalEndpoint))}");
consoleWindow1.Event("WAITING FOR PENDING CONNECTIONS");
server.WaitForConnectionsAsync();
};
And this is the code which runs indefinite until a cancellation token is triggered:
public async Task WaitForConnectionsAsync()
{
waitingForConnectionsToken = new CancellationTokenSource();
await (waitinfConnectionTaks=Task.Factory.StartNew(async () =>
{
while (!waitingForConnectionsToken.IsCancellationRequested)
{
foreach (var listener in networkListeners)
{
if (waitingForConnectionsToken.IsCancellationRequested) break;
if (!listener.Active)
{
continue;
}
if (listener.Pending())
{
try
{
TcpClient connection = await listener.AcceptTcpClientAsync();
//TODO: need to send it synchronised, since this causes a Cross-Thread when using WinForms
OnPendingConnection?.Invoke(this, connection);
}
catch (ObjectDisposedException x)
{
Write.Error(x.ToString());
}
}
}
}
}));
}
I know I can use the textbox .InvokeRequired
and .Invoke
on the GUI but I have the feeling that the server should throw the event in a way the GUI doesn't cause a Cross-Thread exception.
Is there a way to invoke the eventhandler in that "infinite task" without causing this exception?