ASP.NET MVC4中的Ninject

时间:2012-07-13 12:09:28

标签: c# ninject asp.net-mvc-4

所以经过多次搞砸后,我终于将Ninject连接起来并编译在我的MVC4应用程序中。我遇到的问题是IDependencyScope接口不再存在,我所知道的并且System.Web.Http.Dependencies命名空间已经废除。

所以,我现在的问题是我已经连接了所有内容并运行我得到的应用程序:

    Sequence contains no elements

    [InvalidOperationException: Sequence contains no elements]
   System.Linq.Enumerable.Single(IEnumerable`1 source) +379
   Ninject.Web.Mvc.NinjectMvcHttpApplicationPlugin.Start() in c:\Projects\Ninject\ninject.web.mvc\mvc3\src\Ninject.Web.Mvc\NinjectMvcHttpApplicationPlugin.cs:53
   Ninject.Web.Common.Bootstrapper.<Initialize>b__0(INinjectHttpApplicationPlugin c) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:52
   Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map(IEnumerable`1 series, Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerableOfT.cs:31
   Ninject.Web.Common.Bootstrapper.Initialize(Func`1 createKernelCallback) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:53
   Ninject.Web.Common.NinjectHttpApplication.Application_Start() in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\NinjectHttpApplication.cs:81

我无法追踪甚至开始了解它的来源。

Global.asax.cs中的标准Ninject方法如下所示:

        protected override IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            kernel.Load(Assembly.GetExecutingAssembly());
            kernel.Bind<IRenderHelper>().To<RenderHelper>();

            GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new NinjectDependencyResolver(kernel));
            return kernel;
        }

        protected override void OnApplicationStarted()
        {
            base.OnApplicationStarted();
            AreaRegistration.RegisterAllAreas();
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
            BundleTable.Bundles.RegisterTemplateBundles();
        }

我的自定义解析器:

public class NinjectDependencyResolver : IDependencyResolver
{
    private readonly IKernel _kernel;

    public NinjectDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    public object GetService(Type serviceType)
     {
         return _kernel.TryGet(serviceType);
     }

     public IEnumerable<object> GetServices(Type serviceType)
     {
         try
         {
             return _kernel.GetAll(serviceType);
         }
         catch (Exception)
         {
             return new List<object>();
         }
     }

     public void Dispose()
     {
         // When BeginScope returns 'this', the Dispose method must be a no-op.
     }
}

这里的任何见解将不胜感激。我已经花了太多时间试图将任何DI框架连接到运行在.NET 4.5上的最新MVC4 RC,并且现在刚刚达到了对于根本不工作的东西的容忍度。

编辑#1 进一步研究在github中挖掘ExtensionsForIEnumerableOfT.cs并没有多大帮助:

https://github.com/ninject/ninject/blob/master/src/Ninject/Infrastructure/Language/ExtensionsForIEnumerableOfT.cs

如果我自己写了这篇文章,我会开始理解这一点,但Bootstrapper.cs也没有太多帮助。

https://github.com/ninject/Ninject.Web.Common/blob/master/src/Ninject.Web.Common/Bootstrapper.cs

希望这些细节能让您在Ninject中获得更多经验的人更轻松。

编辑#2 遇到的错误特别是在NinjectMvcHttpApplicationPlugin.cs中:

违规行是:

ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());

其中包含以下方法:

public void Start()
{
    ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());
    DependencyResolver.SetResolver(this.CreateDependencyResolver());
    RemoveDefaultAttributeFilterProvider();
}

ModelValidatorProviders集合包含2个元素: {} System.Web.Mvc.DataErrorInfoModelValidatorProvider {System.Web.Mvc.ClientDataTypeModelValidatorProvider}

它试图删除单个实例:

System.Web.Mvc.DataAnnotationsModelValidatorProvider

显然未在ModelValidationProviders.Providers集合中加载。来自这里的任何想法?

解决以上异常并进入下一个

要解决ModelValidatorProviders中的问题,我必须手动添加它所期望的对象。所以现在我的CreateKernel方法看起来像:

protected override IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Load(Assembly.GetExecutingAssembly());

    kernel.Bind<IRenderHelper>().To<RenderHelper>();
    kernel.Unbind<IDocumentViewerAdapter>();

    GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new NinjectDependencyResolver(kernel));
    ModelValidatorProviders.Providers.Add(new DataAnnotationsModelValidatorProvider());
    FilterProviders.Providers.Add(new FilterAttributeFilterProvider());
    return kernel;
}

现在它运行并进入Ninject的实际内容,但仍有一个问题,一个没有意义的问题:

Exception Details: Ninject.ActivationException: Error activating IntPtr
No matching bindings are available, and the type is not self-bindable.
Activation path:
 3) Injection of dependency IntPtr into parameter method of constructor of type Func{IKernel}
 2) Injection of dependency Func{IKernel} into parameter lazyKernel of constructor of type HttpApplicationInitializationHttpModule
 1) Request for IHttpModule

Suggestions:
 1) Ensure that you have defined a binding for IntPtr.
 2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
 3) Ensure you have not accidentally created more than one kernel.
 4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
 5) If you are using automatic module loading, ensure the search path and filters are correct.

8 个答案:

答案 0 :(得分:18)

好好把我的头靠在墙上太长时间后,我发现了发生了什么事。在.NET 4.5上运行的MVC4的默认项目类型引用了System.Web.Http的原始RC版本而不是更新版本。

命名空间丢失,对象不存在,生活不好。

解决步骤:

  1. 删除MVC4项目中对System.Web.Http的引用
  2. 添加参考 - &gt; System.Web.Http
  3. 删除您放入的所有工作以使旧的垃圾版System.Web.Http正常工作
  4. 在Ninject中重新应用标准流程。

    然而,错误:

    异常详细信息:Ninject.ActivationException:激活IntPtr时出错 没有匹配的绑定可用,并且该类型不可自绑定。 激活路径:  3)将依赖IntPtr注入到Func {IKernel}类型的构造函数的参数方法中  2)将依赖关系Func {IKernel}注入到HttpApplicationInitializationHttpModule类型的构造函数的参数lazyKernel中  1)请求IHttpModule

    建议:  1)确保已为IntPtr定义了绑定。  2)如果在模块中定义了绑定,请确保已将模块加载到内核中。  3)确保您没有意外创建多个内核。  4)如果使用构造函数参数,请确保参数名称与构造函数参数名称匹配。  5)如果使用自动模块加载,请确保搜索路径和过滤器正确无误。

  5. 更新这是通过将MVC从MVC4 Beta更新为MVC4 RC来解决的。

答案 1 :(得分:5)

查看Pro ASP.NET MVC 3 book。我昨晚刚将这段代码从MVC3移植到MVC4并正常工作。确切地说是第322页。

我看不到的是您将界面映射到具体项目的位置。

Bind<ISomething>().To<Something>();

添加另一个构造函数并添加调用映射的方法;

public NinjectDependencyResolver() {
    _kernal = new StandardKernel();
    RegisterServices(_kernel);
}

public static void RegisterServices(IKernel kernel) {
    kernel.Bind<ISomething>().To<Something>();
}

这是一个解析器可以/应该是什么样的;

   public class NinjectDependencyResolver : IDependencyResolver {
    private IKernal _kernel;

    public NinjectDependencyResolver(){
        _kernal = StandardKernal();
        AddBindings();
    }

    public NinjectDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    public object GetService(Type serviceType)
     {
         return _kernel.TryGet(serviceType);
     }

     public IEnumerable<object> GetServices(Type serviceType)
     {
        return _kernal.GetAll(serviceType);
     }

    public IBindingToSyntax<T> Bind<T>() {
      return _kernal.Bind<T>();
    }

     public static void RegisterServices(IKernel kernel){
      //Add your bindings here. 
      //This is static as you can use it for WebApi by passing it the IKernel
     }
}

Global.Asx -

  

的Application_Start()

方法

DependencyResolver.SetResolver(new NinjectDependencyResolver());

就是这样。


2012年11月14日更新

另外,如果您正在使用MVC WebAPI,则需要使用nuget中的WebApiContrib.IoC.Ninject。另外,请查看样本asp.net.com中的“联系人管理器”。这有助于清理Ninject的实现

答案 2 :(得分:4)

只需从项目中删除NinjectWebCommon.cs文件(它位于App_Start文件夹中)。一切都应该有效。

来源:http://mlindev.blogspot.com.au/2012/09/how-to-implement-dependency-injection.html

答案 3 :(得分:1)

当您从NuGet包安装最新的Ninject.MVC3时,我们会在NinjectWebCommon.cs文件的顶部找到以下代码:

[assembly: WebActivator.PreApplicationStartMethod(typeof(MvcApplication1.App_Start.NinjectWebCommon), "Start")]

[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(MvcApplication1.App_Start.NinjectWebCommon), "Stop")]

在这种情况下,我们不需要在global.asax中明确注册ninject

我发现使用Ninject和MVC 4 here

的内容很好

答案 4 :(得分:0)

我倾向于将我的Ninject引导保存在一个单独的项目中。为了使用.InRequestScope()的{​​{1}}扩展方法,我通过Nuget添加了 Ninject.Web.Common 库。唉,这个库包含了app_start引导程序,通过WebActivator产生了重复的NinjectWebCommon类和附件(所述项目中有1个,MVC项目中有1个)。

我从我的bootstrap项目中删除了重复的App_Start文件夹,这解决了它。

答案 5 :(得分:0)

我遇到了同样的问题,不太确定在下面的修改之后修复了什么

将Ninject.MVC4添加到项目

删除了NinjectWebCommon.cs(生成的文件,因为整合已存在于global.ascx.cs文件中)

答案 6 :(得分:0)

我正在使用DD4T,遇到同样的错误。

确认所有包都是由nuget包管理器安装的, 我发现有些DLL /引用丢失了(newtonsoft等):

然后,重新安装Newtonsoft.Json(重新安装包使用Nuget包管理器中的以下命令:Update-Package -reinstall Newtonsoft.Json),并将netrtsn.dll从Tridion Deployer bin中放入,我收到此错误 - &#34;序列不包含任何元素&#34;与此问题中给出的堆栈跟踪完全相同。

感谢Naga提供此解决方案 删除NinjectWebCommon.cs(生成的文件,因为整合已存在于global.ascx.cs文件中),并且wohooooo !!!!所有错误都已解决,Tridion + MVC4 = DD4T现在正常运行。

答案 7 :(得分:0)

当我使用nuget在我的实际MVC网站项目引用的项目中安装Ninject.MVC4时,我也遇到了这个问题。

问题是自动安装在引用项目的App_Start目录中的NinjectWebCommon.cs文件与我网站项目中安装的(实际的,有用的)冲突。从引用的项目中删除NinjectWebCommon.cs文件可以解决错误。