How to schedule custom task through c# - c#

I am using Task Scheduler for scheduling my task in c# application. I think i got the basic understanding of this library.
But now i stuck in a place where i want to create a custom action which will execute on the set schedule.Like the built-in action i.e EmailAction ( Which will send mail on set schedule ), ShowMessageAction ( Which will show alert message on set schedule ), i want to create an action which will run my c# code and that code will save some data to my database.
What I tried yet is: I created a class CustomAction which inherits Action, like :
public class NewAction : Microsoft.Win32.TaskScheduler.Action
{
public override string Id
{
get
{
return base.Id;
}
set
{
base.Id = value;
}
}
public NewAction()
{
}
}
And here is my task scheduler code :
..
...
// 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
TimeTrigger tt = new TimeTrigger();
tt.StartBoundary = DateTime.Today + TimeSpan.FromHours(19) + TimeSpan.FromMinutes(1);
tt.EndBoundary = DateTime.Today + TimeSpan.FromHours(19) + TimeSpan.FromMinutes(3);
tt.Repetition.Interval = TimeSpan.FromMinutes(1);
td.Triggers.Add(tt);
// Create an action that will launch Notepad whenever the trigger fires
td.Actions.Add(new NewAction()); <==========================
// Register the task in the root folder
ts.RootFolder.RegisterTaskDefinition(#"Test", td);
// Remove the task we just created
//ts.RootFolder.DeleteTask("Test");
}
...
....
On the line (pointed by arrow) i am getting the exception :
value does not fall within the expected range task scheduler
I am not sure what i am trying to achieve is even possible or not, if it is possible than please guid me on the correct direction?

According my understanding of your question. I had implemented same thing, but I had used "Quartz" Scheduler instead of "Task Scheduler". It is very easy to implement. May be you can also try with this.
To reference:
http://quartznet.sourceforge.net/tutorial/
Please correct me if I am wrong.

Related

How can I get a Hangfire job's end time?

Given a Hangfire job's ID, how can I get the time at which the job finished running?
I've tried the below, but the JobData class doesn't have a property for job end time.
IStorageConnection connection = JobStorage.Current.GetConnection();
JobData jobData = connection.GetJobData(jobId);
I have had a similar requirement before. Here is a method I wrote to get the SucceededAt property using the name of the running method and the current PerformContext:
public static DateTime? GetCompareDate(PerformContext context, string methodName)
{
return long.TryParse(context.BackgroundJob.Id, out var currentJobId)
? JobStorage.Current
?.GetMonitoringApi()
?.SucceededJobs(0, (int)currentJobId)
?.LastOrDefault(x => x.Value?.Job?.Method?.Name == methodName).Value?.SucceededAt
: null;
}
You could just as easily get DeletedJobs, EnqueuedJobs, FailedJobs, etc.
You can call it from a job method like this:
public async Task SomeJob(PerformContext context, CancellationToken token)
{
⋮
var compareDate = GetCompareDate(context, nameof(SomeJob));
⋮
}
You just have to add the PerformContext when adding the job by passing in null:
RecurringJobManager.AddOrUpdate(
recurringJobId: "1",
job: Job.FromExpression(() => SomeJob(null, CancellationToken.None)),
cronExpression: Cron.Hourly(15),
options: new RecurringJobOptions
{
TimeZone = TimeZoneInfo.Local
});
Note: It will only work if the succeeded job has not expired yet. Successful jobs expire after one day - if you need to keep them longer (to get the SucceededAt property), here is a reference for that: How to configure the retention time of job?
You could try using the Stopwatch class when you first call the task and stop it when the task is completed.
Then you could use a log nugget to generate a txt log file containing the start time and end time of your job. Or directly save this values to your database so that you can review them later.

How To Create an Action Class?? To register with "WPF" task schedule queue using MVVM pattern

