8

Tengo un proyecto MVC3 que usa Ninject, Entity Framework y el patrón de Unidad de Trabajo con una capa de Servicio.Problema Ninject Scope con Tareas/Hilos

Mi clase AsyncService tiene una función que inicia una tarea en segundo plano que, por ejemplo, agrega usuarios al repositorio de usuario. Mi problema actual es que la tarea solo se ejecuta correctamente durante unos segundos antes de que me llegue el error de que se ha eliminado el DbContext. Mi contexto de base de datos, que se inyecta con InRequestScope() de Ninject, parece estar siendo eliminado, ya que InRequestScope() lo vincula a HttpContext.

He leído sobre InThreadScope(), pero no estoy seguro de cómo implementarlo correctamente en mi proyecto MVC.

Mi pregunta es: ¿Cuál es la forma correcta de usar Ninject en mi tarea?

public class AsyncService 
{ 
    private CancellationTokenSource cancellationTokenSource; 
    private IUnitOfWork _uow; 
    public AsyncService(IUnitOfWork uow) 
    { 
     _uow = uow; 
    } 
    public void AsyncStartActivity(Activity activity) 
    { 
    ...snip... 
     this.cancellationTokenSource = new CancellationTokenSource(); 
     var cancellationToken = this.cancellationTokenSource.Token; 
     var task = Task.Factory.StartNew(() => 
      { 
       foreach (var user in activity.UserList) 
       { 
        this._uow.UserRepository.Add(new User() {UserID = user}); 
       } 
       this._uow.Save(); 
      }, cancellationToken); 
    ...snip... 
    } 
} 

Respuesta

5

InRequestScope 'objetos D son Dispose d en el extremo de un pedido, por lo que no se puede utilizar en este caso. InThreadScope tampoco encaja, ya que reutilizaría la UoW para varias tareas.

Lo que puedes hacer es declarar tu AsyncService como el Objeto Scoping para todos los objetos dentro utilizando la extensión NamedScope.

Ver http://www.planetgeek.ch/2010/12/08/how-to-use-the-additional-ninject-scopes-of-namedscope/

+3

¿Existe un código de ejemplo? Jason, ¿dónde puedes lograr que funcione? Estoy teniendo el mismo problema y seguir el enlace no me ayudó. –

+0

Tengo este mismo problema, me gustaría ver algún código de muestra para este escenario. –

0

Ésta es una solución sucia que he utilizado en el pasado usando el plugin ChildKernel (creo ámbito con nombre sería mucho más limpio). Básicamente, creo un kernel secundario y alcance todo lo relacionado con la UoW como singleton en el kernel secundario. Luego creo un kernel secundario nuevo para cada Tarea, manejo la UoW, y commit o rollback.

IAsyncTask es una interfaz con 1 método, Execute()

private Task void ExecuteTask<T>() where T:IAsyncTask 
{ 

     var task = Task.Factory.StartNew(() => 
              { 
      var taskKernel = _kernel.Get<ChildKernel>(); 
      var uow = taskKernel.Get<IUnitOfWork>(); 
      var asyncTask = taskKernel.Get<T>(); 

      try 
      { 
       uow.Begin(); 
       asyncTask.Execute(); 
       uow.Commit(); 
      } 
      catch (Exception ex) 
      { 
       uow.Rollback(); 
       //log it, whatever else you want to do 
      } 
      finally 
      { 
       uow.Dispose(); 
       taskKernel.Dispose(); 
      } 
     }); 
     return task; 
}