简体   繁体   English

Ninject和Simple Injector都无法进行属性注入

[英]Property injection failing with both Ninject and Simple Injector

Update - turns out this was a bad configuration/wrong code in the wrong place problem. 更新-事实证明这是配置错误/代码错误的地方。 Got it working now. 现在工作了。

I have scanned the other SO entries (some are really old) but there isn't an answer to be found. 我已经扫描了其他SO条目(有些条目确实很旧),但找不到答案。 I am attempting to follow an example as provided by Adam Freeman's book, "Pro ASP.NET MVC 5" (yeah, it's a little dated but still good) and in the example he sets up a simple website with Dependency Injection (DI) using Ninject. 我正在尝试遵循亚当·弗里曼(Adam Freeman)的书“ Pro ASP.NET MVC 5”中提供的示例(是的,虽然有些陈旧,但仍然不错),并且在该示例中,他使用Ninject。

I followed the example after adapting to current web technologies (I'm using the .NET framework 4.7), updated the basic project (which starts as an empty MVC with Mvc and WebApi both checked) and everything works just fine, right up to the Inject a property example. 在适应当前的Web技术(我使用的是.NET Framework 4.7)之后,我按照示例进行了操作,更新了基本项目(该项目开始时是一个空的MVC,同时选中了Mvc和WebApi),并且一切正常,直到注入一个属性示例。

I thought to myself, "OK, Ninject is getting a little long in the tooth and I don't think it's being maintained anymore so I'll try a new gadget that I have heard is Really Fast - SimpleInjector". 我对自己想,“好吧,Ninject的牙齿长了一点,我不认为它已经得到维护,所以我将尝试一个新的小工具,我听说它是​​Really Fast-SimpleInjector”。

Created a brand new project, moved only the example classes across (copied) and setup SI in the recommended fashion. 创建了一个全新的项目,仅跨(复制)了示例类,并以推荐的方式设置了SI。 SAME PROBLEM! 同样的问题!

What's the problem, you ask? 你问什么问题? Simple, the value I wish injected into the created concrete class isn't being injected. 很简单,我希望注入创建的具体类中的值不会被注入。

To replicate (or at least, follow along), you need to create a standard ASP.NET MVC application (Visual Studio 2017, Enterprise, 15.3.4, .NET Framework version 4.7 in a Windows 10 Creator environment, non-domain), select "Empty" and then check the MVC and Web API check boxes. 要复制(或至少遵循),您需要创建一个标准的ASP.NET MVC应用程序(非域,在Windows 10 Creator环境中为Visual Studio 2017,Enterprise,15.3.4,.NET Framework版本4.7),选择“空”,然后选中“ MVC和Web API”复选框。 Not quite as the book details, but I need both for another project which doesn't matter at this point. 本书的内容还不尽如人意,但我需要一个无关紧要的项目。 Again, following the example as laid out in the book works just fine, DI and all, with Ninject up to the point of property injection. 同样,遵循本书中列出的示例,DI以及全部都可以正常使用,并且Ninject可以达到属性注入点。

From that point, I have added a simple class to support a shopping card, a gadget that calculates total cost and a gadget that applies a discount. 从那时起,我添加了一个简单的类来支持购物卡,一个计算总成本的小工具和一个应用折扣的小工具。 Really simple stuff. 真的很简单的东西。 Following are the mods made for each using each DI container: 以下是使用每个DI容器为每个模型制作的mod:

Ninject: In the NinjectWebCommon.cs file, RegisterServices method: 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>();

In SimpleInjector (created a separate class to perform "registration": 在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());

The view takes in a really simple model, just a class with two properties, both decimal, one with the original total, one with the discounted total. 该视图采用一个非常简单的模型,只是一个具有两个属性的类,两个属性均为十进制,一个具有原始总计,一个具有折现总计。 Despite setting the Discount amount to a value of at least 15M, both numbers are the same. 尽管将折扣金额设置为至少1500万,但两个数字相同。 If I remove property injection and hard code a value in various places, the number comes out correctly. 如果我删除属性注入并在各个位置硬编码一个值,则数字会正确显示。 In short, the injection is failing in both DI containers. 简而言之,在两个DI容器中注入均失败。 This should not be and I cannot figure out why this is happening. 事实并非如此,我无法弄清为什么会这样。

An assist here would be much appreciated. 非常感谢您的协助。 If more code is needed, leave a comment and I'll upload the entire project in a .zip. 如果需要更多代码,请发表评论,然后将整个项目上载为.zip。

The answer was to ensure that all the right initializations are taking place in the correct order. 答案是要确保所有正确的初始化都以正确的顺序进行。 Also needed to ensure that the correct version of IDependencyResolver was referenced (there are two and the other one doesn't play nice). 还需要确保引用了正确的IDependencyResolver版本(有两个版本,另一个版本运行不佳)。 The code that solved it for me for Ninject is this (thanks to Adam Freeman, the author of the book that generated this SO entry): 为我为Ninject解决它的代码是这样的(感谢生成了SO条目的书的作者Adam Freeman):

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>();
    }
}

} }

And the SimpleInjector solution: 和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);
    }

}

} }

Either will give a start to creating an MVC 5 project that will support both MVC and WebApi in the same project. 两家公司都将开始创建一个MVC 5项目,该项目将在同一项目中同时支持MVC和WebApi。 The case I am working on is a simple example but at least it's a start rather than an error. 我正在研究的案例是一个简单的示例,但至少是一个开始,而不是一个错误。 Thanks to everyone (especially Adam Freeman) for their support. 感谢所有人(尤其是亚当·弗里曼)的支持。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM