This project has moved. For the latest updates, please go here.

Task Event Management

Many applications have the need to audit the execution of the tasks they supply. To enable this, the library provides the TaskEventLog class that allows for TaskEvent instances to be enumerated. This can be done for single tasks or the entire system. It can also be filtered by specific events or criticality.

Sometimes, a developer will need to know about events as they occur. In this case, they can use the TaskEventWatcher component that enables the developer to watch a task, a folder, or the entire system for filtered events.

Task Event Logs

// Create a log instance for the Maint task in the root directory
TaskEventLog log = new TaskEventLog(@"\Maint",
   // Specify the event id(s) you want to enumerate
   new int[] { 141 /* TaskDeleted */, 201 /* ActionSuccess */ },
   // Specify the start date of the events to enumerate. Here, we look at the last week.
   DateTime.Now.AddDays(-7));

// Tell the enumerator to expose events 'newest first'
log.EnumerateInReverse = false;

// Enumerate the events
foreach (TaskEvent ev in log)
{
   // TaskEvents can interpret event ids into a well known, readable, enumerated type
   if (ev.StandardEventId == StandardTaskEventId.TaskDeleted)
      output.WriteLine($"  Task '{ev.TaskPath}' was deleted");

   // TaskEvent exposes a number of properties regarding the event
   else if (ev.EventId == 201)
      output.WriteLine($"  Completed action '{ev.DataValues["ActionName"]}',
         ({ev.DataValues["ResultCode"]}) at {ev.TimeCreated.Value}.");
}

Task Event Watching

Below is information on how to watch a folder for all task events. For a complete example, look at this sample project: TestTaskWatcher.zip

private TaskEventWatcher watcher;

// Create and configure a new task watcher for the task folder
private void SetupWatcher(TaskFolder tf)
{
   if (tf != null)
   {
      // Set up a watch over the supplied task folder.
      watcher = new TaskEventWatcher(tf);

      // Assign a SynchronizingObject to a local UI class to synchronize the events in this thread.
      watcher.SynchronizingObject = this;

      // Only watch for tasks that start with my company name
      watcher.Filter.TaskName = "MyCo*";

      // Only watch for task events that are informational
      watcher.Filter.EventLevels = new int[]
         { 0 /* StandardEventLevel.LogAlways */, (int)StandardEventLevel.Informational };

      // Assign an event handler for when events are recorded
      watcher.EventRecorded += Watcher_EventRecorded;
      
      // Start watching the folder by enabling the watcher
      watcher.Enabled = true;
   }
}

// Cleanup and release the task watcher
private void TearDownWatcher()
{
   if (watcher != null)
   {
      // Unhook the event
      watcher.EventRecorded -= Watcher_EventRecorded;
      // Stop watching for events
      watcher.Enabled = false;
      // Initiate garbage collection for the watcher
      watcher = null;
   }
}

// Update ListView instance when task events occur
private void Watcher_EventRecorded(object sender, TaskEventArgs e)
{
   int idx = IndexOfTask(e.TaskName);
   
   // If event is for a task we already have in the list...
   if (idx != -1)
   {
      // If event indicates that task has been deleted, remove it from the list
      if (e.TaskEvent.StandardEventId == StandardTaskEventId.TaskDeleted)
      {
          listView1.Items.RemoveAt(idx);
      }
      
      // If event is anything else, it most likely represents a change,
      // so update the item using information supplied through the
      // TaskEventArgs instance.
      else
      {
         var lvi = listView1.Items[idx];
         lvi.Subitems[0].Text = e.TaskName;
         lvi.Subitems[1].Text = e.Task.State.ToString();
         lvi.Subitems[2].Text = GetNextRunTimeString(e.Task);
      }
   }
   
   // If event is for a task we don't have in our list, add it
   else
   {
      var lvi = new ListViewItem(new string[] { e.TaskName,
         e.Task.State.ToString(), GetNextRunTimeString(e.Task) });
      listView1.Items.Add(lvi);
      listView1.Sort();
   }
}

// Get the next run time for a task
private string GetNextRunTimeString(Task t)
{
    if (t.State == TaskState.Disabled || t.NextRunTime < DateTime.Now)
        return string.Empty;
    return t.NextRunTime.ToString("G");
}

Last edited Dec 21, 2015 at 5:58 PM by dahall, version 2

Comments

dahall May 23 at 3:02 PM 
IndexOfTask was an internal method that only found the index of the task's ListViewItem in the form's ListView control. It simply did a search of the name.

merlachandra May 21 at 6:27 PM 
Could you please also share IndexOfTask(string) method definition? I could not find it in even TestTaskWatcher.zip attached here.

Thanks in advance,
Chandra