2012-07-29 12 views
5

Mój projekt składa się z usług i repozytoriów (wszystkie repozytoria współużytkują kontekst db). W jednej z moich warstw usług mam asynchroniczną metodę, która zapisuje do bazy danych przy użyciu repozytorium. Żądanie internetowe zakończy i pozbędzie się kontekstu, zanim ta metoda będzie mogła go użyć. Próbowałem zrozumieć NamedScopes, jak podano w tym answer. Wciąż nie mogę zrozumieć, jak to wdrożyć. Pokażę, jak zbudowany jest mój projekt i mam nadzieję, że ktoś może mi pomóc na poziomie kodu.Wiązania NamedScopes i asynchronizacja (gwintowanie)

Wiązania

private static void RegisterServices(IKernel kernel) 
    { 
     //dbcontext 
     kernel.Bind<EntityDatabaseContext>().ToMethod(context => new EntityDatabaseContext()).InRequestScope(); 

     //unit of work 
     kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope(); 

     //repositories 
     kernel.Bind<IRepository<Account>>().To<Repository<Account>>().InRequestScope(); 

     //services 
     kernel.Bind<IAuthenticationService>().To<AuthenticationService>().InRequestScope(); 
    } 

AuthenticationService wykorzystuje konstruktora wtrysku

public AuthenticationService(UnitOfWork unitOfWork, IRepository<Account> accountRepository){} 

Sposób w moim AuthenticationService

//this is a background process 
    public Task SomeMethodAsync(string text) 
    { 
     //spin it off into a new task 
     return Task.Factory.StartNew(() => SomeMethod(text)); 
    } 

SomeMethod korzysta z accountRepository. Proszę mi powiedzieć, czy potrzebne są już jakieś informacje. Proszę pomóż mi w kwestii wątków, jeśli NamedScopes jest rozwiązaniem, w jaki sposób mogę go wdrożyć w moim przypadku?

Zasadniczo proces w tle jest wykonywany i korzysta z kontekstu, który jest usuwany przez ninject ze względu na zakres żądania.

+1

Mógłbyś proszę wyjaśnić, co chcesz osiągnąć? Czy chcesz po prostu załadować niektóre dane w metodzie SomeMethodAsync asynchronicznie lub chcesz, aby w tle przetwarzane były pewne informacje w pracy podobnej do mody? Jednym z głównych problemów w projekcie jest to, że zaczynasz bezpośrednio nowe zadanie w SomeMethodAsync. Uruchomienie nowego zadania nie daje żadnej obietnicy dotyczącej wykonania zadania.Zadania mogą być wykonywane po zakończeniu twojego żądania, a następnie ninject będzie już umieszczony w zasięgu żądania. Jeśli używasz AsyncController, zadanie powinno zostać na nim zarejestrowane. Ale API nie powinien go uruchamiać. –

+0

@DanielMarbach To jest mój problem, zadanie może zostać wykonane po tym, jak żądanie się zakończy, a ninject porzuca kontekst. Muszę powiedzieć niniemu, żeby zaczekał. Nie wiem, jak to zrobić. –

+0

@ DanielMarbach co masz na myśli mówiąc, że interfejs API nie powinien go uruchamiać? –

Odpowiedz

6

Należy pamiętać, że uruchamianie wątków w tle może powodować wiele problemów. Usługi IIS mogą zdecydować się na odtworzenie puli aplikacji w dowolnym momencie, co spowoduje natychmiastowe zakończenie działania wątku (lub w niektórych przypadkach nie zostanie wykonane), pozostawiając aplikację niespójną.

http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx

Najprostszym i najmniej podatne na błędy wayto uruchomić operacje Asyncronous jest wdrożenie usługi Windows i przekazać te operacje async do usługi Windows np za pomocą MSMQ.

Jeśli nadal chcesz przejść dalej, przeczytaj o numerach HostingEnvironment.RegisterObject i IRegisteredObject, aby zapobiec tym niespójnym sytuacjom.

Część Ninject jest dość łatwa. Po prostu utwórz klasę procesorów zadań, np. MyJobProcessor podejmowanie wszystkich wymaganych zależności w celu wykonania zadania. Powinien wdrożyć INotifyWhenDisposed. Najprostszym sposobem jest uzyskanie wersji DisposeNotifyingObject.

public class MyJobProcessor : DisposeNotifyingObject, IRegisteredObject 
{ 
    public void Execute() { ... } 
    public void Stop(bool immediate) { ... } 
} 

Wstrzyknij ten procesor do kontrolera i pozwól, aby zadanie zostało uruchomione i wyrzuć je po zakończeniu pracy.

Task.Factory.StartNew(() => 
    { 
     try 
     { 
      processor.Execute(); 
     } 
     finally 
     { 
      processor.Dispose); 
     } 
    }); 

Należy określić, że jest to zakres zależności.

Bind<MyJobProcessor>().ToSelf().Named("MyJobProcessor").DefinesNamedScope("MyJobProcessorScope"); 
Bind<IUnitOfWork>().To<UnitOfWork>().WhenAnyAnchestorNamed("MyJobProcessor").InNamedScope("MyJobProcessorScope"); 
+0

Dziękuję, jeśli chodzi o korzystanie z usługi Windows, czy byłby odpowiedni dla sytuacji takich jak logowanie (logi użytkownika, loguję się) lub wysyłanie e-maile (szablony)? Te zachowania powodują, że działanie zabiera więcej czasu, dlatego chciałbym, aby były wykonywane w tle. –

+0

@Lolcoder Pytanie brzmi, czy możesz pozwolić sobie na utratę tych danych. Na przykład. Jeśli serwer jest poddawany recyklingowi z powodu jakiegoś błędu, możesz pozwolić sobie na brak logu? Czy możesz żyć z sytuacją, w której e-mail nie jest wysyłany? Również logowanie i wysyłanie wiadomości e-mail zazwyczaj nie wymaga zależności. Powinieneś również sprawdzić, ile naprawdę zyskujesz. Tworzenie i uruchamianie zadania zajmuje również trochę czasu. –

+0

Jeśli któryś z nich został wykonany synchronicznie we wniosku, a pula poddana recyklingowi również się nie powiedzie? – solipsicle

Powiązane problemy