简体   繁体   中英

DbContext has been disposed in custom RoleProvider

I have a problem with my DbContext being disposed when used in my CustomRoleProvider .

I've setup my bindings like to:

kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
kernel.Bind(typeof(IGenericRepository<>)).To(typeof(GenericRepository<>)).InRequestScope();
kernel.Bind<MyContext>().ToSelf().InRequestScope();

I'm using this NuGet package Ninject.MVC5 v3.2.1.0 so Ninject is set as the primary DependencyResolver in MVC. Hence why I'm able to do this DependencyResolver.Current.GetService<IGenericRepository<User>>() .

But for some reason the context is disposed.

I tried adding this binding to my setup:

kernel.Bind<MyContext>().ToSelf().WhenInjectedInto<RoleProvider>();

But that doesn't work either. I also tried injecting via property injection

[Inject]
public IGenericRepository<User> UserRepository { get; set; };

But that just results in a lot of others problems I wasn't able to solve (yet).

As far as I can tell from the error message it's here the is problem triggered from.

public abstract class BaseController : Controller
{
    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        User.IsInRole("Admin"); // calls my CustomRoleProvider
        base.OnActionExecuting(filterContext);
    }
}

CustomRoleProvider implementation

public class CustomRoleProvider : RoleProvider
{
    private readonly IGenericRepository<User> _userRepository;

    public CustomRoleProvider()
    {
        // using Service Locator (anti pattern)
        // cause MVC do not support DI in role providers (yet)
        _userRepository = DependencyResolver.Current.GetService<IGenericRepository<User>>();
    }

    public override bool IsUserInRole(string username, string roleName)
    {
        var user = _userRepository.AsQueryable().Where(x => x.Username == username && x.Role.Name == roleName); // dbcontext is here disposed...
        return user.Any();
    }

    public override string[] GetRolesForUser(string username)
    {
        var user = _userRepository.AsQueryable().Where(x => x.Username == username).Select(x => x.Role.Name); // dbcontext is here disposed...
        return user.ToArray();
    }

    // omitted...
}

IGenericRepository<T> implementation

public class GenericRepository<T> : IGenericRepository<T>
    where T : class
{
    private readonly MyContext _context;
    private readonly DbSet<T> _dbSet;

    public GenericRepository(MyContext context)
    {
        _context = context;
        _dbSet = context.Set<T>();
    }

    public IQueryable<T> AsQueryable()
    {
        return _dbSet.AsQueryable();
    }
}

Error message

[InvalidOperationException: The operation cannot be completed because the DbContext has been disposed.]
   System.Data.Entity.Internal.InternalContext.CheckContextNotDisposed() +34
   System.Data.Entity.Internal.LazyInternalContext.InitializeContext() +30
   System.Data.Entity.Internal.InternalContext.Initialize() +21
   System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) +20
   System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() +79
   System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext() +21
   System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider() +64
   System.Linq.Queryable.Where(IQueryable`1 source, Expression`1 predicate) +81
   Presentation.Web.Providers.CustomRoleProvider.GetRolesForUser(String username) in ~\Application\Presentation.Web\Providers\CustomRoleProvider.cs:38
   System.Web.Security.RolePrincipal.IsInRole(String role) +183
   Presentation.Web.Controllers.BaseController.OnActionExecuting(ActionExecutingContext filterContext) in ~\Application\Presentation.Web\Controllers\BaseController.cs:27
   ...

So apparently the life cycle of RoleProvider is the entire lifespan of the MVC application. (can't remember where I read it)

So have to resolve the dependency in each method :(

public class CustomRoleProvider : RoleProvider
{
    public override bool IsUserInRole(string username, string roleName)
    {
        var userRepository = DependencyResolver.Current.GetService<IGenericRepository<User>>();
        var user = userRepository .AsQueryable().Where(x => x.Username == username && x.Role.Name == roleName); // dbcontext is here disposed...
        return user.Any();
    }

    public override string[] GetRolesForUser(string username)
    {
        var userRepository = DependencyResolver.Current.GetService<IGenericRepository<User>>();
        var user = userRepository .AsQueryable().Where(x => x.Username == username).Select(x => x.Role.Name); // dbcontext is here disposed...
        return user.ToArray();
    }

    // omitted...
}

Don't understand why this didn't work then

kernel.Bind<MyContext>().ToSelf().WhenInjectedInto<RoleProvider>();

I even tried adding InSingletonScope

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM