2012-07-06 14 views
8

Używam Visual Studio 2012 RC z .Net 4.5 i ASP MVC 4 RC. Zawiesza się, gdy w ogóle korzystam z asynchronizacji. Metoda działania kontrolera używa asynchronizacji, ale sama nie jest metodą kontrolera asynchronicznego.Kontroler ASP.Net MVC 4 zawiesza się, gdy używany jest async.

Nie zgłoszono błędów ani nie zgłoszono wyjątków, ale przeglądarka wyświetla komunikat "Oczekiwanie na www.myweb.local" "na zawsze.

// Simplest possible async 
public class Waiter 
{ 
    public async Task<int> GetValue() 
    { 
     await Task.Yield(); 
     return await Task.Factory.StartNew(() => 42); 
    } 
} 

// simplest possible controller that uses the async 
public class HomeController : Controller 

    public ActionResult Index() 
    { 
     var waiter = new Waiter(); 
     var resultTask = waiter.GetValue(); 
     int result = resultTask.Result; 

     // it never gets here 
     return View(); 
    } 
} 

Zrobiłem rzeczy, które są odnotowane in this answer i nadal nie działa. tj. Web.config zawiera

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/> 

A magiczne słowa await Task.Yield(); są w sposób asynchroniczny.

Wersja szkieletowa .Net ma numer 4.5.50501. Zaobserwowałem to zachowanie w usługach IIS Express i IIS 6.0.

Próbowałem zastosować "Aktualizacja z lipca 2012" do VS2012, ale to nie naprawiło.

This answer suggests że może być fakt, że zadanie zostało już zakończone, gdy czekam na niego, jednak gdyby tak było, to powinno działać i to nie:

public class Waiter 
{ 
    public async Task<int> GetValue() 
    { 
     await Task.Yield(); 
     return await Task.Factory.StartNew(() => 
      { 
       Thread.Sleep(1500); 
       return 42; 
      }); 
    } 
} 

Kilka osób sugerowało, że ConfigureAwait(false) jest potrzebna, ale ten kod nie działa albo:

public async Task<int> GetValue() 
    { 
     var task = new Task<int>(() => 42); 
     return await task.ConfigureAwait(false); 
    } 

Poniższy działa z poglądem silnik brzytwa, ale nie z iskrą. Z pewnością powinien istnieć sposób na sprawdzenie, czy drugi scenariusz działa? Czy nie można używać zadań asynchronicznych wewnątrz kodu synchronicznego?

public class Waiter 
{ 
    public async Task<int> GetValue() 
    { 
     return await Task.Factory.StartNew(() => 42); 
    } 
} 

public class HomeController : Controller 
{ 
    public async Task<ActionResult> IndexAsync() 
    { 
     await Task.Yield(); 
     var waiter = new Waiter(); 
     int result = await waiter.GetValue(); 

     return View(); 
    } 
} 

wiem, że to nie jest zwolniony oprogramowanie, ale tras RC Microsoft są zazwyczaj dość stabilny, więc jestem zaskoczony, że to się nie powiedzie, a nie w bardzo nowoczesny sposób.

+2

Przepraszam, jeśli coś pominąłem, ale dlaczego blok indeksu ma dostęp do właściwości wyników zamiast oznaczania jej asynchronicznie i czekania tam? Jeśli jest to celowe, może być konieczne użycie opcji ConfigureAwait (false), aby kontynuacja nie została ponownie uruchomiona w tym samym wątku. –

+0

Testuję przeniesienie istniejącej witryny do .Net 4.5. Używa silnika widoku iskry.Chciałem uzyskać asynchroniczne działanie zanim zacząłem zajmować się kontrolerami async i czy iskra może obsłużyć zadanie , czy nie (moje pierwsze wrażenie było nie). Ale niezależnie od tego, czy mógłbym to zrobić, czy nie, scenariusz ten powinien zadziałać. – Anthony

+0

Dlaczego czerpiecie z AsyncController? To nie jest konieczne. Zobacz mój przykład asynchroniczny http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4 – RickAndMSFT

Odpowiedz

1

Asynchronicznie pracowałem w wersji beta. Nie testowałem tego, ale domyślam się, że to dlatego, że twoja metoda kontrolera nie jest tak asynchroniczna. Zmień to na:

public async Task<ActionResult> IndexAsync() 
{ 
    var waiter = new Waiter(); 
    int result = await waiter.GetValue(); 

    // it never gets here 
    return View(); 
} 
+0

Jeśli "ponieważ metoda kontrolera nie jest asynchroniczna", czy mówisz, że używanie zadań asynchronicznych nigdy nie będzie działało w kodzie synchronizacyjnym? W przeciwnym razie powinien istnieć sposób na uruchomienie tego kodu. – Anthony

+0

OK, edytowane, aby dodać zadanie , podczas gdy ja przetrawiam to ... –

+0

Tak więc GetValue() nie kończy się wtedy ... Nie mogę wymyślić oczywistego powodu tego z mojej głowy z tego, co masz i jestem teraz w pociągu! Zajrzę później, jeśli nikt mnie do tego nie pobił. –

9

Powodujesz zakleszczenie, just like this question.

sugestia James Manning jest poprawna, ale trzeba await wynik ConfigureAwait, tak:

public async Task<int> GetValue() 
{ 
    var task = new Task<int> (() => 42); 
    return await task.ConfigureAwait(false); 
} 

Na ogół, mieszanie kodu synchronicznego i asynchronicznego jest naprawdę zły pomysł, chyba że naprawdę wiesz co” Robię to ponownie. Zwiększenie asynchroniczności działania kontrolera byłoby znacznie lepsze.

+1

Zgadzam się - szczególnie, że teraz tak łatwo jest uczynić metody kontrolera asynchronicznymi. Chociaż widzę niektóre (bardzo * bardzo * rzadkie) przypadki, w których sensowne byłoby równoległe wykonywanie niektórych zadań w ramach obsługi synchronicznej. Zawsze warto przeczytać ten artykuł, zanim zabiorą Cię również kontrolki asynchroniczne: http://blog.stevensanderson.com/2010/01/25/measuring-tformance-asynchronous-controllers/ –

+0

Z pewnością każdy program C#, który używa asynchronicznego słowa kluczowego "miesza kod synchroniczny i asynchroniczny"? Używanie kontrolera Async oznacza po prostu, że granica jest w ramach. – Anthony

+0

Jeśli chodzi o "teraz jest tak łatwo uczynić metody kontrolera asynchronicznymi" - nie, jeśli masz wiele istniejących widoków za pomocą silnika widoku iskry. – Anthony

Powiązane problemy