有关使用Ninject的问题

我经历了推荐的步骤来添加Ninject到我的MVC应用程序。 我添加了一个DbContext参数给我的控制器的构造函数。

控制器:

 public class MyController : BaseController { public ArticlesController(MyDbContext context) : base(context) { } } 

基本控制器:

 public class BaseController : Controller { protected DbContext MyDbContext; public BaseController(MyDbContext context) { MyDbContext = context; } } 

这似乎运作良好。 但是留下了几个问题。

  1. Ninject是否确保我的DbContext被清理并及时处理?

  2. 我为所有的应用程序的控制器创build了一个基类来处理任何常见的初始化等。基类在构造函数中接受我的DbContext参数的一个实例。 但是这需要我也将这个参数添加到我的应用程序中的每个控制器。 有没有办法不要求这个?

  3. 我不知道创build我的DbContext的实例是多么昂贵。 有没有什么办法来进行优化,只有当请求实际上需要我访问数据库时才会创build它。

Ninject是否确保我的DbContext被清理并及时处理?

根据这个答案 :

CLR文档指出,创build一个Disposable对象的人负责调用Dispose。 在这种情况下,该对象由Ninject创build。 这意味着你不应该明确地调用Dispose。

Ninject 只要将创build的对象绑定到的作用域对象由GC收集,就会处理具有除InTransientScope之外的另一个作用域的每个Disposable对象。 这就是为什么每个Disposable对象都应该绑定一个不是InTransientScope()的作用域的原因。 例如,您可以使用NamedScope 扩展中的 InParentScope(),一旦注入对象被垃圾收集,该对象将立即释放该对象。


我为所有的应用程序的控制器创build了一个基类来处理任何常见的初始化等。基类在构造函数中接受我的DbContext参数的一个实例。 但是这需要我也将这个参数添加到我的应用程序中的每个控制器。 有没有办法不要求这个?

简而言之, 不要为MVC控制器使用通用的基类 。 类inheritance往往会紧密地耦合你的逻辑,并且随着时间的推移变得难以维持。 它也往往会导致你创build一个神对象 ,因为创build多层次的注入依赖将意味着更多的每个控制器所需的依赖关系。

如果您有交叉问题 ,则应该使用全局注册的filter 。 你可以为每一个逻辑做一个单独的filter,这不会违背共同基类所要求的单一责任原则。 如果你在全局注册你的filter,你可以使用构造器注入,就像这个动作filter或者这个授权filter一样 。 您也可以根据需要制定自己的属性( 无行为 ),使其成为有条件的控制器和/或操作。

例:

既然你明确地说过你想基于当前用户设置普通的ViewBag属性,下面就是如何用filter来完成的。

CurrentUserProfileFilter

 public class CurrentUserProfileFilter : IAuthorizationFilter { private readonly MyDbContext context; public CurrentUserAuthorizationFilter(MyDbContext context) { this.context = context; } public void OnAuthorization(AuthorizationContext filterContext) { var currentUserName = filterContext.HttpContext.User.Identity.Name; // Set the ViewBag for the request. filterContext.Controller.ViewBag.UserName = currentUserName; var userBirthdate = from user as this.context.AspNetUsers where user.UserName == currentUserName select birthdate; if (userBirthdate.Date == DateTime.Now.Date) { filterContext.Controller.ViewBag.Message = "Happy Birthday!"; } } } 

GlobalFilterProvider

MVC有一个静态的GlobalFiltersCollection ,您应该在其中注册全局filter实例。 这不适用于具有由DI容器(例如DbContext )pipe理的依赖性的filter。

为了确保filter按需求parsing(每个请求),我们创build一个IFilterProvider ,通过容器parsing它们(假设你的Ninject容器已经作为DependencyResolver注册到了MVC);

 public class GlobalFilterProvider : IFilterProvider { private readonly IDependencyResolver dependencyResolver; public GlobalFilterProvider(IDependencyResolver dependencyResolver) { this.dependencyResolver = dependencyResolver; } public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { foreach (var filter in this.dependencyResolver.GetServices<IActionFilter>()) { yield return new Filter(filter, FilterScope.Global, order: null); } foreach (var filter in this.dependencyResolver.GetServices<IAuthorizationFilter>()) { yield return new Filter(filter, FilterScope.Global, order: null); } foreach (var filter in this.dependencyResolver.GetServices<IExceptionFilter>()) { yield return new Filter(filter, FilterScope.Global, order: null); } foreach (var filter in this.dependencyResolver.GetServices<IResultFilter>()) { yield return new Filter(filter, FilterScope.Global, order: null); } // If MVC 5, add these as well... //foreach (var filter in this.dependencyResolver.GetServices<System.Web.Mvc.Filters.IAuthenticationFilter>()) //{ // yield return new Filter(filter, FilterScope.Global, order: null); //} } } 

用法

在您的Ninject组合根目录中,将筛选器的实例与kernel一起注册为实现的筛选器接口的types或types。

 // Self-bind our filter, so dependencies can be injected. kernel.Bind<IAuthorizationFilter>().To<CurrentUserProfileFilter>(); 

FilterConfig ,注册你的filter提供者。

 public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); // Register the filter provider with MVC. FilterProviders.Providers.Insert(0, new GlobalFilterProvider(DependencyResolver.Current)); } } 

现在,在每个请求中,都会填充您的用户详细信息。

但更重要的是,你的ArticlesController不需要MyDbContext作为依赖,也不需要你的其他控制器。

我不知道创build我的DbContext的实例是多么昂贵。 有没有什么办法来进行优化,只有当请求实际上需要我访问数据库时才会创build它。

看看这个问题: 每个Web请求一个DbContext …为什么?