Reputation: 7136
In my application, I am using ActionBlock
from Dataflow library, to send out email alerts using SmtpClient.SendAsync()
method, which does not block calling thread.(ActionBlock
is getting it's data from BufferBlock
, and blocks are tied together using bufferBlock.LinkTo(actionBlock)
). However, this method will throw InvalidOperationException
if another .SendAsync()
call is in progress.
According to MSDN documentation, there is public event SendCompletedEventHandler SendCompleted
that is raised when send operation completes.
How do I make sure, that race between threads (or Tasks
) spawned by ActionBlock
will not cause InvalidOperationException
to be thrown ?
One thought, I have so far, is to add to my class(that sends out emails) private lock around SendAsync()
call and private function that will be assigned to SendCompleted
event. When the thread reaches SendAsync()
it obtains the lock, and when the event is raised, private function unlocks the lock, allowing other threads to obtain lock, and progress.
Upvotes: 1
Views: 1096
Reputation: 116518
You should simply use SendMailAsync
instead. It will start with calling SendAsync
and complete when SendCompleted
is raised.
To make sure only 1 message is sent at each moment you can use SemaphoreSlim
set to 1. It's basically an AsyncLock
.
However, this will limit you parallelism as you can only perform one operation at a time. You can simply use many different clients. If not one per call then use some resource pool and then you can have concurrency but still keep each client thread-safe.
var client = _smtpClientPool.Get();
try
{
await client.SendMailAsync(...)
}
finally
{
_smtpClientPool.Put(client);
}
Upvotes: 2
Reputation: 171168
Create one SmtpClient
for each send operation. That way there is no need to synchronize anything. Simply enclose it in using
to clean up.
Upvotes: 4