I've been running a C# http handler (ashx) to send mail for years. We believe the problem started when we switched to 4.5.1. We are getting the error:
"An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle..."
I was using:
public static void sendMessage(....
...
client.SendAsync(message);
After looking around for what was happening, the method was changed to:
public static async Task sendMessage(....
...
await client.SendMailAsync(message);
I'm assuming that we still get this error because not all the calls up the stack have the async operator. To do that, I'd have to make the entire handler, that does many other things, asynchronous which doesn't sound like a good idea just to send mail.
So, I have two questions:
Am I correct in that I'm not using async in every method that eventually calls sendMessage?
How do I send mail asynchronously now?
Since there were no more comments, I just started a new thread and sent the message synchronously. Seems to work fine, haven't had a problem since.
Related
I'm working on a C# Docker application, where I am creating a microservice in order to handle TCP socket communication. This works, but it seems to be very unstable (some packets pass, some not). I have added a log entry, which might explain something (it's about sending a message over a TCP socket):
Source code (shown on multiple lines, but it's a oneliner):
Debug.WriteLine(
$"T[{System.Threading.Thread.CurrentThread.ManagedThreadId}],
{DateTime.UtcNow}: Handle().
Trying to send [{Message}] to [{ConnectionName}]");
Results:
T[14], 12/14/2022 15:26:08: Handle(). Trying to send [abc] to [XL_Test]
T[19], 12/14/2022 15:26:32: Handle(). Trying to send [abc] to [XL_Test]
As you can see, apparently my application always uses another thread to handle the requests. So, I'm left with a very simple question: is multithreaded programming allowed when working with TCP sockets?
For your information: I have already worked with multithreaded applications on TCP sockets before, where one thread was used for regular checking the connection and another for sending the messages, but here I have one thread which regularly checks the connection, while for sending messages, always another thread gets opened.
Edit: I don't know if this is helpful, but the name of the thread, handling the message, is .Net ThreadPool Worker.
Edit2: this is the way this Send() method is called:
await _mediator.Send(command);
... where _mediator is an IMediator from the MediatR library.
The first comment refers to another StackOverflow post which is using locks, but while trying this, I got a compilation error:
object lockobject = new object();
lock(lockobject)
{
await _mediator.Send(command);
}
The compiler message is CS1996: Cannot await in the body of a lock statement. (Pardon my ignorance, but I'm very new at this)
How can I send a message (or publish an event) when a message runs out of retries and moves to the error queue?
When a request comes into my system, I create a Saga to track it. The Saga sends commands to Handlers to do async work. If the handler fails, I want to both move that command to the error queue (the default behavior) and send a message to the Saga to alert the client that originally requested the work.
I have tried customizing the recoverability behavior to use the Saga as the error queue, which sends the command back but does not get it into the error queue:
recoverability.CustomPolicy((config, context) =>
{
// invocation of default recoverability policy
var action = DefaultRecoverabilityPolicy.Invoke(config, context);
if (action is MoveToError)
{
return RecoverabilityAction.MoveToError("SagaEndpoint");
}
return action;
});
Another thing I tried was using a Behavior to hook into the Pipeline, but there does not seem to be a a way to override the "move to error queue" step. I can create an IIncomingLogicalMessageContext and try/catch around the await next();, but that triggers for each retry instead of just the final one. I also tried an IOutgoingLogicalMessageContext, but that does not get invoked when a message moves to the error queue. If I missed something, that could be a solution.
I also know I can use a timeout in the Saga to guess when the Handler fails. But I would rather not wait for a timeout if the failure is quick or risk timing out if the work takes longer than expected.
I found this older question that sounds like it's asking the same thing, but the answer is incomplete and uses the older EventHandler Notifications instead of the newer Task-based Notifications. If there is a way to access an IMessageSession or IEndpointInstance from the Notification callback, I think that would work for me as well.
There's not an "easy" way to do that because at the moment when recoverability is happening, any transaction related to the incoming message (this is different for each transport) is in doubt, so you can't really do anything else within the scope of what's going on right at that moment.
Once you start your endpoint, you can cast the IEndpointInstance to an IMessageSession (same thing without things like the Stop method) and then assign that to a place where your "error queue notifier" will be able to find it. Then any operation you do with the IMessageSession will basically be a separate context, disconnected from the processing of the incoming message.
Just understand that if the message is failing processing because of an underlying problem with the queue, that's not going to report correctly. That's why most people would be doing some sort of call to a reporting/diagnostics service in those callbacks.
I'm receiving from a queue using IQueueClient.RegisterMessageHandler(), and in the receiving method I'm then starting a Hangfire task. But in the Hangfire task, all calls to IQueueClient.CompleteAsync() to mark the message as consumed (because I'm using ReceiveMode.PeekLock mode) fail.
I suspect it's because the Hangfire task re-creates the IQueueClient, that it may be because the call to CompleteAsync() is from a different instance of IQueueClient? Or is something else possibly going wrong? I'm passing Message.SystemProperties.LockToken into the Hangfire task which is what is then being used by CompleteAsync.
I suspect it's because the Hangfire task re-creates the IQueueClient, that it may be because the call to CompleteAsync() is from a different instance of IQueueClient?
That's correct. LockToken is not enough to complete the message. You have to use the same client used to receive the message in order to complete it.
I'm trying to implement a client-server socket system based on this MSDN article and I have it working. If I do this it works fine when the server is returning a string immediately.
client.send();
client.receive();
The problem is if my send method requests something that takes the server a few minutes to process, such as creating a PDF version of a file, the receive call executes straight after and receives nothing (because the server hasn't sent anything as it's still processing the PDF).
How can I make the client wait for a certain period of time before executing the receive method so that it's called once the server has finished processing and has sent the file?
This seems to be the difference between a blocking and non-blocking receive call. A blocking receive call would wait until it actually had something to receive or it would timeout. A non-blocking receive call would return right away whether data is present or not. I don't know what call this is but I know C# has both types of calls.
The link you gave was to a asynchronous socket example which is generally different than what you are trying to do. What you are trying to do is more similar to a synchronous style.
Asynchronous in terms of sockets usually means you would register a function to be called when data was received. Synchronous means to poll (explicitly ask for data) in either a blocking or non-blocking manner.
EDIT:
You would send your data and set a class variable saying you have sent something and are expecting to receive something. Then wait for that variable to be cleared saying you've received something.
sent = 1
client.send()
while(sent);
Then in your receive callback when you actually get something you would set that variable.
/* receive data and process */
sent = 0;
Use async and wait. The function will get called after the call returns.
http://msdn.microsoft.com/en-us/library/vstudio/hh156513.aspx
I read this on MSDN documentation, which seems to imply that I will still need to wait after calling the SendAsync method in my code, which is pasted below. Is this right? If it is, then I might as well just use the synchronous method of Send rather than SendAsync. My goal was to go to the next email message in my loop and send it without waiting for the previous one to be sent, which would allow me to handle the emailMessages collection more quickly as compared to using Send method. But it doesn't seem true.
After calling SendAsync, you must wait for the e-mail transmission to complete before attempting to send another e-mail message using Send or SendAsync.
I am using C# and .Net framework 4.5. In my code, I am trying to send multiple emails from within a loop as in code below using SendAsync method.
List<EmailMessage> emailMessages = DAL.GetEmailsToBeSent();
SmtpClient client = new SmtpClient();
foreach(EmailMessage emailMessage in emailMessages)
{
//create a message object from emailMessage object and then send it asynchronously
client.SendAsync(message);
//client.Send(message);
}
The advantage of the async method over the non-async alternative is that you don't need to block the current thread. This is particularly helpful in UI environments where you don't want to be blocking the UI thread, and also prevents the need for blocking a thread pool thread.
If you're just going to do a blocking wait on the results, it has no advantage over the non-async alternative.