Razor Pages EF Core - Await Timer inside OnPostAsync

MaxPowers1982 81 Reputation points
2022-08-01T19:06:36.01+00:00

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.

My app is available here

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);  
        }  
Entity Framework Core
Entity Framework Core
A lightweight, extensible, open-source, and cross-platform version of the Entity Framework data access technology.
697 questions
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,161 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. AgaveJoe 26,201 Reputation points
    2022-08-01T19:53:06.457+00:00

    ASP.NET Core has the hosted service feature for running background tasks.

    Background tasks with hosted services in ASP.NET Core


  2. 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 API

    You 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.

    Overview of ASP.NET Core SignalR

    0 comments No comments