2013-02-15 50 views
7

Ben MVC4 API DİNLENME yeni dizisindeki bir süreç başlatmaya çalışıyor var. Framework 4.5 ile çalışıyorum ve senkronizasyon kullanmaya ve clausules'i beklemeye çalışıyorum.MVC4 WebAPI süreci başlatıcısı

[AcceptVerbs("POST")] 
public HttpResponseMessage Launch(string id) 
{ 
    runProcessAsync(id); // 1               

    return Request.CreateResponse(HttpStatusCode.Accepted); // 2 
} 

protected async void runProcessAsync(string id) 
{ 
    int exitcode = await runProcess(id); // 3 
    string exitcodesz = string.Format("exitcode: {0}", exitcode); // 4 
    // do more stuff with exitcode 
} 

protected Task<int> runProcess(string id) 
{ 
    var tcs = new TaskCompletionSource<int>(); 

    var process = new Process 
    { 
     StartInfo = { FileName = @"C:\a_very_slow_task.bat" }, 
      EnableRaisingEvents = true 
     }; 
     process.Exited += (sender, args) => tcs.SetResult(((Process)sender).ExitCode);    

     process.Start(); 

     return tcs.Task; 
    } 
} 

İdeal olarak, birisi POST fiil ile bir API dinlenme çağrısı (/ görev/slowtask/fırlatma) gerçekleştirecek ve çok hızlı bir 202 (Kabul) bekliyoruz:

Kodum benziyor.

Fiddler Web Hata Ayıklayıcısını Kullanma İsteğimi yapıyorum, kod (// 1) içine girer, sonra beklemeye geçer (// 3), yavaş görev oluşturulur ve başlatılır ve Kabul edildi (//) döndürülür 2). Ama bu noktada, Fiddler 202 sonucunu göstermiyor. Yavaş görev sona erdiğinde

http://imageshack.us/photo/my-images/703/fiddler1.png/

, kod exitCode (// 4) ve daha sonra 202 Fiddler içine yakalanır yakalama devam: ekli resme bakın. Ben dönüş uzun zaman önce yaptığı, çünkü çok garip

. Benim neyim eksik? 202 kodunu çok hızlı döndürmek ve görevi unutmak için bu kodu nasıl değiştirebilirim?

Not: Bunu, çerçeve dışı 4.5 özellikleriyle nasıl yapacağımı biliyorum, async/wait'i kullanmayı öğrenmeye çalışıyorum.

+1

Bunun nedeni, 'runProcessAsync()' isteğinin senkronizasyon bağlamında çalıştığı içindir. Eğer bunu istemezseniz, 'Task.Run (() => runProcessAsync (id));' kullanabilirsiniz. Ancak, bu konuya dikkat edin, çünkü IIS bu süre içinde uygulama alanınızı geri dönüştürebilir, bu yüzden runProcessAsync() 'ın tamamlanamayacağı bir şans olacaktır. – svick

+0

Bunu yaptım ve çalışıyor. Doğru bir cevap vermediğin için utanç vericiydi, sorunumu çözdüğün için neden oldu – Jordi

cevap

4

Bu isteğin senkronizasyon bağlamına runProcessAsync() çünkü çalışır olduğunu düşünüyorum. Bunu istemiyorsanız, Task.Run(() => runProcessAsync(id));'u kullanabilirsiniz. Ancak, bu konuya dikkat edin, çünkü IIS, AppDomain'inizi bu süre içinde geri dönüştürebilir, dolayısıyla runProcessAsync()'un tamamlanma şansı yoktur.

1

kolay yolu sadece Task dönmek için runProcessAsync değiştirmektir. async yöntemleri Task/Task<T> mümkün olduğunca dönmek ve onlar zorunda yalnızca void dönmelidir unutmayın.

Ancak, bu oldukça tehlikeli olduğunu size uyarmak gerekir. ASP.NET bir HTTP sunucusudur, bu yüzden aktif istek yoksa, eğer isterseniz AppDomain'inizi almakta özgürsünüz. Bu, "çıkış koduyla daha fazla şeyler yap" anlamına gelir, sadece dünyanın yüzünü bırakacaktır.

Task s'yi ASP.NET çalışma zamanı ile kaydetmek için kullanabileceğiniz bir blog post with a BackgroundTaskManager var. Tamamlanmayan kayıtlı Task s varsa, AppDomain kapatmalarını ertelemeye çalışacaktır. Ancak, bu sadece bir "en iyi çaba"; Bu tür şeyler için hiçbir garanti yoktur. ASP.NET'te çalışan ve etkin bir istekle ilişkilendirilmemiş kodlar tehlikeli bir durumdur.

+0

Anlamıyorum, neden 'Task' yardımının dönüş türünü değiştirecek? Sorun senkronizasyon bağlamındaysa, o zaman hiçbir şey değişmeyecek, değil mi? – svick