I have a web API over net core 3.0 and my API is using a mail DLL where I do some operations.
Web API controller:
_mailService.SendEmail();
Mail DLL:
public void SendEmail()
{
Console.Writeline("Registering at database");
RegisterAtDatabase(); //Do some stuff at database
SendMailToUser(); //Send mail to user. His operation takes about 1 minute
Console.Writeline("End mail proccess");
}
private void SendMailToUser()
{
Console.Writeline("Creating and sending mail");
//Here some stuff to send the mail. It takes about 1 minute
Console.Writeline("Mail sended");
}
I want to call _mailService.SendEmail() and not wait for the whole process. I want to write at the database and not wait for email sending process. So console output should be....
Registering at database
Creating and sending mail
End mail proccess
//After 1 minute
Mail sended
Is that possible using Task Async and await in some way?
I wanna return the control to the API while the email is sending.
Thanks
Is that possible using Task Async and await in some way?
No, that's not what async is for.
The proper solution is to write the work (e.g., "send this message to this email address") to a reliable queue (e.g., Azure Queue / Amazon SQS / etc), and then have a separate background process read and process that queue (e.g., ASP.NET Core background service / Azure Function / Amazon Lambda / etc).
You can use background Task queue for this kind of works and run them in the background.
full info at Microsoft Documents Background tasks with hosted services in ASP.NET Core
Related
I am working on a microservice based application in azure. My requirement is I had a service bus and I need to consume that service bus message in web api. Currently I implemented through azure functions, but my company asked to use api. Is it possible?, If possible please show me how to do it
You can create Background service to listen to message from service bus queue.
Below are few key points that needs to be noted:
Background task that runs on a timer.
Hosted service that activates a scoped service. The scoped service can use dependency injection (DI).
Queued background tasks that run sequentially.
App Settings:
1. {
2. "AppSettings": {
3. "QueueConnectionString": "<replace your RootManageSharedAccessKey here>",
4. "QueueName": "order-queue"
5. }
6. }
You can refer to c-sharpcorner blog for step by step process.
There is a simple way to get a simple message.
ServiceBusClient client = new ServiceBusClient("Endpoint=sb://yourservicesbusnamespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Your_SharedAccess");
var receiver = client.CreateReceiver("Your Queue");
var message = await receiver.ReceiveMessagesAsync(1);
string ascii = Encoding.ASCII.GetString(message.FirstOrDefault().Body);
Console.WriteLine("Received Single Message: " + ascii);
await receiver.CompleteMessageAsync(message.FirstOrDefault());
I did some modifications from this post
https://ciaranodonnell.dev/posts/receiving-from-azure-servicebus/
Consider this extremely simple .NET Core 3.1 (and .NET 5) application with no special config or hosted services:
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
internal class Program
{
public static async Task Main(string[] args)
{
var builder = Host.CreateDefaultBuilder(args);
builder.UseWindowsService();
var host = builder.Build();
var fireAndforget = Task.Run(async () => await host.RunAsync());
await Task.Delay(5000);
await host.StopAsync();
await Task.Delay(5000);
await host.RunAsync();
}
The first Run (sent as a background fire and forget task only for the purpose of this test) and Stop complete successfully. Upon calling Run a second time, I receive this exception:
System.AggregateException : 'Object name: 'EventLogInternal'.Cannot access a disposed object. Object name: 'EventLogInternal'.)'
If I do the same but using StartAsync instead of RunAsync (this time no need for a fireAndForget), I receive a System.OperationCanceledException upon called StartAsync the second time.
Am I right to deduce that .NET Generic Host aren't meant to be stopped and restarted?
Why do I need this?
My goal is to have a single application running as a Windows Service that would host two different .NET Generic Host. This is based on recommendation from here in order to have separate configuration and dependency injection rules and message queues.
One would stay active for all application lifetime (until the service is stopped in the Windows services) and would serve as a entry point to receive message events that would start/stop the other one which would be the main processing host with full services. This way the main services could be in "idle" state until they receive a message triggering their process, and another message could return them to idle state.
The host returned by CreateDefaultBuilder(...).Build() is meant to represent the whole application. From docs:
The main reason for including all of the app's interdependent resources in one object is lifetime management: control over app startup and graceful shutdown.
The default builder registers many services in singleton scope and when the host is stopped all of these services are disposed or switched to some "stopped" state. For example before calling StopAsync you can resolve IHostApplicationLifetime:
var appLifetime = host.Services.GetService<IHostApplicationLifetime>();
It has cancellation tokens representing application states. When you call StartAsync or RunAsync after stopping, all tokens still have IsCancellationRequested set to true. That's why the OperactionCancelledException is thrown in Host.StartAsync.
You can list other services during configuration:
For me it sounds like you just need some background jobs to process messages but I've never used NServiceBus so I don't know how it will work with something like Hangfire. You can also implement IHostedService and use it in the generic host builder.
I'm doing something like:
do
{
using IHost host = BuildHost();
await host.RunAsync();
} while (MainService.Restart);
with MainService constructor:
public MainService(IHostApplicationLifetime HostApplicationLifetime)
MainService.Restart is a static bool set by the MainService itself in response to some event which also calls HostApplicationLifetime.StopApplication().
I have a server-side streaming gRPC service that may have messages coming in very rapidly. A nice to have client feature would be to know there are more updates already queued by the time this onNext execution is ready to display in the UI, as I would simply display the next one instead.
StreamObserver< Info > streamObserver = new StreamObserver< info >( )
{
#Override
public void onNext( Info info )
{
doStuffForALittleWhile();
if( !someHasNextFunction() )
render();
}
}
Is there some has next function or method of detection I'm unaware of?
There's no API to determine if additional messages have been received, but not yet delivered to the application.
The client-side stub API (e.g., StreamObserver) is implemented using the more advanced ClientCall/ClientCall.Listener API. It does not provide any received-but-not-delivered hint.
Internally, gRPC processes messages lazily. gRPC waits until the application is ready for more messages (typically by returning from StreamObserver.onNext()) to try to decode another message. If it decodes another message then it will immediately begin delivering that message.
One way would be to have a small, buffer with messages from onNext. That would let you should the current message, and then check to see if another has arrived in the mean time.
I have to solve the following problem. We got an ASMX web service which is requested every two minutes. If this service is not requested for ten minutes an email should be sent. We want to realize this by using the scheduled tasks. We imagined it like this
1. Creating a scheduled task which will send an email every ten minutes
2. If the service is requested the execution time for the task will be set to ten minutes from now and so the execution time cannot be reached
- If the service is not requested the execution time will be reached and the email is sent
Is there a way to solve this in ASP.NET or are there maybe better solutions?
Thanks for any response.
You may want to take a look at the Revalee open source project.
You can use it to schedule web callbacks at specific times. In your case, you could schedule a web callback (10 minutes in the future) every time your web service is used. When your web service receives the callback, it can determine whether or not the service has been used recently. If the web service has been active, then the callback is ignored; if the web service has been inactive, then it can send out an email message.
For example using Revalee, you might:
Register a future (10 minutes from now) callback when your application launches.
private DateTimeOffet? lastActive = null;
private void ScheduleTenMinuteCallback()
{
// Schedule your callback 10 minutes from now
DateTimeOffset callbackTime = DateTimeOffset.Now.AddMinutes(10.0);
// Your web service's Uri
Uri callbackUrl = new Uri("http://yourwebservice.com/ScheduledCallback/YourActivityMonitor");
// Register the callback request with the Revalee service
RevaleeRegistrar.ScheduleCallback(callbackTime, callbackUrl);
}
Anytime your web service is used, you register another callback and store the date & time that your service was active as a global value.
lastActive = DateTimeOffset.Now;
ScheduleTenMinuteCallback();
Finally, when the web schedule task activates and calls your application back, then you test the value of the global
private void YourActivityMonitor()
{
if (!lastActive.HasValue || lastActive.Value <= DateTimeOffset.Now.AddMinutes(-10.0))
{
// Send your "10 minutes has elapsed" email message
}
}
I hope this helps.
Disclaimer: I was one of the developers involved with the Revalee project. To be clear, however, Revalee is free, open source software. The source code is available on GitHub.
Currently i have a web application and a wins form application in my server. Basically, the web application will receive request from user and this request will be send to the wins form application to proceed (wins form need about 1 minute to complete a request).
Let say 2 users send a request at the same time via web application, I need to develop a queue job to maintain the request in sequence.
1) User A make a request > request will be store into a queue job
2) User B make a request > request will be store into a queue job
3) The queue job will send the first request to the wins form. Once first request is complete, then will follow by the second request
So my question is, this queue job should be develop inside the web application? Or it should be develop in a stand alone wins form?
Any example code for create a queue job in ASP.NET?
Or anyone can suggest a better solution?
using System.Collections.Generic;
Queue<task> Q = new Queue<task>();
public void Proccess_Request(string info)
{
task t = new task();
t.INFO = info;
Q.Enqueue(task);
}
public void DoWork()
{
//
while (Q.Count > 0)
{
task t = Q.Dequeue();
//Process task t
}
}
public class task
{
public string INFO { get; set; }
// Whatever task properties you need
}
You will need to build the service that accepts form data and passes it to method Process_Request. You will also need to call method DoWork either once every x minutes, or have it listen for Process_Request to fire.
Or you can use MSMQ and do it that way. the ASP.NET site sends a message to the queue, the winforms app (or service) is bound to the queue so when messages come into the queue, it will pick it up, process it and let it be done until no more messages in the queue.
You can handle cross domain queue communication with MSMQ, for example.