What is the proper way to use WebSocketClient ReceiveAsync and buffer? - c#

I want to create a Bot class in C# for slack to let services create and consume messages for our company. To make it easy for our services to use, I have it just called with Connect() and use an event to let the caller know when there's a message. This is basically how it will be called:
SlackBot bot = new SlackBot(TOKEN);
bot.OnReceiveMessage += message => {
Console.WriteLine("DELEGATE GOT MESSAGE: '{0}'", message);
};
bot.Connect();
The Connect() method calls an internal Receive() method that calls itself after every message:
public delegate void MessageReceivedDelegate(string message);
public event MessageReceivedDelegate OnReceiveMessage;
void Receive()
{
_ReceiveTask = _Client.ReceiveAsync(_ClientBuffer, _CancellationToken);
_ReceiveTask.ContinueWith(twsrr =>
{
WebSocketReceiveResult result = twsrr.Result;
string message = Encoding.ASCII.GetString(_ClientBuffer.Array,
_ClientBuffer.Offset, result.Count);
OnReceiveMessage(message);
Receive();
});
}
So the largest buffer acceptable is 64k, do I need to check result.EndOfMessage and use a MemoryStream or something to to keep adding bytes to until I get the end of the message, then send it?

Looking at the RFC, that seems to be the case to me. I'm less familiar with the WebSocket protocol than the underlying TCP and other network protocols, but if on each call to ReceiveAsync() you actually received a complete message, there would not seem to be a need for the EndOfMessage property on the result.
Note also that your code could benefit from being written in the async/await pattern:
async Task Receive()
{
WebSocketReceiveResult result = await _Client.ReceiveAsync(_ClientBuffer, _CancellationToken);
if (result.Count != 0 || result.CloseStatus == WebSocketCloseStatus.Empty)
{
string message = Encoding.ASCII.GetString(_ClientBuffer.Array,
_ClientBuffer.Offset, result.Count);
OnReceiveMessage(message);
await Receive();
}
}
Or, if you prefer, change the Receive() to async but leave it as void and don't await it. It's an exception to the general rule for async methods, but it would avoid the I/O building a chain of continuations that only gets resolved when the connection is actually closed.

Related

How to start an async method without await its completion?

Sometimes I need to start an async job which works very slow. I don't care if that job success and I need to continue working on my current thread.
Like sometimes I need to send an Email or SMS which works very slow. I need to respond to the web client as soon as possible so I don't want to await it.
I have googled this question and some articles suggest me to write like this:
// This method has to be async
public async Task<Response> SomeHTTPAction()
{
// Some logic...
// ...
// Send an Email but don't care if it successfully sent.
Task.Run(() => _emailService.SendEmailAsync());
return MyRespond();
}
Or like this:
// This method has to be async
public async Task<Response> SomeHTTPAction()
{
// Some logic...
// ...
// Send an Email but don't care if it successfully sent.
Task.Factory.StartNew(() => _emailService.SendEmailAsync());
return MyRespond();
}
There will be a warning says: before the call is completed. Consider applying the 'await' operator to the result of the call.
So what if I really awaited it? What is the best practice in C# to 'fire and forget', just call an async method without waiting for its completion?
A standalone discard is the best way to avoid this warning.
_ = Task.Run(() => _emailService.SendEmailAsync());
Discards are dummy variables and can be used to ignore the Task object returned by an asynchronous operation.
https://learn.microsoft.com/en-us/dotnet/csharp/discards#a-standalone-discard
If you truly just want to fire and forget. Simply don't call use await.
// It is a good idea to add CancellationTokens
var asyncProcedure = SomeHTTPAction(cancellationToken).ConfigureAwait(false);
// Or If not simply do:
var asyncProcedure = SomeHTTPAction().ConfigureAwait(false);
If you want to use the result output later its gets trickier. But if it is truly fire and forget the above should work
A Cancellation token allows interrupts and canceling procedures. If you are using Cancellation token you will need to use it everywhere from the retrieval straight through to the calling method (Turtles all the way down).
I used ConfigureAwait(false) to prevent deadlocks. Here for more information
EDIT
See the second answer that uses 'Task.Factory.StartNew' I gave this answer some time ago. At the time I didn't realise that the way I did it at the time doesn't ensure completion.
If you need to use async in your function you can also use a discard variable and don't use await. This is also usefull if you have multiple async function calls but you don't need to wait for all of them.
public async function(){
var tmp = await asyncfunction();
...
_ = _httpClient.PutAsync(url, content);
...
}
As Amadan told in the comment that, you need to remove async from your function. then it will stop giving you the warning.
// This method has to be async
public Response SomeHTTPAction()
{
// Some logic...
// ...
// Send an Email but don't care if it successfully sent.
Task.Factory.StartNew(() => _emailService.SendEmailAsync());
return MyRespond();
}
and Task.Factory.StartNew(() => _emailService.SendEmailAsync()); will indeed work on a new thread.
It all depends on what your Async method accepts. Normally it will accept a "special" class that also holds an event. You can subscribe your callback method to that event and pass it along with the method. When it's finished, your callback method will be called.
An example of this (for sockets) would be:
public void CreateSocket()
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs sockAsync = new SocketAsyncEventArgs();
sockAsync.Completed += SockAsync_Completed;
s.ConnectAsync(sockAsync);
}
private void SockAsync_Completed(object sender, SocketAsyncEventArgs e)
{
//Do stuff with your callback object.
}
It all depends on what the method you are trying to call can accept. I would look at the documentation for more help on that specifically.
I am curious why this hasn't been suggested.
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
//what ever code here...e.g.
DoSomething();
UpdateSomething();
}).Start();
It just fires off a separate thread.

