报告/监控长流程进度的设计模式
本文关键字:程进度 设计模式 监控 报告 | 更新日期: 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…"
我考虑了以下选项:
INotifyPropertyChanged:将"Progress"属性添加到DataContext
公共字符串Progress{get;set{_Progress=value;RaisePropertyChanged("Progress");}
并将创建DataContext对象的代码注册到PropertyChanged事件。然而,这似乎是一种过于简单化的方法。。。
ILog(使用您喜欢的任何日志框架):在各种任务/子任务中使用ILog实例,并让主任务执行器将其自己的侦听器添加到日志框架中。然而,这似乎是弯曲了日志记录机制来做它不应该做的事情
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事件。