2014-07-18 14 views
7

Próbuję zaimplementować funkcję, w której jest procedura składowana na serwerze SQL, która musi zostać wywołana z aplikacji ASP MVC i przetworzona w tle (to może potrwać długo, ponieważ wywołuje zdalnie inną procedurę składowaną, aby przetworzyć plik Excela przechowywany na serwerze). Jednak odpowiedź ostatniego żądania HTTP powinna zostać zwrócona do klienta, aby interfejs użytkownika nie czekał na przetworzenie.Uruchamiaj zadanie w tle, ale zwróć odpowiedź klientowi w aplikacji WWW ASP MVC

Próbowałem na wiele różnych sposobów, ale interfejs użytkownika nadal nie reaguje od razu.

Próbowałem BackgroundWorker ale to nie pozwalając główny wątek z odpowiedzią z powrotem do klienta, aż do jego Sporządzono przetwarzania również próbowałem:

Thread.QueueUserWorkItem(delegate { //method which performs stored procedure calls// 
}); 

nie Nadal powrocie odpowiedź i HttpContext.Current niedostępny w wątku tła.

Może istnieje sposób, aby rozpocząć przetwarzanie w tle, pozwalając wstrzymać go na główny wątek, aby powrócić odpowiedź na przeglądarce, a następnie wznowić wątek tła, aby wszystkie z przechowywanych przetwarzanie wywołań procedur?

Czy brakuje mi czegoś?

Czy ktoś mógłby podać pomysł, jak rozwiązać ten problem? Byłoby to bardzo doceniane.

+1

Odradzam próby trzymania się czegoś takiego jak kontekst HTTP. Oczywiście potrzebujesz czegoś z tego, więc przekaż cokolwiek to jest do wątku w tle jako stan wątku i wykonaj przetwarzanie. Jest to nie tylko prostsze, ale dzięki zdefiniowaniu tego, czego potrzebuje twój wątek, lepiej zdefiniuj jego cel. –

Odpowiedz

6

Co mi się udało i działa dobrze w moim przypadku. Nie jestem pewien co do wydajności, ale działa idealnie. Tak więc kod wywołujący procedurę przechowywaną umieszczam osobny wątek, tak że główny wątek jest kończony, podczas gdy przetwarzanie wyłącza wywoływanie w tle odbywa się w osobnym wątku i kończy się pomyślnie po pewnym czasie. W tym samym czasie interfejs użytkownika jest dostępny, aby użytkownik mógł wykonać inne żądanie, które również zostanie przetworzone w ten sam sposób. Przetestowałem trzy wnioski. Jedno po drugim nakładające się, co oznacza, że ​​podczas przetwarzania pierwszego wniosku w tle przesłałem kolejną i jeszcze jedną. Interfejs użytkownika natychmiast reagował i cała praca została wykonana.

// ...main thread is working here 
    //put a call to stored procedure on a separate thread 
    Thread t = new Thread(()=> { 
     //call stored procedure which will run longer time since it calls another remote stored procedure and 
     //waits until it's done processing 
    }); 
    t.Start(); 

    // ...main thread continue to work here and finishes the request so it looks for user as the response is coming right away, all other stuff is being processed on that new thread so user even doesn't suspect 
+0

jest błąd "nie można niejawnie przekonwertować typu void na wątek" –

2

zacytuję Stephan Clearych great article:

Podczas korzystania asynchronicznie po stronie serwera (na przykład z ApiController), to można traktować każdego żądania sieci Web jako operacja asynchroniczna. Ale kiedy wydajność, wystarczy tylko poddać się puli wątków serwera WWW, a nie do klienta. HTTP zezwala tylko na jedną odpowiedź, więc odpowiedź może zostać wysłana dopiero po pełnym wypełnieniu żądania.

Zasadniczo nie jest to zgodne z protokołem HTTP, w którym każde żądanie ma tylko jedną odpowiedź.

ten można osiągnąć za pomocą wielu połączeń do usługi ASP.NET, gdy wniosek niezwłocznie zwraca unikalny identyfikator, który klient może zapytać wielokrotnie dla postępu. Możesz zajrzeć do SignalR, aby uzyskać pomoc przy takiej implementacji:

Co to jest funkcja SignalR i "sieć w czasie rzeczywistym"? Jest to zdolność do Twojego po stronie serwera zawartości kod Prześlij na podłączonych klientów, jak to dzieje się w czasie rzeczywistym.

0

Jeśli odpowiedź klientowi nie zależy od wyniku procesu w tle (tzn uruchomić proces w tle i nie mają UI czeka na niego), a następnie można użyć Revalee (narzędzie open-source), aby wykonać zadanie tła.

UI zwróci tę drogę ...

public class ForegroundController : Controller 
{ 
    public ActionResult InitiateBackgroundTask() 
    { 
    // The absolute URL that will be requested on the callback. 
    var callbackUri = new Uri("http://localhost/BackgroundTask/Callback"); 

    // The information that will be needed to initiate the background task. 
    object state = "Any object"; 

    this.CallbackNowAsync(callbackUri, state) 

    // ... your controller will now return a response to the browser 
    return View(); 
    } 
} 

praca Tło zostanie wykonany w tym kontrolerze ...

public class BackgroundTaskController : Controller 
{ 
    [AllowAnonymous] 
    [HttpPost] 
    [CallbackAction] 
    public ActionResult Callback(Guid callbackId, object state) 
    { 
    // Perform the background work 

    // ... insert your background task code here ... 

    // Return a status code back to the Revalee Service. 
    return new HttpStatusCodeResult(HttpStatusCode.OK); 
    } 
} 

Revalee Project Site

2

Jest part1 i part2 artykuł Dino Esposito nakreśla sposób, aby osiągnąć swój odpytywanie pomocą zegara po stronie klienta i działania regulatora. Zasadniczo serializuje się dostęp do metody kontrolera pracownika postępu, która zwraca status zadania i dane zakończenia. Jednak może być trochę rozmowny, jeśli zamierzasz wykonywać tylko jeden lub dwa długie procesy.

Powiązane problemy