C# 异步工作流和用户交互:如何实现';背面';功能
我们正在尝试使用异步工作流来处理用户交互。我们的想法是,我们提供了一些基本的可能交互(上传文件、提示输入一些数据等)——以Web表单的形式实现——我们的系统用户可以编写在服务器上运行的工作流,并结合这些交互:C# 异步工作流和用户交互:如何实现';背面';功能,c#,async-await,C#,Async Await,我们正在尝试使用异步工作流来处理用户交互。我们的想法是,我们提供了一些基本的可能交互(上传文件、提示输入一些数据等)——以Web表单的形式实现——我们的系统用户可以编写在服务器上运行的工作流,并结合这些交互: var uploadResult = await DoUpload(); // . . .do stuff with uploadResult .. .. var formResult = await DoForm() // . . . do stuff with form
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);
}
}
}
类程序{
类步{
公共字符串提示;
公共任务完成源Tsc;
}
///迄今为止执行的用户交互
静态列表s_步骤=新列表();
静态布尔s_Continue=false;
///(非常基本的)用户交互示例
静态任务ReadString(字符串提示)
{
TaskCompletionSource tsc=新TaskCompletionSource();
试一试{
s_步骤添加(
新步骤(){Prompt=Prompt,Tsc=Tsc}
);
s_Continue=true;
}捕获(异常){
tsc.SetException(异常);
}
返回tsc任务;
}//读取字符串
静态异步任务工作流()
{
var str1=等待读取字符串(“字符串1”);
WriteLine(“字符串1='{0}',str1);
var str2=等待读取字符串(“字符串2”);
WriteLine(“字符串2='{0}',str2);
}//工作流
静态void Main(字符串[]参数)
{
//启动工作流。。。
工作流();
//…然后执行它
while(s_Continue&&s_Steps.Count>0){
s_Continue=false;
背面:
var step=s_Steps[s_Steps.Count-1];
如果(s_Steps.Count>1){
Console.Write(step.Prompt+“[back]:”);
}否则{
Console.Write(step.Prompt+“:”);
}
字符串结果=Console.ReadLine();
如果(s_Steps.Count>1&&result==“返回”){
s_Steps.RemoveAt(s_Steps.Count-1);
返回;
}
步骤Tsc设置结果(结果);
}
}
}
在第二个提示下键入back
时,代码尝试重新执行第一个任务,但失败,因为它已经完成
有没有一种方法可以让它工作——即以某种方式调用以前执行的任务的延续?简言之,没有。您正在对核心类型进行一次相当大的重新设计,我认为您无法使用
异步
方法将其全部绑定在一起。注意内部平台效应。谢谢@StephenCleary,我想是的,但我希望在放弃这个想法之前得到一些确认。