注入DbContext InRequestScope不会返回相同的对象实例

时间:2014-05-04 12:38:12

标签: asp.net-mvc-4 dependency-injection entity-framework-5 ninject

问题:

我在我的web应用程序中使用Ninject作为IoC-Framework。我试图将Entity-Framework DbContext类注入我的代码中的几个类。我想按要求共享一个对象实例。所以我尝试使用ninject的InRequestScope方法。问题是实例未共享。相反,我总是得到一个新的DbContext实例。

代码:

首先我实现DbContext类:

public class BudgetContext : DbContext, IUnitOfWork
{
    public BudgetContext() : base("DefaultConnection") 
    {
        Database.SetInitializer<BudgetContext>(new DropCreateDatabaseIfModelChanges<BudgetContext>());
    }

    public DbSet<Expense> Expenses { get; set; }

    public int Commit()
    {
        return SaveChanges();
    }
}

我想在两个不同的地方注入BudgetContext(我的DbContext和UnitOfWork):

public class UnitOfWorkAttribute : ActionFilterAttribute
{
    [Inject]
    public IUnitOfWork UnitOfWork { get; set; }  // injecting DbContext here (1)

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);
        if (filterContext.Exception == null)
        {
            UnitOfWork.Commit();
        }
    }
}

public class ExpenseRepository : IExpenseRepository
{
    private readonly BudgetContext context;

    public ExpenseRepository(IUnitOfWork context)  // injecting DbContext here (2)
    {
        this.context = (BudgetContext)context;
    }

    public void Add(Expense expense)
    {
        context.Expenses.Add(expense);
    }
}

两个注入的DbContext类都应该是一个请求的相同对象实例。 NinjectWebCommon.cs中的我的Ninject配置如下所示:

...
private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<IUnitOfWork>().To<BudgetContext>().InRequestScope();
    kernel.Bind<IExpenseRepository>().To<ExpenseRepository>();
    // ...
    kernel.Bind<ExpensesController>().To<ExpensesController>();
}    
... 

我是否正确配置了Ninject-Framework?我错过了什么? 谢谢你帮助我。

**更新:**

我已经实现了一个工厂来创建我的UnitOfWork(基本上是我的DbContext类)。工厂的实施如下:

public class UnitOfWorkFactory : IUnitOfWorkFactory
{
    private IUnitOfWork unitOfWork;

    public IUnitOfWork Get()
    {
        if (unitOfWork == null)
            unitOfWork = new BudgetContext();
        return unitOfWork;
    }
}

在Ninject中,我对新工厂使用以下配置:

kernel.Bind<IUnitOfWorkFactory>().To<UnitOfWorkFactory>().InRequestScope();

在我的属性中,我这样注入:

[Inject]
public IUnitOfWorkFactory UnitOfWorkFactory{ get; set; } 
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
    base.OnActionExecuted(filterContext);
    if (filterContext.Exception == null)
    {
        var unitOfWork = UnitOfWorkFactory.Get();
        unitOfWork.Commit();
    }
}

不幸的是我没有成功。我的DbContext在到达属性类后总是被重置。

3 个答案:

答案 0 :(得分:2)

过滤器由MVC框架缓存。不要使用InRequest作用域引用,而是注入工厂。

https://github.com/ninject/ninject.web.mvc/wiki/Filters-and-Scoped

答案 1 :(得分:2)

感谢@Remo Gloor我发现我的属性一定有问题。所以我改变了我的实现并实现了接口IActionFilter,而不是继承ActionFilterAttribute类。现在我可以禁止我的DbContext InRequest范围。

属性:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class UnitOfWorkAttribute : Attribute { }
public class UnitOfWorkFilter : IActionFilter
{
    private readonly IUnitOfWork unitOfWork;

    public UnitOfWorkFilter(IUnitOfWork unitOfWork)
    {
        this.unitOfWork = unitOfWork;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext) { }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Exception == null)
        {
            unitOfWork.Commit();
        }
    }

}

绑定:

kernel.Bind<IUnitOfWork>().To<BudgetContext>().InRequestScope();
kernel.BindFilter<UnitOfWorkFilter>(FilterScope.Action, 0).WhenActionMethodHas<UnitOfWorkAttribute>();

答案 2 :(得分:1)

你需要三个包

Ninject
Ninject.Web
Ninject.Web.Common

然后你应该在NinjectHttpModuleNinject.Web.Common

两个库中注册Ninject.Web
public static void Start()
{
    DynamicModuleUtility.RegisterModule(typeof (OnePerRequestHttpModule));
    DynamicModuleUtility.RegisterModule(typeof (Ninject.Web.Common.NinjectHttpModule));
    DynamicModuleUtility.RegisterModule(typeof (Ninject.Web.NinjectHttpModule));
    bootstrapper.Initialize(createKernel);
}

我不确定您是否需要添加Bind<UnitOfWorkAttribute>().ToSelf()