我的目标是在我的应用程序中使用静态方法Ninject。我知道静态方法不应该有任何依赖性,因为从测试的角度来看很难。但是,在我的应用程序中,我无法将每个方法静态化为非静态方法。我需要用最少的更改来实现DI,即我应该在一次更改代码并且应该在调用该方法或类的任何地方更改实现。我也不想使用服务定位器模式,因为它甚至不是纯粹的DI模式。
为了保留上述所有要点,我实施了以下设置并且运行良好。无论我是否正确使用Ninject和静态方法,我都需要你的想法。
我的ASP.NET WebForms设置:
解决方案:NinjectPlayGround
项目:
NinjectPlayGround(Web Project)
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 and static classes - how to?,这是理论上的方式。我已经完全实际地要求使用Ninject的staic方法。此外,这个问题是针对静态类的,在我看来它不是静态类而是静态方法。