I am creating a WPF application. I am implementing the MVVM pattern. I have a UI which returns the source path, destination path and a list of DateTimes which is a queue of times to execute for then next seven days.
In this function I want to be able to take the list of scheduled dates and register a task using my Schedule Helper Class
This is my ViewModel which has access to my Directory Helper class instance and a model instances bound to my UI.
Below is my function which get called after my fields are populated and the button is submitted
//THIS FUNCTION IS BOUND TO A BUTTON ON THE PAGE
private void startBackUp(object param) {
// LIST OF DATETIMES
List<DateTime> backUpQueue = new List<DateTime>();
// FUNCTION IN THIS VIEW MODEL THAT RETURNS
// CURRENT INSTANCE OF THE MODEL WITH THE USERS SELECTION
backUpQueue = populateBackUpQueue(backUpQueue);
// THIS IS THE ACTION I WANT TO PERFORM
// FRUNCTION FROM INSTANCE OF A HELPER CLASS
DirectoryCommand.DirectoryCopy(BackUp.SourcePath,BackUp.DestinationPath, true);
}
I want to create a task which runs Directory copy function using this scheduled Task helper method
SchedualeTask.cs
using Microsoft.Win32.TaskScheduler;
using System;
namespace BackUpProject.Helper
{
class SchedualeWindowsTasks
{
public TaskService ts { get; set; }
public SchedualeWindowsTasks()
{
// INSTANCE OF A TASK SERVICE
TaskService ts = new TaskService();
}
private void CreateNewWindowsScheduale(Action<DateTime>schedualedAction) {
// Create a new task definition and assign properties
TaskDefinition td = ts.NewTask();
td.RegistrationInfo.Description = "THIS SHOULD BE MY TASK";
// This will be the date time to execute this task
// I can the use DailyTrigger to repeat weekly
//Currently exceute every other day
td.Triggers.Add(new DailyTrigger(2));
// This needs to be my DirectoryCopy() function with parameters
td.Actions.Add(new ExecAction("notepad.exe", "c:\\test.log", null));
// need to register it so can delete by calling DeleteTask("Test")
ts.RootFolder.RegisterTaskDefinition(#"Test", td);
}
}
}
I simply want to take by source path and directory path and execute my directoryCopy function on every DateTime given by the user and then use a weekly Trigger to repeat every week until Deleted by the user, but I handle delete later.
My question is by maintaining the MVVM pattern what is the favorable method of implementing such a task.

Quartz scheduler: avoid using class file and want to call a method directly

I am using quartz scheduler in my project. I have copy pasted my code below.In this area of code,
Type type=typeof(class),
I need to call a method like,
Type type=typeof(methodname()).
I dont want to call an external class file.
int JobID = 0;
JobDetailImpl job = null;
Quartz.Impl.Triggers.CronTriggerImpl trigger = null;
ISimpleTrigger simpleTrigger = null;
JobDataMap jobdatamap = new JobDataMap();
sheduler.Start();
String cronExpression = "0 0/1 * * * ?";
Type type = typeof(TriggerJob1);
job = new JobDetailImpl("Job" + JobID + "", null, type);
trigger = new Quartz.Impl.Triggers.CronTriggerImpl("Trigger" + JobID + "", "Job" + JobID + "", cronExpression);
sheduler.ScheduleJob(job, trigger);
TriggerJob1 in the above code is a class file which I created locally. According to quartz scheduler, it has the functionality that scheduler calls at its scheduled time.
why i want to use a method instead of Triggerjob1 class file is:- I am using quartz scheduler in aspx file. I have all functionality written in a button click event. I am going to invoke this button by using scheduler.
I want to use like this. This is my expected behaviour.
Type type = typeof(button_click);
I do not want to call this button click from external class file. But the syntax of quartz scheduler advices me to use a class file only.
Kindly help me if anyone know it. If anyone cannot understand me what I am saying, please let me know.

Reading activity InArgument values

I am creating a custom native activity using workflow foundation 4.5. I want to set a bookmark for the activity and do some custom handling in the WorkflowApplication's PersistableIdle callback. Within that callback I want to read the data that was provided into the activity's InArgument<> and/or Properties before the workflow instance is persisted away. So essentially, I want to read these values from outside the context of the activity that executed and outside the run time as a pre-step before completing the persistence process.
I thought I might be able to do this with the WorkflowInspectionServices helper class but it's unclear if that works given I have to context to read from that activity instance's InArgument<>.
Is there another helper class that can make this happen with wf4.5 that I haven't discovered yet? Thanks.
wfApp.PersistableIdle += args =>
{
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
wfApp.Unload();
args.Bookmarks.ForEach(bookmark =>
{
var activityId = bookmark.BookmarkName;
//Doesn't seem this will really work?
var activityInfo = WorkflowInspectionServices.Resolve(activity, activityId) as MyCustomActivity;
var recipientId = activityInfo.RecipientId.Get(<I have no context>);
workflowSuspendedCallback.Invoke(activityId, recipientId));
});
scope.Complete();
}
return PersistableIdleAction.None;
};
The use of activity extensions did the trick.
Thanks Will.

Quartz.Net - update/delete jobs/triggers

I'm using Quartz to pull latest tasks (from another source), it then adds it in as a job, creates triggers etc per each task. - Easy.
However, sometimes tasks change (therefore they already exist). Therefore I would like to change its (lets say to keep it simple Description. Code below updates specific task's description with given date.
private static void SetLastPull(DateTime lastPullDateTime)
{
var lastpull = sched.GetJobDetail("db_pull", "Settings");
if(lastpull != null)
{
lastpull.Description = lastPullDateTime.ToString();
}
else
{
var newLastPull = new JobDetail("db_pull", "Settings", typeof(IJob));
newLastPull.Description = lastPullDateTime.ToString();
var newLastPullTrigger = new CronTrigger("db_pull", "Settings", "0 0 0 * 12 ? 2099");
sched.ScheduleJob(newLastPull, newLastPullTrigger);
}
}
I'm assuming after I do lastpull.Description = lastPullDateTime.ToString(); I should call something to save changes to database. Is there a way to do it in Quartz or do I have to go to using other means and update it?
You can't change (update) a job once it has been scheduled. You can only re-schedule it (with any changes you might want to make) or delete it and create a new one.

Categories