Ninject: objeto de entidad no puede ser referenciado por múltiples instancias de IEntityChangeTracker

Estoy empezando a usar Ninject en mi aplicación de código MVC5 primero. Aquí está mi NinjectWebCommon.cs:

private static IKernel CreateKernel() { var kernel = new StandardKernel(); try { kernel.Bind<Func>().ToMethod(ctx => () => new Bootstrapper().Kernel); kernel.Bind().To(); kernel.Bind() .ToSelf() //.InSingletonScope(); .InRequestScope(); kernel.Bind() .To(); kernel.Bind() .To(); kernel.Bind() .To(); kernel.Bind() .To(); kernel.Bind() .To(); RegisterServices(kernel); return kernel; } catch { kernel.Dispose(); throw; } } 

Intenté .InSingletonScope () así como .InRequestScope (), pero aún obtengo el objetoentidad no puede ser referenciado por varias instancias del error IEntityChangeTracker ‘. Aquí está mi interfaz:

  public interface IExecutiveRepository : IDisposable { IEnumerable GetExecutives(); Executive GetExecutiveById(int executiveId); void InsertExecutive(Executive executive); void UpdateExecutive(Executive executive); void DeleteExecutive(int executiveId); void Save(); } 

Aquí está mi concreto:

  public class ExecutiveRepository : IExecutiveRepository, IDisposable { private CMSContext context; public ExecutiveRepository(CMSContext context) { this.context = context; } public IEnumerable GetExecutives() { return context.Executives.ToList(); } public Executive GetExecutiveById(int id) { return context.Executives.Find(id); } public void InsertExecutive(Executive executive) { context.Executives.Add(executive); } public void DeleteExecutive(int executiveId) { Executive executive = context.Executives.Find(executiveId); context.Executives.Remove(executive); } public void UpdateExecutive(Executive executive) { context.Entry(executive).State = EntityState.Modified; } public void Save() { context.SaveChanges(); } private bool disposed = false; protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { context.Dispose(); } } this.disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } 

Aquí está el controlador (parte superior pertinente):

  public class ExecutiveController : Controller { private IExecutiveRepository executiveRepository; private IUserRepository userRepository; private IExecutiveSectionRepository executiveSectionRepository; private IExecutiveSectionMappingRepository executiveSectionMappingRepository; private IContentRepository contentRepository; private Ninject.IKernel _kernel = new StandardKernel(); //[Inject] public ExecutiveController() { executiveRepository = _kernel.Get(); userRepository = _kernel.Get(); executiveSectionRepository = _kernel.Get(); executiveSectionMappingRepository = _kernel.Get(); contentRepository = _kernel.Get(); } ... 

No estoy seguro de lo que estoy haciendo mal, pero al agregar un nuevo ‘Ejecutivo’, me molesta … Entiendo que está intentando usar contextos separados y ese es el problema, pero no estoy seguro de cómo solucionarlo. Aparentemente, la línea en la clase NinjectWebCommon.cs:

  kernel.Bind() .ToSelf() //.InSingletonScope(); .InRequestScope(); 

Se supone que es la solución, pero no es … ¿alguna idea / sugerencia?

Debería estar utilizando el paquete Ninject.Web.Mvc si aún no lo está. Esto configura su aplicación lista para usar Ninject, además de sus enlaces. Parece que estás razonablemente familiarizado con el lado de los enlaces de lo que puedo ver en tu método CreateKernel() .

Una vez que sus enlaces estén en su lugar, no debe crear Kernels en sus controladores, esto se debe a que la biblioteca Ninject.Web.Mvc configura Ninject para crear sus controladores bajo el capó. Por lo tanto, cualquier dependencia que agregue a ellos debe resolverse automáticamente.

Por lo tanto, puede utilizar la inyección de constructor para resolver sus dependencias:

 public class ExecutiveController : Controller { private IExecutiveRepository ExecutiveRepository; private IUserRepository UserRepository; private IExecutiveSectionRepository ExecutiveSectionRepository; private IExecutiveSectionMappingRepository ExecutiveSectionMappingRepository; private IContentRepository ContentRepository; public ExecutiveController( IExecutiveRepository executiveRepository, IUserRepository userRepository, IExecutiveSectionRepository executiveSectionRepository, IExecutiveSectionMappingRepository executiveSectionMappingRepository, IContentRepository contentRepository) { // Set the field values this.ExecutiveRepository = executiveRepository, this.UserRepository = userRepository, this.ExecutiveSectionRepository = executiveSectionRepository, this.ExecutiveSectionMappingRepository = executiveSectionMappingRepository, this.ContentRepository = contentRepository; } public ActionResult Index(int id) { // Use one of your dependencies... var executive = this.executiveRepository.GetExecutiveById(id); } } 

O puede usar el atributo [Inject] que tiene el mismo efecto:

 public class ExecutiveController : Controller { [Inject] public IExecutiveRepository executiveRepository { get; set; } [Inject] public IUserRepository userRepository { get; set; } [Inject] public IExecutiveSectionRepository executiveSectionRepository { get; set; } [Inject] public IExecutiveSectionMappingRepository executiveSectionMappingRepository { get; set; } [Inject] public IContentRepository contentRepository { get; set; } public ExecutiveController() { } public ActionResult Index(int id) { // Use one of your dependencies... var executive = this.executiveRepository.GetExecutiveById(id); } } 

Estás creando un núcleo por controlador.

InRequestScope solo garantiza una instancia por solicitud por kernel .

Por lo tanto, debe adaptar la configuración del kernel para que solo haya un kernel por aplicación web. Ver:

  • Ninject.Web.Mvc
  • Tutorial
  • Youtube

Esto puede no responder a la pregunta. Pero tiendo a usar el IDbContextFactory que EF le proporciona y hacer algo como esto:

 public interface IDefaultContextFactory : IDbContextFactory {} public class DefaultContextFactory : IDefaultContextFactory { private readonly Lazy lazyContext = new Lazy(() => new CMSContext()); public CMSContext Create() { return lazyContext.Value; } } 

Luego simplemente lo unes, y cuando necesites el contexto, puedes hacer algo como esto:

 public class ExecutiveRepository : IExecutiveRepository, IDisposable { private readonly CMSContext context; public ExecutiveRepository(IDefaultContextFactory contextFactory) { this.context = contextFactory.Create(); } } 

Creo que @BatteryBackupUnit es correcto, también consideraría usar el patrón anterior para contextos.