ASP.NET Core - Send email without wait - c#

I have an APS.NET Core 5 Web API:
I have this:
await _mailSender.SendMailAsync(entity.Id);
But, I don't want to wait for the email sender to return Ok for client.
I want to continue code execution and send email in background.
How can I do this?

I did this using HangFire to queue the email to send.
//send email
BackgroundJob.Enqueue(() => _mailSender.SendMailAsync(entity.Id));

By using Task class, you can execute a single operation asynchronously.
Try this code:
System.Threading.Tasks.Task.Run(() => _mailSender.SendMailAsync(entity.Id).Result;
The work performed by a Task object typically executes asynchronously on a thread pool thread rather than synchronously on the main application thread.

Related

Using Threads , to send response and continue with another task in Web application in C#

I am new to C# and working on a Web Service project. I am having a scenario as below :
1. From web i will get the parameters
2. With the request i construct and start a set of test cases ,
this is time taking and user may not wait for almost 40 mins to an hour.
Instead Can i send the response back to the browser to say that the execution is initiated ? and as a background thread will run the next task.
Any idea or info will be of great help. I will have to use C# and ASP.net as my api's for UCMA are in c#. Basically i want to do something like:
var threads = new List<Thread>
{
new Thread(() => sendResponse(fileLogger,execution)),// expecting this to send the response back to browser.
new Thread(() => goAheadWithlongerTimetakingTask(fileLogger))
};
threads.ForEach(t => t.Start());
threads.ForEach(t => t.Join());
Once the second thread is done i would kill both the threads in Finally.
If this is not a better solution, can you suggest a better one ?
Don't mess with threads in ASP.NET.
Instead, make the initial request schedule a task with a tool like HangFire or Quartz.NET. Then, have a Windows Service running that knows to watch for those scheduled tasks and execute them. Allow the web client (browser) to poll (or, if you want to get fancy, use something like SignalR) to check the status of the task, and when it's done retrieve the result.
Scott Hanselman has a great post about different strategies you can use for running background tasks in ASP.NET here. I recommended the Hangfire/Quartz.NET strategy because the 40-minutes-to-1-hour timespan you're talking about is easily enough time for ASP.NET to get shut down while you're trying to execute the background task, so you'll definitely want to offload that to a separate app.

Triggering an async operation in from mvc controller

Here is my scenario.
I want to create a web endpoint that will kick off a service that may be long-running, perhaps 20-30 minutes. I'd like to return an HttpResponseResult immediately and trigger the service to run asynchronously, instead of having to wait for the service to complete before returning a response to client.
What is the easiest way to go about doing this? I don't need to return any sort of result from the service, just trigger it.
Just run a task using Task.Run(() => <trigger service call> ) and ignore the return value. The only down side of this is that it will consume a thread from the thread pool. If the service has an asynchronous version of the operation you are calling you can use a TaskCompletionSource
SignalR will be my choice to do this kind of behavior. Tutorial is here.
Basically, a client invokes a server method/action and is 'done' (you can continue and do whatever y you want in the client side). Once the server is done it pushes data/notification to client via RPC.
On the server side you can execute the code anyway you like, synchronously or async.

SendEmailAsync benefits doubtful

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.

Passing exception or message from thread/task to main thread

We are dealing with processing and uploading of large files in windows service (.net 4.0). Process and upoload steps can take minutes to complete. Admin has the ability to mark job as cancelled, directly in database but to clear in memory queue it requires service restart. Goal is to abandon that job and pick next job in queue without service restart. Here's what I want to do:
In main entry point, start two tasks:
Task processTask = Task.Factory.StartNew(ProcessJob);
Task monitorTask = Task.Factory.StartNew(MonitorDB);
ProcessJob would call multiple long running steps like ProcessFile, UploadFile. We are checking for job status between the steps but job may be stuck in one of these long running steps.
If monitorTask detects job status change in DB, it should communicate that to main thread (through exception or message), so that main thread can quit, removing itself from the processing queue and allow next job in queue to start. Without Wait cannot get to exception but cannot wait because need to run these tasks in parallel.
At this time we are not concerned with the fact that some synch step in ProcessJob may still be going on and it may eventually complete. We would handle that in code.
So far in all of my applications, I have used Task.ContinueWith for success and failure, but never had to communicate back to main thread.
You could communicate between the monitor thread and the main thread through a BlockingCollection<T>.
Here's a simple example I wrote.
BlockingCollection<string> queue =
new BlockingCollection<string>();
// monitor thread.
Task.Factory.StartNew(() =>
{
while (true)
{
Thread.Sleep(1000);
queue.Add("event occured.");
}
});
// main thread.
while (true)
{
// blocks when no messages are in queue.
string message = queue.Take();
// kill process thread here.
}
You can use a CancellationToken for this. If you look at the Task class, there is an overload where you can pass in a CancellationToken. Store a reference to this token in your service and simply have your upload/process routine periodically check if the token has been cancelled like so:
if (yourToken.IsCancellationRequested)
break;

checking if a thread is alive

for a task, potentially taking too long to complete, I'd like a mechanism
to start the task
return back to user interface (its a web page)
periodically/randomly check if the task is complete
cancel the executing task when user wishes so
get notified when the task completes / fails
what are the possible solutions?
Threads?
Start a thread, save its ManagedThreadId, (can you get a thread by its id)
write a windows service,
send the request to service via shared objects/files/db?
keep interacting with the service the same way (objects/files/db,etc)
Services?
Host a WCF Service in a Windows Service that will perform the background tasks by adding/reading from a queue which can be maintained either using MSMQ or in a database.
When you add an item for processing; you should get a task id. You should be able to then log the completion/failed/cancel status of the task in db against the task id.
You can have following methods in your WCF contract
int ProcessItem(ItemDetails details); // returns task id
bool CancelTask(int taskID); // returns true if successfully cancelled; false otherwise
TaskStatus GetTaskStatus(int taskID); // returns Cancelled, Waiting, Failed or Completed
You can do that in single process
Have a look at the Task Paralell Library and / or TPL DataFlow
http://msdn.microsoft.com/en-us/library/dd460717.aspx
http://go.microsoft.com/fwlink/?LinkId=205053

Categories

Resources