更新 - 结果证明这是一个错误的配置/错误的代码错误的地方问题。现在就开始工作了。
我已经扫描了其他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。
答案 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)的支持。