Пользовательское членство + Ninject + InRequestScope = ObjectContext экземпляр был удален - PullRequest
3 голосов
/ 10 декабря 2011

Экземпляр ObjectContext был размещен в InRequestScope!

Я пытался решить проблему в течение нескольких часов в Интернете.

Экземпляр ObjectContext был удален и больше не может использоваться для операций, требующих подключения.

Я нашел несколько статей и сообщений с такой же проблемой, как это , это , это и это

Я перепробовал все способы, но всегда возникает ошибка.


Код

Контекст

public class BindSolutionContext : DbContext
{
    public DbSet<Project> Projects { get; set; }
    public DbSet<User> Users { get; set; }
    public DbSet<Role> Roles { get; set; }
    public DbSet<Address> Addresses { get; set; }
    public DbSet<ProjectImage> ProjectImages { get; set; }

    public BindSolutionContext()
        : base("name=Data")
    {
        Database.SetInitializer(new DropCreateDatabaseIfModelChanges<BindSolutionContext>());
    }
}

Ninject

kernel.Bind<BindSolutionContext>().ToSelf().InRequestScope();

kernel.Bind<IProjectRepository>().To<ProjectRepository>().InRequestScope();
kernel.Bind<IUserRepository>().To<UserRepository>().InRequestScope();
kernel.Bind<IRoleRepository>().To<RoleRepository>().InRequestScope();
kernel.Bind<IAddressRepository>().To<AddressRepository>().InRequestScope();
kernel.Bind<IProjectImageRepository>().To<ProjectImageRepository>().InRequestScope();

Репозиторий

public class ProjectRepository : IProjectRepository
{
    private readonly BindSolutionContext _context;

    public ProjectRepository(BindSolutionContext context)
    {
        _context = context;
    }

    public IQueryable<Project> Query(params Expression<Func<Project, object>>[] includeProperties)
    {
        return includeProperties.Aggregate<Expression<Func<Project, object>>,
            IQueryable<Project>>(_context.Projects, (current, includeProperty) => current.Include(includeProperty));
    }

    public IQueryable<Project> Query(int pageIndex, int pageSize, params Expression<Func<Project, object>>[] includeProperties)
    {
        return includeProperties.Aggregate<Expression<Func<Project, object>>,
            IQueryable<Project>>(_context.Projects, (current, includeProperty) => current.Include(includeProperty)).OrderBy(p => p.Name).Skip(pageIndex).Take(pageSize);
    }

    //Rest of Implementation
}

Для ProjectImageRepository, AddressRepository, RoleRepository и UserRepository реализация следует той же модели!

public class BindUserProvider : MembershipProvider
{
    [Inject]
    public IUserService UserService { get; set; }

    //Rest of implementation
}


public class BindRoleProvider : RoleProvider
{
    private IRoleService _roleServ;
    private IRoleService RoleServ { get { return _roleServ ?? (_roleServ = DependencyResolver.Current.GetService<IRoleService>()); } }

    private IUserService _userServ;
    private IUserService UserServ { get { return _userServ ?? (_userServ = DependencyResolver.Current.GetService<IUserService>()); } }

    //Rest of implementation
}

Поскольку область действия - запрос, Ninject должен избавиться от объекта в конце запроса. Но в некоторых ситуациях удаление происходит до завершения запроса.

Попытка

Я не уверен, связана ли проблема с пользовательским членством, но провел некоторое тестирование. следующим образом:

Ninject

kernel.Bind<BindSolutionContext>().ToSelf().InTransientScope();

kernel.Bind<IProjectRepository>().To<ProjectRepository>().InSingletonScope();
kernel.Bind<IUserRepository>().To<UserRepository>().InSingletonScope();
kernel.Bind<IRoleRepository>().To<RoleRepository>().InSingletonScope();
kernel.Bind<IAddressRepository>().To<AddressRepository>().InSingletonScope();
kernel.Bind<IProjectImageRepository>().To<ProjectImageRepository>().InSingletonScope();

Так что больше нет ошибки!

Но возникает другая проблема! Поскольку repository и context являются одноэлементными объектами, они не обновляются.

Например, если я зарегистрирую новый адрес для проекта, коллекция project.Addresses не будет обновлена!

Примечание: Адрес зарегистрирован в базе данных без проблем!

Ответы [ 3 ]

5 голосов
/ 11 декабря 2011

Членство и RoleProviders имеют более длительный жизненный цикл, чем запрос. Объекты никогда не должны зависеть от более коротких объектов (если они не были созданы и уничтожены локально во время выполнения метода), поскольку в конечном итоге они ссылаются на удаленные объекты.

Поскольку вы хотите, чтобы новый контекстный запрос foreach не содержал кэшированные объекты, вы не должны внедрять контекст в репозитории, а передавать его извне с помощью вызова метода и создавать его в службах или поставщиках с использованием фабрики.

1 голос
/ 16 мая 2012

Чтобы избежать этого исключения, используйте DependencyResolver.Current.GetService () вместо внедряемых свойств в классах с длинным жизненным циклом (фильтры действий, поставщики членства и т. Д.).Этот подход не подходит для тестирования, но позволяет использовать экземпляр контекста данных текущего http-запроса при использовании InRequestScope ().

0 голосов
/ 25 августа 2012

Я удалил внедрение зависимостей и сделал это так ...

    public class CustomRoleProvider:RoleProvider
    {
        private IGroupService _groupService;
        private MyDbContext context;

         public CustomRoleProvider()
         {
              //  _groupService = DependencyResolver.Current.GetService<IGroupService>();
              context = new MyDbContext();
             _groupService = new GroupService(new GroupRepository(context), new AccountRepository(context));

         }

    }
...