ASP.NET Core has the hosted service feature for running background tasks.
Razor Pages EF Core - Await Timer inside OnPostAsync
I hope to use a timer to monitor the status of SQL Server Agent jobs inside of the Post action in my .NET 6 Razor Pages app. It is a requirement that the Post action await the completion of the job so the app can report the outcome to the user.
In my example so far, I cannot get the app to actually wait for the timer. It appears to just go straight to SaveChangesAsync() then to return RedirectToPage, without waiting for the timer to tick away. My intention with this example is to have the timer keep ticking forever (until I close the app of course), as it would wait for 3 seconds every 2 seconds. I have not been able to learn how to do this from my days of searching, reading and trail and error attempts.
public class CreateModel : PageModel
{
private readonly Buggy.Models.Scaffold.BuggyDBContext _context;
private static System.Timers.Timer aTimer;
public CreateModel(Buggy.Models.Scaffold.BuggyDBContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public AnotherTable AnotherTable { get; set; } = default!;
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid || _context.AnotherTables == null || AnotherTable == null)
{
return Page();
}
// Create a timer with a two second interval.
aTimer = new System.Timers.Timer(2000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = true;
aTimer.Enabled = true;
_context.AnotherTables.Add(AnotherTable);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
private async void OnTimedEvent(Object source, ElapsedEventArgs e)
{
await Task.Delay(3000);
string[] logMeTwice = {DateTime.Now.ToLongTimeString() };
await System.IO.File.AppendAllLinesAsync(@"\\rds2\toolkat\Log\log.txt", logMeTwice);
Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
e.SignalTime);
}
2 answers
Sort by: Most helpful
-
-
AgaveJoe 26,201 Reputation points
2022-08-01T21:11:27.077+00:00 That's not how I understood your original post. A hosted service runs until the web application closes.
My intention with this example is to have the timer keep ticking forever (until I close the app of course),
A typical solution is to store the processing state in a database by a unique identifier like a GUID. The job updates the database state using the GUID. A JavaScript timer application makes AJAX requests to check the state in the database using the same GUID. The Razor Page's job is to generates the GUID, kicks off the job, returns the GUID to the JavaScript app (browser).
JavaScript Timing Events
Fetch APIYou could also have the user refresh a page to check the state if you don't want to write a JavaScript application.
Why are recommending a background task over helping me debug the method I have attempted?
It is not possible for a Razor Page to return a response (redirect) and monitor a process using a timer. In the web world there is one request and one response. Either create a process with multiple request to check state on the server, like the recommendation above, or switch to web sockets (SignalR). A web socket is an open connection with the web server that allows the web server to send multiple messages to the client.