2013-03-11 62 views
1

我正在開發一個MVC應用程序,它在幕後使用一些Windows Workflow來實現自動化。WaitHandle是最佳選擇嗎?

我已經實現了一些代碼來等待工作流程完成。下面是一個示例應用程序,將問題歸結爲其關鍵部分。

這個問題並不是真的與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很熟悉,但感覺就像一個klunky解決方案。

任何幫助/指導表示讚賞。

+0

我還沒有想法,但我有興趣看到一個答案。我用waithandles - 而我不喜歡它們。感覺「粗呃」比GOTO: – 2013-03-13 01:16:11

回答

1

WaitHandle是一個抽象類,提供了在操作系統級別等待訪問共享資源的能力。如果您希望在此級別同步訪問,則不會放棄使用它。但是,正如您所提到的,使用類似ManualResetEvent的東西可能會中斷代碼的流向,從而在出現問題時很難進行閱讀和診斷。

.NET框架最近增加了很多關於線程的嘗試來解決這個問題。在.NET 4中引入了Task的概念,可以簡化代碼,並且C#5構建在該基礎結構之上,以引入async/await關鍵字。下面的代碼是一個簡單的控制檯應用程序,顯示了使用ManualResetEvent,Taskasync/await實現您想要的三種方法。

重要的是要認識到,所有三個在某個級別上使用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); 
    } 
}