Asynchronous message processing with async/await, RX and LINQ

I'm using Reactive Extensions in combination with async/await to simplify my socket protocol implementation. There's some actions that have to be performed when specific message arrives (e.g. send 'pong' to each 'ping' -message) and there's also some method's where we have to wait for some specific responses asynchronously. The following example illustrates this:
private Subject<string> MessageReceived = new Subject<string>();
//this method gets called every time a message is received from socket
internal void OnReceiveMessage(string message)
{
MessageReceived.OnNext(message);
ProcessMessage(message);
}
public async Task<string> TestMethod()
{
var expectedMessage = MessageReceived.Where(x => x.EndsWith("D") && x.EndsWith("F")).FirstOrDefaultAsync();
await SendMessage("ABC");
//some code...
//if response we are waiting for comes before next row, we miss it
return await expectedMessage;
}
TestMethod() sends "ABC" to the socket and continues when for example "DEF" is received (there might be some other messages before that).
This works almost, but there's a race condition. It seems that this code won't listen for messages until return await expectedMessage; And this is a problem, since sometimes the message arrives before that.
FirstOrDefaultAsync won't work here nicely: It doesn't subscribe until the await line, which leaves you with a race condition (as you point out). Here's how you can replace it:
var expectedMessage = MessageReceived
.Where(x => x.EndsWith("D") && x.EndsWith("F"))
.Take(1)
.Replay(1)
.RefCount();
using (var dummySubscription = expectedMessage.Subscribe(i => {}))
{
await SendMessage("ABC");
//Some code... goes here.
return await expectedMessage;
}
.Replay(1) makes sure that a new subscription gets the most recent entry, assuming one exists. It only works though if there's a subscriber listening, hence dummySubscription.

Implementing callback mechanism as async/await pattern in C#

