1

我正在开发一个 MVC 应用程序,它在幕后使用一些 Windows 工作流来实现自动化。

我已经实现了一些代码来等待工作流完成。下面是一个示例应用程序,将问题归结为关键部分。

这个问题实际上与 WF 活动中正在进行的工作无关,而更多的是我如何等待它完成。

家庭控制器.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);
        }

索引.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>

示例代码活动.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;
    }
}

我的问题是关于控制器操作中的 WaitHandle/ManualResetEvent。有没有更好的方法来使用任务等来实现这一点?我正在使用.NET 4.5。

如果没有 WaitHandle,Action 会在工作流完成之前返回。

我熟悉 WaitHandle,但感觉就像一个笨拙的解决方案。

任何帮助/指导表示赞赏。

4

1 回答 1

2

WaitHandle是一个抽象类,提供了在操作系统级别等待访问共享资源的能力。如果您希望在此级别同步访问,则无法避免使用它。但是,正如您所提到的,使用类似的东西ManualResetEvent可能会中断您的代码流,从而在出现问题时难以阅读和诊断。

.NET 框架中最近添加的许多关于线程的功能都试图解决这个问题。在 .NET 4 中Task引入了 的概念,这可以在一定程度上简化代码,而 C# 5 在该基础架构之上构建以引入async/await关键字。ManualResetEvent下面的代码是一个简单的控制台应用程序,显示了使用、Task和实现您想要的三种方式async/await

重要的是要意识到这三个都在某种程度上使用该类来同步线程,但是使用's 和WaitHandle提高了可读性。Taskasync/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);
    }
}
于 2013-05-22T09:37:51.280 回答