We're writing a threaded service using topshelf / windsor / masstransit to pick up messages off of MSMQ and then send an e-mail off with PDF attachment.
Every now and again the SmtpClient.Send() method throws this error message:
An asynchronous call is already in progress. It must be completed or canceled before you can call this method.
I've got the SmtpClient set up as .LifeStyle.Transient in Windsor, so my understanding is that each thread should get its own instance?
Any idea how I can around this, short of locking that part of the code. Which would kind of defeat the purpose of the threads.
Thanks in advance
Transient shouldn't just create a new instance per thread, but a new instance for every request.
I'd try to confirm that you're truly getting a new instance of SmtpClient - make sure you're not sticking it in a static field or otherwise somehow ending up with the same reference. You could try spitting the result from GetHashCode() into the Console each time you send an email to see if they're all using the same object.
Failing that, my only suggestion is to try and strip it down to a really simple example - if you don't find the issue in doing this, you can post the code here and someone might be able to help.
Related
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 have a c# application that the client uses wcf to talk to the server. In the background every X seconds the client calls a Ping method to the server (through WCF). The following error has reproduced a couple of times (for different method calls):
System.ServiceModel.ProtocolException: A reply message was received for operation 'MyMethodToServer' with action 'http://tempuri.org/IMyInterface/PingServerResponse'. However, your client code requires action 'http://tempuri.org/IMyInterface/MyMethodToServerResponse'.
MyMethodToServer is not consistent and it falls on different methods.
How can this happen that a request receives a different response?
I think you have a pretty mess problem with async communication, main suggestion (as your question isn't clear very well), is try to identify every request, catch the calls and waiting for them, do asyncronic communication and getting a several work with threading.
As you present it, is a typical architecture problem.
If you present more code, can I suggest some code fixing in my answer and I'll be glad to update my answer.
If this occurs randomly and not you consistently, you might be running in a load-balanced setup, and deployed an update to only one of the servers?
Wild guess: your client uses same connection to do two requests in parallel. So what happens is:
Thread 1 sends request ARequest
Thread 2 sends request BRequest
Server sends reply BReply
Thread 1 receives reply BReply while expecting AReply
If you have request logs on the server, it'll be easy to confirm - you'll likely see two requests coming with short delay from the client host experiencing the issue
I think MaxConcurrentCall and ConcurrencyMode may be relevant here (although I did not touch WCF for a long while)
I am writing an API using ASP.NET and I have some potentially long running code from the different end points. The system uses CQRS and Event Sourcing. A Command comes into to an end point and is then published as an event using MediatR. However the Handlers are potentially long running. Since some of the Requests coming in might be sent to multiple Handlers. This process could take longer than the 12s that AWS allows before returning an Error code.
Is there a way to return a response back to the caller to say that the event has been created while still contining with the process? That is to say fire off a separate task that performs the long running piece of code, that also catches and logs errors. Then return a value back to the user saying the Event has been successfully created?
I believe that ASP.NET spins up a new instance each time a call is made, will the old instance die one a value is returned, killing the task?
I could be wrong with a number of points here, this is my knowledge gleaned from the internet but I could have missunderstood articles.
Thanks.
Yes, you should pass the long-running task off to a background process and return to the user. When the task is complete, notifiy the user with whatever mechanism is appropriate for your site.
But do not start a new thread, what you want is to have a background service running for this, and use that to manage your request.
If a new thread is running the long operation it will remain “open/live” until it finishes. Also you can configure the app pool to always be active.
There are a lot of frameworks to work with long running tasks like Hangfire.
And to keep the user updated with the status of the task you can use SignalR to push notifications to the UI
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.
Does anyone know of a way to create a listener for a proxy so that when the CommunicationState has changed I can invoke an action or a method?
An example, I want to update my WCF service for a code change. Since the application is in its early development code changes are very frequent. However, instead of annoying my employees with an email tell them that hey they need to restart their application. I would rather avoid them having to restart the app and having to send them an email. I would rather write a listener that looks at the communication state of a service and if it has changed to a faulted stated then attempt to reconnect.
Edit
Maybe some more context here.
InstanceContext context = new InstanceContext(this);
Subscriber = new SubscriptionService.MySubscriptionServiceClient(context);
Subscriber.Subscribe("");
So basically I want to know when the subscription service has stopped so that I can attempt to reconnect every 60 seconds or so. I tried looking for an event in the Subscriber service but I didn't see anything. Would I need to implement something on the service end?
Thanks
You can use the Faulted event available on the InnerChannel property of your generated client class. The State property of the client class is just a wrapper for InnerChannel.State, so this should work as you desire.
(For reference, you can also use the similarly named event on ChannelFactory<TChannel> if you are creating communication channels in code rather than using generated proxies.)