关于使用Ninject的问题

Jon*_*ood 2 c# asp.net asp.net-mvc dependency-injection ninject

我完成了建议的步骤,将Ninject添加到我的MVC应用程序中.我向DbContext控制器的构造函数添加了一个参数.

控制器:

public class MyController : BaseController
{
    public ArticlesController(MyDbContext context)
        : base(context)
    { }
}
Run Code Online (Sandbox Code Playgroud)

基础控制器:

public class BaseController : Controller
{
    protected DbContext MyDbContext;

    public BaseController(MyDbContext context)
    {
        MyDbContext = context;
    }
}
Run Code Online (Sandbox Code Playgroud)

这似乎运作良好.但是请给我一些问题.

  1. Ninject能否确保我DbContext的清理和及时处理?

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

  3. 我不确定创建一个我的实例是多么昂贵DbContext.是否有任何方法可以进行优化,只有在请求实际要求我访问数据库时才会创建它.

Nig*_*888 10

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

根据这个答案:

CLR文档指出,创建Disposable对象的任何人都负责调用Dispose.在这种情况下,对象由Ninject创建.这意味着你不应该明确地调用Dispose.

Ninject处理具有另一个范围的每个Disposable对象,而不是InTransientScope 只要GC收集与创建的对象绑定的范围对象.这就是为什么每个Disposable对象应该使用非InTransientScope()的范围进行Bindd.例如,你可以使用NamedScope 扩展中的 InParentScope(),它将在注入对象时立即对象进行垃圾收集.


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

简而言之,永远不要为MVC控制器使用通用基类.类继承倾向于紧密耦合您的逻辑,并且随着时间的推移变得难以维护.它还会导致您创建一个上帝对象,因为创建多个注入的依赖项级别意味着每个Controller都需要更多的依赖项.

如果您有横切关注点,则应使用全局注册的过滤器.您可以为每个逻辑块创建一个单独的过滤器,它不会违反单一责任原则作为共享基类.如果您在全局注册过滤器,则可以在此操作过滤器此授权过滤器中使用构造函数注入.如果需要,您还可以创建自己的属性(没有行为),使其成为每个控制器和/或操作的条件.

例:

由于您明确表示要ViewBag基于当前用户设置公共属性,因此以下是使用过滤器的方法.

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!";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

GlobalFilterProvider

MVC有一个静态GlobalFiltersCollection,你应该在全局注册过滤器实例.对于具有由DI容器管理的生命周期的依赖项的过滤器(例如DbContext),这不会发生.

为了确保按需解析过滤器(按请求),我们IFilterProvider通过容器解析它们(假设您的Ninject容器在MVC中注册为DependencyResolver);

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);
        //}
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

在Ninject组合根目录中,使用kernel它实现的过滤器接口的类型或类型注册过滤器的实例.

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

FilterConfig,注册您的过滤器提供商.

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,每次请求都会填充您的用户详细信息.

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

我不确定创建DbContext的实例是多么昂贵.是否有任何方法可以进行优化,只有在请求实际要求我访问数据库时才会创建它.

看看这个问题:每个网页请求一个DbContext ...为什么?