1

I have a problem with Ninject in a MVC project using Owin.

I have a generic class for UnitOfWork that is not specific to my project :

public class UnitOfWork : IUnitOfWork
{
    public UnitOfWork(DbContext context)
    {...}
}

I define two repositories using my custom DbContext :

public UserRepository : IUserRepository
{
    public UserRepository(MyEntities context)
    {...}
}
public OrderRepository : IOrderRepository
{
    public OrderRepository(MyEntities context)
    {...}
}

Then I have a ApiController which use the unit of work and the repositories.

public OrderController : ApiController
{
    public OrderController(IUnitOfWork uow, IUserRepository userRepository, IOrderRepository orderRepository)
    {...}
}

I configure my Ninject kernel within a module. My bindings are with a request scope.

public class MyModule : Ninject.Modules.NinjectModule
{
    public override void Load()
    {
        // Bind all the repositories
        this.Bind(x =>
            x.FromAssembliesMatching("*.Repositories")
                .SelectAllClasses()
                .BindDefaultInterface()
                .Configure(c => c.InRequestScope()));

        // Bind the DbContext of the application
        this.Bind<MyEntities>()
            .ToSelf()
            .InRequestScope();

        // To bind the UnitOfWork, I need to specify the real DbContext to use. For that I use a callback which provide argument to constructor :
        this.Bind<IUnitOfWork>()
            .To<UnitOfWork>()
            .InRequestScope()
            .WithConstructorArgument("context", GetContext);
    }

    private Object GetContext(IContext context, ITarget target)
    {
        IResolutionRoot resolver;
        ActivationBlock scope;

        scope = context.Request.GetScope() as ActivationBlock;
        resolver = scope ?? (IResolutionRoot)context.Kernel;

        var o = resolver.Get<MyEntities>();
        var o2 = resolver.Get<MyEntities>();
        var same = Object.ReferenceEquals(o, o2);
        return o;
    }
}

Then I activate Ninject with Owin like this in the Startup class :

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ...
        app.UseNinjectMiddleware(Startup.CreateKernel);

        var config = new HttpConfiguration();
        ...
        app.UseNinjectWebApi(config);
    }

    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Load(new MyModule());
        return kernel;
    }
}

It seems good but there is a big problem. The repositories share the same DbContext, but the DbContext in the UnitOfWork is a different instance. In the function GetContext, the scope is always null, so the MyContext instance is retrieved from the kernel. The boolean variable same is always false. The problem is here. The Get function of the kernel return a new instance, instead of the instance of the request scope.

gentiane
  • 6,715
  • 3
  • 23
  • 34

1 Answers1

0

Not sure if you still need this... but you can bind the dbcontext to self and then ask for it when you want to use it.

        Bind<ApplicationDbContext>().ToSelf();
        Bind<IUserStoreGuid<User>>().To<UserStoreGuid<User>>().WithConstructorArgument("context", Kernel.GetService(typeof(ApplicationDbContext)));

Although the connection string in the app is called "DefautConnection", you need to use "context" because that is how it is called in the constructor argument. I got this from here

alikuli
  • 526
  • 6
  • 18