Шаблон проектирования для отчетности / мониторинга прогресса длинных процессов - PullRequest
8 голосов
/ 20 июня 2011

Любой может предложить хороший шаблон проектирования для составления отчетов / мониторинга состояния / хода выполнения длительных процессов. По сути, у меня есть кодовая база, которая получает объект «data-context»:

public class DataContext : IDataContext
{
    pulbic Dictionary<string, objects> Properties { get; private set; }

    // Additional properties removed for simplicity...
}

На основе предоставленного контекста создается объект Task (не TPL-Task) с различными подзадачами. Во время выполнения объект DataContext передается различным подзадачам, которые могут получить или обновить его.

Например, допустим, что основная задача - это задача «Копировать файлы». DataContext будет иметь такие свойства, как SourceFolder и TargetFolder и, возможно, свойство FilterFiles (например, * .docx). Нашей главной задачей будет CopyFilesTasks, и он будет иметь «конвейер» подзадач - сканирование папок, сканирование файлов, фильтрацию файлов, копирование файлов и т. Д ....

То, что я ищу, - это лучший способ позволить задаче / подзадачам сообщать о своем ходе вызывающей стороне / исполнителю. В нашем примере выше, изменения в процессе могут быть просто «Скопированный файл ABC.docx ...», или, возможно, что-то более «сложное», например, «Сканирование папки XYZ ...»

Я рассмотрел следующие варианты:

  1. INotifyPropertyChanged : добавить свойство «Progress» в DataContext

    публичная строка Progress {get; set {_progress = value; RaisePropertyChanged ( "Прогресс"); }

    и иметь код, который создал объект DataContext, для регистрации в событии PropertyChanged. Тем не менее, это кажется слишком упрощенным подходом ...

  2. ILog (используя любую среду ведения журналов, которую вы предпочитаете): используйте экземпляр ILog в различных задачах / подзадачах и попросите, чтобы исполнитель главной задачи добавил своего собственного слушателя в структуру ведения журнала , Однако это выглядело как сгибание механизма каротажа для выполнения действий, которые он не должен был делать.

  3. Udi Dahan's DomainEvents : исполнитель задачи может рассматривать DataContext как «домен», и поэтому мы можем попытаться реализовать «EventHandler» для Событие "ProgressChanged". Теоретически, это может даже использоваться для более изощренных событий, которые происходят в определенных подзадачах ... Но опять же, это похоже на форсирование концепции ...

Мои опасения включают в себя такие вещи, как:

  • Прогресс может быть не единственным «событием», которое необходимо отслеживать - в нашем примере выше мы могли бы хотеть более определенные вещи, такие как FolderHandled, FileCopied и т. Д., Но мы можем не знать точные события при выполнении задач (помните - подзадачи создаются на основе DataContext и могут привести к выполнению разных задач).
  • Контекст выполнения задач еще не определен. Пока я просто планирую запускать задачи из приложения командной строки, поэтому для отладки необходим вывод в командную строку. Позже, когда я перенесу это в службу, мне может потребоваться, чтобы «слушатель» обновил базу данных, например, о ходе выполнения задачи.

Ответы [ 2 ]

1 голос
/ 21 июня 2011

Вы можете объявить аргументы для каждого возможного типа операции, например, FileOperationEventArgs для операции с файлом, DatabaseUpdateEventArgs для операции с базой данных и т. Д.

public class FileOperationEventArgs : EventArgs
{
    public readonly string SourceFolder;
    public readonly string TargetFolder;

    public FileOperationEventArgs(string sourceFolder, string targetFolder)
    {
        SourceFolder = sourceFolder;
        TargetFolder = targetFolder;
    }
}

public class DatabaseUpdateEventArgs : EventArgs
{
    public readonly int RowsUpdated;

    public DatabaseUpdateEventArgs(int rowsUpdated)
    {
        RowsUpdated = rowsUpdated;
    }
}

Класс OperationProgress объявляет события для каждого типа операции.

public class OperationProgress
{
    public event EventHandler<FileOperationEventArgs> FileCopied;
    public event EventHandler<DatabaseUpdateEventArgs> DatabaseUpdated;

    public void OnFileCopied(FileOperationEventArgs a)
    {
        if(FileCopied != null)
            FileCopied(this, a);
    }

    public void OnDatabaseUpdated(DatabaseUpdateEventArgs a)
    {
        if (DatabaseUpdated != null)
            DatabaseUpdated(this, a);
    }
}

OperationProgress будет указан при создании DataContext.

public class DataContext : IDataContext
{
    public Dictionary<string, object> Properties { get; private set; }
    public OperationProgress Progress { get; private set; }

    public DataContext(OperationProgress progress)
    {
        Progress = progress;
    }
}

Реализация подзадачи может обновлять ход выполнения.

public class FileCopySubTask
{
    public void Execute(DataContext context)
    {
        context.Progress.OnFileCopied(new FileOperationEventArgs("c:/temp1", "c:/temp2"));
    }
}
0 голосов
/ 20 июня 2011

Рассмотрим BackgroundWorkers. http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx У них есть собственное событие reportprogress в отдельном потоке пользовательского интерфейса.

...