Asked  7 Months ago    Answers:  5   Viewed   110 times

I am working on a C# WPF project. I need to allow the user to create and add a scheduled task to the Windows Task Scheduler.

How could I go about doing this and what using directives and references do I need as I am not finding much when searching the Internet.

 Answers

18

You can use Task Scheduler Managed Wrapper:

using System;
using Microsoft.Win32.TaskScheduler;

class Program
{
   static void Main(string[] args)
   {
      // Get the service on the local machine
      using (TaskService ts = new TaskService())
      {
         // Create a new task definition and assign properties
         TaskDefinition td = ts.NewTask();
         td.RegistrationInfo.Description = "Does something";

         // Create a trigger that will fire the task at this time every other day
         td.Triggers.Add(new DailyTrigger { DaysInterval = 2 });

         // Create an action that will launch Notepad whenever the trigger fires
         td.Actions.Add(new ExecAction("notepad.exe", "c:\test.log", null));

         // Register the task in the root folder
         ts.RootFolder.RegisterTaskDefinition(@"Test", td);

         // Remove the task we just created
         ts.RootFolder.DeleteTask("Test");
      }
   }
}

Alternatively you can use native API or go for Quartz.NET. See this for details.

Tuesday, June 1, 2021
 
TheLovelySausage
answered 7 Months ago
13

There's no SQL Agent equivalent for SQL Azure today. You'd have to call your single-line statement from a background task. However, if you have a Web Role already, you can easily spawn a thread to handle this in your web role without having to create a Worker Role. I blogged about the concept here. To spawn a thread, you can either do it in the OnStart() event handler (where the Role instance is not yet added to the load balancer), or in the Run() method (where the Role instance has been added to the load balancer). Usually it's a good idea to do setup in the OnStart().

One caveat that might not be obvious, whether you execute this call in its own worker role or in a background thread of an existing Web Role: If you scale your Role to, say, two instances, you need to ensure that the daily call only occurs from one of the instances (otherwise you could end up with either duplicates, or a possibly-costly operation being performed multiple times). There are a few techniques you can use to avoid this, such as a table row-lock or an Azure Storage blob lease. With the former, you can use that row to store the timestamp of the last time the operation was executed. If you acquire the lock, you can check to see if the operation occurred within a set time window (maybe an hour?) to decide whether one of the other instances already executed it. If you fail to acquire the lock, you can assume another instance has the lock and is executing the command. There are other techniques - this is just one idea.

Thursday, August 5, 2021
 
Philippe
answered 4 Months ago
69

Is the scheduled task folder has any check for the session or anything? I mean is the scheduled task folder is accessible without login? Please try with removing all the redirect rules for the application. That might work.

Wednesday, August 25, 2021
 
motanelu
answered 4 Months ago
46

If code you need to run can be factored / extracted as a Node.js app, you can run it as a scheduled Azure WebJob. You can find details on how to do that here. You don't need to install Node.js - it's already installed on all the Azure App Service workers.

One thing to note is that WebJobs run an execution sandbox (details here) and there are some restrictions on what is allowed to run in the sandbox. So you'd have to experiment to see if your PDF library runs successfully there.

For example, one of the popular libraries for PDF generation wkhtmtopdf will not work on Azure App Service. This SO post discusses this in more detail. One user has successfully hosted wkhtmtopdf on an Azure VM and offers it as a service that you can call.

Wednesday, November 24, 2021
 
nlucaroni
answered 2 Weeks ago
39

When does it start to work and to count the 24hrs, when I first run the application?

Yes. Set a breakpoint and start your application. You'll see how quickly it fires.

Is the Worker Service suitable for managing scheduled tasks?

Yes.

How can I say that the task must be run at a specific time in a day, at midnight for example?

Let's take a look at this code:

public sealed class MyTimedBackgroundService : BackgroundService
{

    private static int SecondsUntilMidnight()
    {
        return (int)(DateTime.Today.AddDays(1.0) - DateTime.Now).TotalSeconds;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var countdown = SecondsUntilMidnight();

        while (!stoppingToken.IsCancellationRequested)
        {
            if (countdown-- <= 0)
            {
                try
                {
                    await OnTimerFiredAsync(stoppingToken);
                }
                catch(Exception ex)
                {
                    // TODO: log exception
                }
                finally
                {
                    countdown = SecondsUntilMidnight();
                }
            }
            await Task.Delay(1000, stoppingToken);
        }
    }

    private async Task OnTimerFiredAsync(CancellationToken stoppingToken)
    {
        // do your work here
        Debug.WriteLine("Simulating heavy I/O bound work");
        await Task.Delay(2000, stoppingToken);
    }
}

This doesn't use System.Threading.Timer at all incase you are worried about the timer never actually firing off because of some boundary. Some people are paranoid of this. I have never had that happen to me. And I use Timer a lot for this type of work.

It will calculates the number of seconds until midnight then loop until it gets there.

This is a non-reentrant timer and there will be slight time slippage due to the business logic for processing the delay.

Here is another example using System.Threading.Timer:

public sealed class MyTimedBackgroundService : IHostedService
{
    private Timer _t;

    private static int MilliSecondsUntilMidnight()
    {
        return (int)(DateTime.Today.AddDays(1.0) - DateTime.Now).TotalMilliseconds;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        // set up a timer to be non-reentrant
        _t = new Timer(async _ => await OnTimerFiredAsync(cancellationToken),
            null, MilliSecondsUntilMidnight(), Timeout.Infinite);
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _t?.Dispose();
        return Task.CompletedTask;
    }

    private async Task OnTimerFiredAsync(CancellationToken cancellationToken)
    {
        try
        {
            // do your work here
            Debug.WriteLine("Simulating heavy I/O bound work");
            await Task.Delay(2000, cancellationToken);
        }
        finally
        {
            // set timer to fire off again
            _t?.Change(MilliSecondsUntilMidnight(), Timeout.Infinite);
        }
    }
}

(this code was not tested, there may be some spelling/syntax errors)

This is a non-reentrant timer meaning you are guaranteed that it will not fire off again if it's currently processing data.

It will calculates the number of milliseconds until midnight then set a timer based on that calculation.

This idea was taken from Microsoft.

Both of these examples can be injected as so:

services.AddHostedService<MyTimedBackgroundService>();

Cloud Native Warning:

Keep in mind that since these examples are local to your application, that if your application scales up horizontally where you have more than one instance running, you will be running two or more timers, just in separate processes. Just a friendly reminder. If your application will never scale, then ignore this warning.

Sunday, December 5, 2021
 
Bojan Kseneman
answered 2 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share