有关使用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; } }
这似乎运作良好。 但是留下了几个问题。
-
Ninject是否确保我的
DbContext
被清理并及时处理? -
我为所有的应用程序的控制器创build了一个基类来处理任何常见的初始化等。基类在构造函数中接受我的
DbContext
参数的一个实例。 但是这需要我也将这个参数添加到我的应用程序中的每个控制器。 有没有办法不要求这个? -
我不知道创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 …为什么?