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

时间:2011-06-20 15:14:05

标签: c# design-patterns reporting progress

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

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 :向DataContext添加“Progress”属性

    public string Progress {get;设置{_progress = value; RaisePropertyChanged( “进度”); }

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

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

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

  4. 我的担忧包括:

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

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

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