使用Ninject进行Asp.Net MVC3或MVC4的依赖注入

7

我正在使用Ninject MVC3(版本3.0.0.0)来进行我的ASP.Net MVC3应用程序的依赖注入,这是通过NuGet包安装的。

下面是Global.asax的更改:

public class MvcApplication : NinjectHttpApplication
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.IgnoreRoute("favicon.ico");
        routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });

        routes.MapRoute(
            "Default",                                              // Route name
            "{controller}/{action}/{id}",                           // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional }  // Parameter defaults
        );
    }


    protected override IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
        RegisterServices(kernel);
        return kernel;
    }

    protected override void OnApplicationStarted()
    {
        base.OnApplicationStarted();

        AreaRegistration.RegisterAllAreas();
        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IUserRepository>().To<UserRepository>();
        kernel.Bind<IUserService>().To<UserService>();
        kernel.Bind<ICommonRepository>().To<CommonRepository>();
        kernel.Bind<ICommonService>().To<CommonService>();
    }
}

但是,尽管我为我的HomeController提供了无参数的构造函数,它仍然会出现以下错误:
    System.NullReferenceException: Object reference not set to an instance of an object.

Generated: Wed, 28 Mar 2012 05:49:01 GMT

System.InvalidOperationException: An error occurred when trying to create a controller of type 'MVC3.Web.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at Ninject.Planning.Bindings.BindingConfiguration.GetProvider(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Bindings\BindingConfiguration.cs:line 107
   at Ninject.Planning.Bindings.Binding.GetProvider(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Bindings\Binding.cs:line 212
   at Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:line 157
   at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 386
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 197
   at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 165
   at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 114
   at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Ninject.Activation.Providers.StandardProvider.Create(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96
   at Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:line 157
   at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 386
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 197
   at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 165
   at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 114
   at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Ninject.Activation.Providers.StandardProvider.Create(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96
   at Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:line 157
   at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 386
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 197
   at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Targets\Target.cs:line 165
   at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 114
   at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Ninject.Activation.Providers.StandardProvider.Create(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Providers\StandardProvider.cs:line 96
   at Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:line 157
   at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 386
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at Ninject.Web.Mvc.NinjectDependencyResolver.GetService(Type serviceType) in c:\Projects\Ninject\ninject.web.mvc\mvc3\src\Ninject.Web.Mvc\NinjectDependencyResolver.cs:line 56
   at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
   --- End of inner exception stack trace ---
   at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
   at System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType)
   at System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName)
   at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory)
   at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<BeginProcessRequest>b__2()
   at System.Web.Mvc.SecurityUtil.<>c__DisplayClassb`1.<ProcessInApplicationTrust>b__a()
   at System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f)
   at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action)
   at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust[TResult](Func`1 func)
   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)
   at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

更新:

以下是HomeController中的代码:

public class HomeController : Controller
    {
        #region Declaration
        public ICommonService _commonService { get; set; }
        #endregion

        #region Constructor

        public HomeController()
        {

        }

        public HomeController(ICommonService commonService)
        {
            this._commonService = commonService;
        }
        #endregion

        public ActionResult Index()
        {
            return View();
        }

CommonService和CommonRepository的构造函数:

public class CommonService : ICommonService
    {
        #region Declaration
        private readonly ICommonRepository _repository;
        #endregion

        #region Constructor
        public CommonService(ICommonRepository repository)
        {
            this._repository = repository;
        }
        #endregion

 public class CommonRepository : ICommonRepository
    {
        #region Declaration
        private DBContainer _context = new DBContainer();
        #endregion

        #region Constructor
        public CommonRepository()
        {

        }
        #endregion

我有没有漏掉其他的参考资料?

检查您的无参数构造函数是否为公共的。 - Ventsyslav Raikov
Bond,是的,我已将它设置为公共的。 公共HomeController() {} - Prasad
@tpeczek,我已经更新了我的问题,附上了Controller。 - Prasad
我不知道 ninject 的工作原理,因为我正在使用 Unity。但是 Unity 默认使用具有最多参数的 ctor。也许 Ninject 表现相同,并尝试将 ICommonService 注入到您的 HomeController 中。尝试删除所有 ctor,只保留无参数 ctor。然后尝试再次通过 Ninject 解析您的实例。 - Jehof
看看我回答的这篇文章吧,它应该能让你快速上手:https://dev59.com/xeo6XIcBkEYKwwoYPSH7#11471180 - anAgent
显示剩余2条评论
3个回答

7
这是Ninject中构造函数选择的工作方式:
  1. 如果一个构造函数有[Inject]属性,它将被使用。如果多个构造函数都有[Inject]属性,Ninject将抛出NotSupportedException异常。
  2. 如果没有构造函数有[Inject]属性,则Ninject将选择最多参数且Ninject能够解析的构造函数。
  3. 如果没有定义构造函数,则Ninject将选择默认的无参构造函数。
在您的情况下,Ninject很可能不会选择无参构造函数,因为它认为知道如何解析ICommonService。如果您希望Ninject使用它,请尝试使用[Inject]属性装饰您的无参构造函数,或进一步调查为什么ICommonService未被解析。

我已经尝试在Global.asax的RegisterServices中添加ICommonService,但它仍然无法解决,并且我刚刚更新了我的问题。 - Prasad
在这种情况下,请分享CommonService的构造函数。 - tpeczek
tpeczek,我已经更新了我的问题,包括CommonService和CommonRepository的构造函数。 - Prasad
"DBContainer _context" 不是一个接口,它是访问数据库信息的实体。当我在无参数构造函数上使用[Inject]属性时,它不会抛出任何异常,但接口无法解析。 - Prasad
当您使用[Inject]属性时,它不会抛出异常,因为Ninject甚至不会尝试解决ICommonService(也不会)。当您不使用[Inject]属性时,引发异常的真正原因是在构建CommonService的对象图中出现了NullReferenceException。从您发布的代码来看,最好的理由是DBContainer()引发了此异常。这就是为什么我要求您将其更改为null并尝试不使用[Inject]属性的原因。 - tpeczek
显示剩余9条评论

2
如果您最近将MVC应用程序从.NET 4.0转换为4.5或反之,则会出现完全相同的症状。通过引用正确的目标.NET版本DLL来解决该问题。
如果您正在使用Ninject、Ninject.MVC3和Ninject.Web.Common nugets,则可以在其中找到所有.NET目标。

谢谢!这样做解决了我的问题。 - Johann

1

来自https://github.com/ninject/ninject/wiki/Injection-Patterns的引用:

主要的 DI 模式是构造函数注入。当激活类型的实例时,Ninject 将按照以下规则选择一个类型的构造函数使用:

如果构造函数有 [Inject] 属性,则使用它(但如果将该属性应用于多个构造函数,则 Ninject 在检测到后会在运行时抛出 NotSupportedException 异常)。

如果没有构造函数具有 [Inject] 属性,则 Ninject 将选择具有 Ninject 理解如何解析的最多参数的构造函数。

如果未定义任何构造函数,则 Ninject 将选择默认的无参数构造函数(假设存在这样的构造函数)。


当我移除无参数构造函数时,它会抛出“确保控制器具有无参数公共构造函数”的错误。 - Prasad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接