我的目标是在我的应用程序中使用Ninject和静态方法。我知道静态方法不应该有任何依赖关系,因为从测试的角度来看它很难。但是,在我的应用程序中,我无法将每个方法从静态变为非静态。我需要以最少的更改来实现 DI,即我应该一次性更改代码,并且应该在调用该方法或类的任何地方更改实现。我也不想使用服务定位器模式,因为它甚至不是纯 DI 模式。
为了牢记以上所有要点,我实施了以下设置,并且运行良好。无论我是否正确使用 Ninject 和静态方法,我都需要你的想法。
我的 ASP.NET WebForms 设置:
解决方案:NinjectPlayGround
项目:
NinjectPlayGround(Web 项目)
NinjectPlayGround.BL(业务层)
NinjectPlayGround.Common(POCO 层)
为了使用 Ninject,我安装了Ninject.Web
NinjectWebCommon.cs 代码:
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(NinjectPlayGround.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(NinjectPlayGround.App_Start.NinjectWebCommon), "Stop")]
namespace NinjectPlayGround.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using NinjectPlayGround.Common;
using NinjectPlayGround.BL;
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);
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)
{
kernel.Bind<ILogger>().To<DefaultLogger>();
// Set static properties
CommonHelper.Logger = kernel.Get<ILogger>();
}
}
}
我在那里添加了以下两条自定义行:
kernel.Bind<ILogger>().To<DefaultLogger>();
// Set static properties
CommonHelper.Logger = kernel.Get<ILogger>();
CommonHelper 是具有静态方法的类,我想在其中使用 Logger 实例。
CommonHelper 类代码:
using NinjectPlayGround.Common;
namespace NinjectPlayGround.BL
{
public class CommonHelper
{
public static ILogger Logger { get; set; }
public static void RunCleanUp()
{
// Run clean up
//.....
Logger.Log("Clean up done");
}
}
}
ILogger 类代码:
namespace NinjectPlayGround.Common
{
public interface ILogger
{
void Log(string message);
}
}
DefaultLogger 类代码:
using System.Diagnostics;
namespace NinjectPlayGround.Common
{
public class DefaultLogger : ILogger
{
public void Log(string message)
{
Debug.WriteLine(message);
}
}
}
由于 Ninject 属性不允许在这样的静态属性上使用:
public static ILogger Logger { get; set; }
我通过NinjectWebCommon类中存在的RegisterServices方法设置该属性,该方法在 每个应用程序启动时仅调用一次(如果我在这里错了,请纠正我)
// Set static properties
CommonHelper.Logger = kernel.Get<ILogger>();
在 UI 中,这个辅助方法是这样调用的:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Ninject;
using NinjectPlayGround.BL;
namespace NinjectPlayGround
{
public partial class _default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
CommonHelper.RunCleanUp();
}
}
}
上述设置工作正常,即如果我将 DefaultLogger 更改为 PersistentLogger(这是 ILogger 的另一种实现)
kernel.Bind<ILogger>().To<DefaultLogger>();
至
kernel.Bind<ILogger>().To<PersistentLogger>();
我可以看到 PersistentLogger 被调用而不是 DefaultLogger 而没有在CommonHelper类中进行任何混乱/更改。
这是将 Ninject 与静态方法一起使用的正确方法吗?
这就是我需要在NinjectWebCommon类的RegisterServices方法中设置我需要通过 DI 设置的所有静态属性的方式吗?
我会在这种实施中遇到任何困难吗?
编辑:我已经经历过Ninject 和静态类 - 如何?这是理论上的。我已经询问了在 Ninject 中使用 staic 方法的完整实际实现。此外,这个问题是针对静态类的,在我的案例中,它不是静态类,而是静态方法。