问题:
我在我的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在到达属性类后总是被重置。
答案 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
然后你应该在NinjectHttpModule
和Ninject.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()