我们正在尝试使用异步工作流来处理用户交互。我们的想法是,我们提供了许多基本的可能交互(上传文件,提示某些数据等) - 实现为Web表单 - 我们系统的用户可以编写在服务器上运行的工作流,并结合这些交互:
var uploadResult = await DoUpload();
// . . .do stuff with uploadResult .. ..
var formResult = await DoForm()
// . . . do stuff with formResult
除了处理“后退”按钮外,我们已经完成了这一切:在上面的示例中,对DoForm()
的调用提示输入某些数据,并且因为它是工作流中的第二种形式,它应该具有还有一个“后退”按钮,按下后返回初始上传表单。
显而易见的方法是在每次交互的结果中返回一个BackClicked
标志,然后应该由工作流代码进行测试和处理 - 我们更喜欢自动运行的东西。
这是一个简单的控制台应用程序的代码,它复制了我们正在做的事情:
class Program {
class Step {
public string Prompt;
public TaskCompletionSource<string> Tsc;
}
/// <summary>User interactions executed so far</summary>
static List<Step> s_Steps = new List<Step>();
static bool s_Continue = false;
/// <summary>Example of a (very basic) user interaction</summary>
static Task<string> ReadString(string prompt)
{
TaskCompletionSource<string> tsc = new TaskCompletionSource<string>();
try {
s_Steps.Add(
new Step() { Prompt = prompt, Tsc = tsc }
);
s_Continue = true;
} catch (Exception exception) {
tsc.SetException(exception);
}
return tsc.Task;
} // ReadString
static async Task TheWorkflow()
{
var str1 = await ReadString("String 1");
Console.WriteLine("String 1='{0}'", str1);
var str2 = await ReadString("String 2");
Console.WriteLine("String 2='{0}'", str2);
} // TheWorkflow
static void Main(string[] args)
{
// Start the workflow...
TheWorkflow();
// ..and then execute it
while (s_Continue && s_Steps.Count > 0) {
s_Continue = false;
Back:
var step = s_Steps[s_Steps.Count - 1];
if (s_Steps.Count > 1) {
Console.Write(step.Prompt + " [back]: ");
} else {
Console.Write(step.Prompt + ": ");
}
string result = Console.ReadLine();
if (s_Steps.Count > 1 && result == "back") {
s_Steps.RemoveAt(s_Steps.Count - 1);
goto Back;
}
step.Tsc.SetResult(result);
}
}
}
在第二个提示符下键入back
时,代码会尝试重新执行第一个任务,但由于它已经完成而失败。
有没有办法让它发挥作用 - 即以某种方式调用以前执行的任务的继续?