I've got an async discover function which discovers devices in the local network which I call on a button click. I'm sending a broadcast message to all devices and listen for responses for 5 seconds using a CancellationTokenSource. After the token has expired I'm returning an IEnumerable of parsed responses to my WPF model.
I'd like return incoming responses directly (and stop listening after 5 seconds) so that I can show discovered devices instantly in the UI instead of showing them all after 5 seconds.
This is my code:
public async Task<IEnumerable<IDevice>> Discover()
{
var client = new MyClient();
var responseData = await GetResponseData(client);
return this.ParseResponseData(responseData);
}
private IEnumerable<IDevice> ParseResponseData(List<DeviceResponseData> responseData)
{
foreach (var data in responseData)
{
yield return DeviceFactory.Create(data);
}
}
private static async Task<List<DeviceResponseData>> GetResponseData(MyClient client,
int timeout = 5000)
{
var cancellationToken = new CancellationTokenSource(timeout);
var data = new List<DeviceResponseData>();
// ... prepare message and send it
await client.SendAsync(message, new CancellationToken());
try
{
while (!cancellationToken.IsCancellationRequested)
{
// Wait indefinitely until any message is received.
var response = await client.ReceiveAsync(cancellationToken.Token);
data.Add(new DeviceResponseData(/* ... */ response));
}
}
catch (TaskCanceledException e)
{
}
return data;
}
If you want to show results as they come in, there are many ways of achieving this, like decoupled messages, events, etc.
However, you could just use a simple Action
private static async Task<List<DeviceResponseData>> GetResponseData(MyClient client, Action<DeviceResponseData> update, int timeout = 5000)
{
var cancellationToken = new CancellationTokenSource(timeout);
...
while (!cancellationToken.IsCancellationRequested)
{
// Wait indefinitely until any message is received.
var response = await client.ReceiveAsync(cancellationToken.Token);
var result = new DeviceResponseData( /* ... */ response);
data.Add(result);
update(result);
}
...
}
usage
var allResults = await GetResponseData(client,data => UdpateUI(data), timeout);
Note : because this the Async Await Pattern, you wont have to marshal the result form the Action back to the UI Context, if that's where this was called from.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With