报告/监控长流程进度的设计模式

本文关键字:程进度 设计模式 监控 报告 | 更新日期: 2023-09-27 17:59:31

任何人都可以建议一个好的设计模式来报告/监控长流程的状态/进度。基本上,我有一个接收"数据上下文"对象的代码库:

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("Progress");}

    并将创建DataContext对象的代码注册到PropertyChanged事件。然而,这似乎是一种过于简单化的方法。。。

  2. ILog(使用您喜欢的任何日志框架):在各种任务/子任务中使用ILog实例,并让主任务执行器将其自己的侦听器添加到日志框架中。然而,这似乎是弯曲了日志记录机制来做它不应该做的事情

  3. Udi Dahan的DomainEvents:任务的执行者可以将DataContext视为"域",因此我们可以尝试为"ProgressChanged"事件实现"EventHandler"。理论上,这甚至可以用于更精细的事件,这些事件发生在特定的子任务中。。。但再一次,这感觉就像是在强迫这个概念。。。

我关心的问题包括:

  • 进度可能不是唯一需要监控的"事件"-在我们上面的例子中,我们可能想要更明确的东西,如FolderHandled、FileCopied等,但我们可能不知道执行任务时的确切事件(记住,子任务是基于DataContext创建的,可能会导致执行不同的任务)
  • 运行任务的上下文尚未定义。目前,我只是计划从命令行应用程序运行任务,因此调试需要输出到命令行。稍后,当我将其转移到服务时,我可能希望有一个"侦听器"用任务的进度更新数据库(例如)

报告/监控长流程进度的设计模式

您可以为每种可能的操作类型声明参数,例如文件操作的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);
    }
}

创建DataContext时将指定OperationProgress。

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"));
    }
}

考虑BackgroundWorkers。http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx它们在一个单独的UI线程上有自己的reportprogress事件。