使用Ninject和Simple Injector进行属性注入失败

时间:2017-09-19 00:48:15

标签: c# asp.net-mvc dependency-injection ninject

更新 - 结果证明这是一个错误的配置/错误的代码错误的地方问题。现在就开始工作了。

我已经扫描了其他SO条目(有些真的旧),但没有找到答案。我试图按照Adam Freeman的书“Pro ASP.NET MVC 5”提供的一个例子(是的,它有点过时但仍然很好)并且在这个例子中他建立了一个使用依赖注入(DI)的简单网站Ninject。

我在适应当前的Web技术(我正在使用.NET框架4.7)之后关注了这个示例,更新了基本项目(以Mvc和WebApi检查的空MVC开始)并且一切正常,正确直到注入属性示例。

我心想,“好吧,Ninject的牙齿有点长,我不认为它会被维护,所以我会尝试一个我听说过的真正快速的新工具 - SimpleInjector”。 / p>

创建了一个全新的项目,仅以推荐的方式移动(复制)示例类并设置SI。同样的问题!

你问的问题是什么?很简单,我希望注入到创建的具体类中的值不会被注入。

要复制(或至少遵循),您需要在Windows 10 Creator环境中创建标准ASP.NET MVC应用程序(Visual Studio 2017,Enterprise,15.3.4,.NET Framework 4.7版,非域),选择“清空”,然后选中MVC和Web API复选框。不像书的细节那么详细,但我需要另外一个在这一点上无关紧要的项目。再次,遵循本书中列出的例子,工作得很好,DI和所有,Ninject达到了注入财产的程度。

从那时起,我添加了一个简单的类来支持购物卡,一个计算总成本的小工具和一个应用折扣的小工具。真的很简单。以下是每个使用DI容器的mod:

Ninject: 在NinjectWebCommon.cs文件中,RegisterServices方法:

kernel.Bind<IDiscountHelper>()
.To<DiscountHelper>()
    .WithPropertyValue(nameof(DiscountHelper.DiscountSize), 15.0M);
kernel.Bind<ILinqValueCalculator>().To<LinqValueCalculator>();
kernel.Bind<IShoppingCart>().To<ShoppingCart>();

在SimpleInjector中(创建了一个单独的类来执行“注册”:

// Put all the aContainer.Register<ISomeInterface, SomeConcreteClass>(LifetimeScope) calls here
aContainer.Register<IDiscountHelper, DiscountHelper>(new AsyncScopedLifestyle());
// How to inject a property initializer
aContainer.RegisterInitializer<IDiscountHelper>
(
    i =>
        {
            i.DiscountSize = 15M;
            i.DiscountAmount = 30M;
        }
);
aContainer.Register<ILinqValueCalculator, LinqValueCalculator>(new AsyncScopedLifestyle());
aContainer.Register<IShoppingCart, ShoppingCart>(new AsyncScopedLifestyle());

视图采用一个非常简单的模型,只是一个具有两个属性的类,包括十进制,一个具有原始总数,一个具有折扣总数。尽管将折扣金额设置为至少15M的值,但两个数字都相同。如果我删除属性注入并在各个位置硬编码值,则数字正确显示。简而言之,两个DI容器中的注射都失败了。这不应该是,我无法弄清楚为什么会发生这种情况。

非常感谢这里的协助。如果需要更多代码,请留下评论,我将整个项目上传到.zip。

1 个答案:

答案 0 :(得分:1)

答案是确保所有正确的初始化都以正确的顺序进行。还需要确保引用了正确版本的IDependencyResolver(有两个而另一个不好玩)。 为Ninject解决它的代码就是这个(感谢Adam Freeman,这本书的作者生成了这个SO条目):

using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using Ninject.Web.WebApi;
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using Web.Models;
[ assembly:WebActivatorEx.PreApplicationStartMethod(typeof(Web.App_Start.NinjectWebCommon), "Start")]
[ assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(Web.App_Start.NinjectWebCommon), "Stop")]

namespace Web.App_Start {

public static class NinjectWebCommon {
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop() {
        bootstrapper.ShutDown();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel() {
        var kernel = new StandardKernel();
        try {
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            RegisterServices(kernel);
            GlobalConfiguration.Configuration.DependencyResolver =
                new NinjectDependencyResolver(kernel);
            return kernel;
        } catch {
            kernel.Dispose();
            throw;
        }
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel) {
        System.Web.Mvc.DependencyResolver.SetResolver(new
            MvcNinjectDependencyResolver(kernel));
    }
}

public class MvcNinjectDependencyResolver : IDependencyResolver {
    private IKernel kernel;

    public MvcNinjectDependencyResolver(IKernel kernelParam) {
        kernel = kernelParam;
        AddBindings();
    }

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

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

    private void AddBindings() {
        kernel.Bind<IDiscountHelper>()
            .To<DiscountHelper>()
                .WithPropertyValue(nameof(DiscountHelper.DiscountSize), 15.0M);
        kernel.Bind<ILinqValueCalculator>().To<LinqValueCalculator>();
        kernel.Bind<IShoppingCart>().To<ShoppingCart>();
    }
}

}

SimpleInjector解决方案:

using Web;
using WebActivator;

[assembly: PostApplicationStartMethod(typeof(SimpleInjectorWebInitializer), nameof(SimpleInjectorWebInitializer.Initialize))]

namespace Web
{
using System.Reflection;
using System.Web.Http;
using System.Web.Mvc;
using Infrastructure;
using SimpleInjector;
using SimpleInjector.Integration.Web;
using SimpleInjector.Integration.Web.Mvc;
using SimpleInjector.Integration.WebApi;

public static class SimpleInjectorWebInitializer
{
    /// <summary>Initialize the container and register it as Web API Dependency Resolver.</summary>
    public static void Initialize()
    {
        var vContainer = new Container();
        // To use the "greediest constructor" paradigm, add the following line:
        vContainer.Options.ConstructorResolutionBehavior =
            new MostResolvableParametersConstructorResolutionBehavior(vContainer);

        vContainer.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
        InitializeContainer(vContainer);

        // From the docs, these next two lines need to be added for MVC
        vContainer.RegisterMvcControllers(Assembly.GetExecutingAssembly());
        vContainer.RegisterMvcIntegratedFilterProvider();

        // This is for Web Api
        vContainer.RegisterWebApiControllers(GlobalConfiguration.Configuration);

        vContainer.Verify();

        // This is needed for MVC
        DependencyResolver.SetResolver
            (new SimpleInjectorDependencyResolver(vContainer));
        // This is needed for WebApi
        GlobalConfiguration.Configuration.DependencyResolver =
            new SimpleInjectorWebApiDependencyResolver(vContainer);
    }

    private static void InitializeContainer(Container aContainer)
    {
        // This is just a call to a regular static method of a static class
        // that performs the container.Register calls.
        InitializeContainerBindings.InitializeBindings(aContainer);
    }

}

}

要么开始创建一个MVC 5项目,它将在同一个项目中同时支持MVC和WebApi。我正在研究的案例是一个简单的例子,但至少它是一个开始而不是一个错误。 感谢所有人(特别是Adam Freeman)的支持。

相关问题