How to transform the following callback-driven code to async/await pattern PROPERLY:
public class DeviceWrapper
{
// external device which provides real time stream of data
private InternalDevice device = new InternalDevice();
private List<int> accumulationBuffer = new List<int>();
public void StartReceiving()
{
// the following callback invocations might by synchronized by main
// UI message pump, particular window message pump
// or some other way
device.Synchronization = Synchronization.UI;
device.DataAvailable += DataAvailableHandler;
device.ReceivingStoppedOrErrorOccured += StopHandler;
device.Start();
}
private void DataAvailableHandler(object sender, DataEventArgs e)
{
// Filter data from e.Data and accumulate to accumulationBuffer field.
// If certail condition is met, signal pending task (if there is any)
//as complete return to the awaiting caller accumulationBuffer or perhaps temporary buffer created from accumulationBuffer
// in order to make it available to the caller.
// Handle also requested cancellation.
}
public Task<byte[]> GetData(CancellationToken token)
{
// create task returning data filtered and accumulated in DataAvailableHandler
}
}
// usage:
async void Test()
{
DeviceWrapper w = new DeviceWrapper();
w.StartReceiving();
while(true)
{
byte[] filteredData = await w.GetData(CancellationToken.Null);
Use(filteredData);
}
}
I have sought inspiration to solve this by reading .NET StreamReader class source, but it made me even more confused.
Thank you experts for any advice!
You're looking for TaskCompletionSource<byte[]>. This is an approximation of what it would look like:
public Task<byte[]> GetData(CancellationToken token)
{
cancellationToken.ThrowIfCancellationRequested;
var tcs = new TaskCompletionSource<byte[]>();
DataEventHandler dataHandler = null;
dataHandler = (o, e) =>
{
device.DataAvailable -= dataHandler;
tcs.SetResult(e.Data);
}
StopEventHandler stopHandler = null;
stopHandler = (os, se) =>
{
device.ReceivingStoppedOrErrorOccured -= stopHandler;
// Assuming stop handler has some sort of error property.
tcs.SetException(se.Exception);
}
device.DataAvailable += dataHandler;
device.ReceivingStoppedOrErrorOccured += stopHandler;
device.Start();
return tcs.Task;
}
If you use your async await properly your code would be much easier:
First of all:
If you want to call an async function you should be async yourself
every async function returns Task instead of void or Task<TResult> instead of TResult
There is one exception: the async event handler may return void
After you call an async function you can do other things until you need the answer. But you don't have to do other things.
Once you need the answer await for the Task, the result is the TResult.
Now implementing your example. There are several methods to solve this, but I think this typically is a producer - consumer pattern: we have an object that produces things in a tempo independant from another object that consumes them.
You can create this yourself, using semaphores to signal new data, but .NET already has something for this:
System.Threading.Tasks.DataFlow.BufferBlock.
You'll need to download a microsoft nuget package. See the remarks in MSDN description of BufferBlock.
A BufferBlock is something you send objects of type T to, while another task waits for objects of type T to arrive. Fully supports async / await.
Sender side:
The bufferblock implements ITargetBlock<T> where T is the type it sends.
You can send items of type T to any ITargetBlock
Consider making the sender a separate object with the ITargetBlock<T> as property.
Whenever it has data to distribute: Post it, or SendAsync if you want to use async / await. See later
Consumer side:
BufferBlock<T> implements als ISourceBlock<T>
The consumer gets the ISourceBlock where the sender sends his objects to, in this case the BufferBlock that the sender uses.
When started the consumer waits for data to arrive using Receive or ReceiveAsync.
Ok, lets put it all together:
public class DeviceWrapper
{
// external device which provides real time stream of data
private InternalDevice device = new InternalDevice();
// internal buffer replaced by the bufferBlock
BufferBlock<byte> bufferBlock = new BufferBlock<byte>()
public void StartReceiving() {...}
private async void DataAvailableHandler(object sender, DataEventArgs e)
{
// get the input and convert it to a byte
// post the byte to the buffer block asynchronously
byte byteToSend = ...
await this.bufferBlock.SendAsync(byteToSend);
}
public async Task<IEnumerable<byte>> GetData(CancellationToken token)
{
List<byte> receivedBytes = new List<byte>()
while (await this.BufferBlock.OutputAvailableAsync(token))
{ // a byte is available
byte b = await this.bufferBlock.ReceiveAsync(token);
receivedBytes.Add(b);
if (receivedBytes.Count > ...)
{
return receivedBytes;
}
// else: not enough bytes received yet, wait for more
}
}
}
async Task Test(CancellationToken token)
{
DeviceWrapper w = new DeviceWrapper();
w.StartReceiving();
while(NoStopRequested)
{
token.ThrowIfCancellationrequested();
var filteredData = await w.GetData(token);
Use(filteredData);
}
}
There is a lot more to tell with BufferBlocks, especially on how to stop them neatly if no data is available anymore MSDN has several examples about this.
See the chapter about DataFlow in parallel library
https://msdn.microsoft.com/en-us/library/hh228603(v=vs.110).aspx

Wait for another method to invoke and then continue with result

