我正在开发一个MVC应用程序,它在后台使用一些Windows Workflow进行自动化。
我已经实现了一些代码来等待Workflow完成。下面是一个示例应用程序,将问题归结为其关键部分。
这个问题与WF活动中的工作没有关系,更多的是我等待它完成的工作。
HomeController.cs
public ActionResult Index()
{
return View();
}
[HttpPost]
public JsonResult ProcessRequest()
{
int[] arr = new int[0];
var wh = new ManualResetEvent(false);
var instance = new Activities.SampleCodeActivity();
var args = new Dictionary<string, object>();
args.Add("Limit", 25);
var app = new WorkflowApplication(instance, args);
app.Completed = resultArgs =>
{
var list = (List<int>)resultArgs.Outputs["Primes"];
arr = list.ToArray();
wh.Set();
};
app.Run();
wh.WaitOne();
return Json(arr);
}
Index.cshtml
@{ ViewBag.Title = "Index"; }
<script src="../../Scripts/jquery-1.7.1.min.js"></script>
<script type="text/javascript">
var tools = {};
tools.processRequest = function () {
$.ajax({
url: "@Url.Action("ProcessRequest")", type: "POST",
success: function (data) {
alert(data);
}
});
};
$(document).ready(function () {
tools.processRequest();
});
</script>
<h2>Index</h2>
SampleCodeActivity.cs
public class SampleCodeActivity : CodeActivity
{
public InArgument<int> Limit { get; set; }
public OutArgument<List<int>> Primes { get; set; }
private List<int> _list = new List<int>();
protected override void Execute(CodeActivityContext context)
{
var limit = context.GetValue(Limit);
checkForPrimes(limit);
context.SetValue(Primes, _list);
}
private void checkForPrimes(int limit)
{
for (var x = 2; x <= limit; x++)
if (isPrime(x)) _list.Add(x);
}
private bool isPrime(int value)
{
for (var x = value - 1; x > 1; x--)
if (value % x == 0) return false;
return true;
}
}
我的问题是关于Controller Action中的WaitHandle / ManualResetEvent。有没有更好的方法来使用任务等来实现这一点?我使用的是.NET 4.5。
如果没有WaitHandle,Action将在工作流程完成之前返回。
我熟悉WaitHandle,但感觉就像一个笨重的解决方案。
感谢任何帮助/指导。
答案 0 :(得分:2)
WaitHandle
是一个抽象类,提供在操作系统级别等待访问共享资源的能力。如果您希望在此级别同步访问权限,则无法使用它。但是,正如您所提到的,使用类似ManualResetEvent
之类的内容可能会中断代码流,使得在出现问题时难以阅读和诊断。
.NET框架最近添加的许多关于线程的尝试都试图解决这个问题。在.NET 4中引入了Task
的概念,它可以在某种程度上简化代码,并在该基础结构之上构建C#5以引入async/await
关键字。下面的代码是一个简单的控制台应用程序,显示了使用ManualResetEvent
,Task
和async/await
实现所需内容的三种方法。
重要的是要意识到所有三个都在某个级别使用WaitHandle
类来同步线程,但使用Task
和async/await
来提高可读性。
class Program
{
static void Main(string[] args)
{
List<int> results;
//Using raw Wait Handle
ManualResetEvent handle = new ManualResetEvent(false);
Thread thread = new Thread(o =>
{
//Long running process
results = LongRunningTask();
handle.Set();
});
thread.Start();
handle.WaitOne();
Console.WriteLine("Thread completed");
//Using Tasks
Task<List<int>> task = Task<List<int>>.Factory.StartNew(LongRunningTask);
results = task.Result;
Console.WriteLine("Task completed");
//Using async/await
results = LongRunningTaskAsync().Result;
Console.WriteLine("Async Method completed");
Console.ReadLine();
}
public static List<int> LongRunningTask()
{
Thread.Sleep(5000);
return new List<int>();
}
public static async Task<List<int>> LongRunningTaskAsync()
{
return await Task<List<int>>.Factory.StartNew(LongRunningTask);
}
}