2012-07-29 3 views
5

Il mio progetto è strutturato da servizi e repository (tutti i repository condividono il contesto db). In uno dei miei livelli di servizio, ho un metodo asincrono che scrive nel database usando un repository. La richiesta web terminerà e eliminerà il contesto prima che questo metodo possa essere utilizzato. Ho provato a capire NamedScopes come indicato in questo answer. Non riesco ancora a capire come implementarlo. Mostrerò come è strutturato il mio progetto e spero che qualcuno possa aiutarmi a livello di codice.NamedScopes Associazioni Ninject e asincrona (threading)

Binding

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 utilizza iniezione costruttore

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

Procedimento dentro il mio 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 fa uso di accountRepository. Per favore dimmi se sono necessarie ulteriori informazioni. Per favore aiutatemi con il problema del threading, se NamedScopes è la soluzione, come posso implementarla nel mio caso?

Fondamentalmente, un processo in background è in esecuzione e sta utilizzando un contesto che viene eliminato da ninject a causa dell'ambito della richiesta.

+1

Potresti per favore elaborare quello che vuoi ottenere? Vuoi semplicemente caricare alcuni dati nel tuo metodo SomeMethodAsync in modo asincrono o vuoi eseguire in background alcune informazioni in un lavoro come moda? Uno dei problemi principali nella progettazione è che stai iniziando direttamente una nuova attività in SomeMethodAsync. L'avvio di una nuova attività non promette l'esecuzione dell'attività.Le attività potrebbero essere eseguite dopo che la richiesta è terminata e quindi ninject avrà già disposto nell'ambito della richiesta. Se si utilizza AsyncController, l'attività dovrebbe essere registrata su di essa. Ma l'API non dovrebbe avviarlo –

+0

@DanielMarbach Questo è il mio problema, il compito può essere eseguita dopo le estremità di richiesta e dispone Ninject del contesto. Devo dire che devo aspettare. Non sono sicuro di come si faccia. –

+0

@DanielMarbach, cosa intendi con cui l'API non dovrebbe avviarlo? –

risposta

6

È necessario tenere presente che l'esecuzione di thread in background può causare molti problemi. IIS può decidere di riciclare il pool di applicazioni in qualsiasi momento che interrompe immediatamente il thread (o che in alcuni casi non viene eseguito) lasciando l'applicazione in uno stato incoerente.

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

Il più semplice e meno errori wayto incline eseguire operazioni asincroni è quello di implementare un servizio di Windows e delegare quelle operazioni asincrone al servizio delle finestre per esempio usando MSMQ.

Se si desidera continuare a leggere, leggere HostingEnvironment.RegisterObject e IRegisteredObject per evitare queste situazioni incoerenti.

La parte di Ninject è abbastanza semplice. Crea semplicemente una classe di processore di lavoro, ad es. MyJobProcessor prendendo tutte le dipendenze richieste per eseguire l'attività. Dovrebbe implementare INotifyWhenDisposed. Il modo più semplice per farlo è derivare da DisposeNotifyingObject.

Iniettare questo processore sul controller e lasciare che l'attività avviarlo e disporlo quando ha finito il suo lavoro.

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

Specificare che è lo scopo delle sue dipendenze.

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

Grazie, per quanto riguarda utilizzando un servizio di Windows, sarebbe adatto per situazioni come la registrazione (utente accede a, accedo esso) o l'invio email (modelli)? Questi comportamenti rendono l'azione più lunga per il ritorno, motivo per cui mi piacerebbe farli in un task in background. –

+0

@Lolcoder La domanda è se puoi permetterti di perdere questi dati. Per esempio. Se il server si ricicla a causa di un errore, puoi permetterti di non avere il registro? Oppure puoi vivere in una situazione in cui l'email non viene inviata? Anche la registrazione e l'invio di e-mail di solito non hanno bisogno di dipendenze. Dovresti anche controllare quanto prestazioni ottieni davvero. Anche la creazione e l'avvio di un'attività richiedono del tempo. –

+0

Se uno di questi è stato fatto in modo sincrono nella richiesta e il pool riciclato non fallirebbe anche loro? – solipsicle