I am trying to invoke a method from another .dll file .
It is sending a message through the VPN then Return the RecievedMessage from another computer.
As you now it takes time to sending and receiving message and VpnObject just send message and I should wait for listener to invoke the RecievedMessage.
This method is like this!
public string RecievedMessage()
{
string Recieved ;
// Some VPN Code and then return the result;
return Recieved;
}
public string SendAndRecieveMessage(string MessageToSend)
{
string RecievedAnswer = string.Empty;
// Now Sending Message through the VPN
VpnObject.SendMessage(MessageToSend);
//Then want to Recieve the answer and return the answer here .
return RecievedAnswer;
}
I'm just thinking how can wait for RecievedMessage to invoke then return the result .
You know it is simple to use a variable and assign it value and check for while but it reduced the performance dramatically .
Is there anyway to continue from SendAndRecieveMessage just when RecievedMessage invoked ? (I think it is something with async and await but don't know how!)
Edit :VpnObject is just a sender and receiver through the vpn . it contains a simple socket send and a listener that invoke a method(RecievedMessage) when new message received .
Whether or not you have an alternative to polling depends on whether the library you are using provides any events or callbacks that will tell you when the request has completed.
Either way, the standard approach to exposing the deferred result of an asynchronous operation is to use a Task. Your method signature would look like this:
public Task<string> SendAndRecieveMessage(string MessageToSend)
Now, how you actually implement the method depends on what API VpnObject exposes. TaskCompletionSource is very useful for this kind of thing.
If VpnObject has an event that fires when the request completes:
public Task<string> SendAndReceiveMessage(string messageToSend)
{
var tcs = new TaskCompletionSource<string>();
...
VpnObject.OnMessageReceived += (s, e) => tcs.SetResult(e.Message);
...
return tcs.Task;
}
If VpnObject can accept a callback that it will invoke when the request completes:
public Task<string> SendAndReceiveMessage(string messageToSend)
{
var tcs = new TaskCompletionSource<string>();
...
VpnObject.OnMessageReceived(message => tcs.SetResult(message));
...
return tcs.Task;
}
If VpnObject doesn't support any of this, you can fall back to polling:
public async Task<string> SendAndReceiveMessage(string messageToSend)
{
var tcs = new TaskCompletionSource<string>();
...
while(!VpnObject.IsMessageReceived)
await Task.Delay(500); // Adjust to a reasonable polling interval
...
return VpnObject.Message;
}
You know it is simple to use a variable and assign it value and check for while but it reduced the performance dramatically .
A spin while loop is definitely not the way to implement this. Even with a sleep, it's clunky, and C# has multiple ways to solve this problem.
It's not entirely clear how your VPN Send and Receive method works, but the idea for solving this is to either use a callback approach, or as you noted, use C# async framework.
Without more details on the VPN Object, I'll just have to have some stub methods. The idea is to create a Task that returns the string, mark it as an async task, then await for it to complete. In your case, the task is receiving the VPN response string.
Something like this.
public Task<string> ReceivedMessage()
{
//get the response from the VPN Object.
string Received = VpnObject.GetResponse();
var ts = new TaskCompletionSource<string>();
ts.SetResult(Received);
// Some VPN Code and then return the result;
return ts.Task;
}
public async Task<string> SendAndReceiveMessageAsync(string MessageToSend)
{
string result = string.Empty;
// Now Sending Message through the VPN
VpnObject.SendMessage(MessageToSend);
result = await ReceivedMessage();
return result;
}

New async/await constructs in .net cause bumps

I am trying to take advantage of new async/await constructs while working UdpClient. It has several async methods that work nice with async/await.
The problem occurs when I need to connect current request with appropriate response. Since responses from UdpClient are not ordered, it is possible to mess up whole logic by using:
var response = await udpClient.ReceiveAsync();
// We might receive here a response
// that belongs to other request
Full source below:
// Here I am trying to provide unified message sending logic
private async Task<Response> SendMessageAsync(IPEndPoint destination, Message message)
{
var stream = new MemoryStream();
formatter.Serialize(stream, message);
var buffer = stream.GetBuffer();
// Here I am sending message
var numBytes = await udp.SendAsync(buffer, buffer.Length, destination);
// Now I need to wait for response
// but I can't just use:
// var response = await udp.ReceiveAsync();
// Because current receive operation might catch data that is subject to
// another send message operation which has started some time before the
// current one.
// So how the question how is it possible to implement the following construct:
// return await GetResponse(message.ConversationID);
}
You need to match it up yourself after reading the response.
This is a fundamental limitation of UDP, not a limitation of async/await.
If you need to keep your messages in order, I recommend TCP. TCP was designed for that.

Categories

Resources