我正在开发一个项目来实现DI(使用Ninject)到现有的WinForms应用程序中,但是我遇到了一些问题,而且我在WinForms中使用DI的知识充其量是有限的,但是我已经成功地使用了几个在MVC项目中的时间。
我在尝试创建一个包含需要存储库接口的构造函数的表单时收到此消息:
Error activating IProductionRepository
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IProductionRepository into parameter
productionRepository of constructor of type Main
1) Request for Main
我在网上搜索过,但是我在这个错误上阅读的大部分文章要么处理更复杂的设置,要么是关于参数注入,我不确定这是问题。
我有一个表单,用于启动使用DI的表单(错误发生在kernel.Get
调用上:
Private Sub txt_Click(sender As System.Object, e As System.EventArgs) Handles txt.Click
Try
Dim kernel As Ninject.IKernel =
New Ninject.StandardKernel(New NinjectFactory())
Dim form As Main = kernel.Get(Of Main)()
form.ConnectionString = App.pstrConnectString
form.ShowDialog(Me)
Catch ex As Exception
Support.ErrorHandler.ReportError(ex.Message, ex, True)
End Try
End Sub
我的NinjectFactory具有正确的绑定(以及其他一些已注释的尝试):
public class NinjectFactory : NinjectModule
{
private IKernel _ninjectKernel;
public NinjectFactory()
{
_ninjectKernel = new StandardKernel();
}
public override void Load()
{
//_ninjectKernel.Bind(typeof(IRepository<>))
// .To(typeof(GenericRepository<>));
//_ninjectKernel.Bind(typeof(IProductionRepository))
// .To(typeof(ProductionRepository));
_ninjectKernel.Bind<IProductionRepository>().To<ProductionRepository>();
}
}
最后我有我想要推出的表格:
private IProductionRepository _productionRepository;
public string ConnectionString
{
get
{
return _connectionString;
}
set
{
_connectionString = value;
}
[Inject]
public Main(IProductionRepository productionRepository) : this()
{
this._productionRepository = productionRepository;
}
public Main()
{
InitializeComponent();
}
这是我以前在MVC项目中使用Ninject的方式,我没有遇到过问题,但是很明显WinForms有些不同。
非常感谢任何帮助。
答案 0 :(得分:2)
我建议使用Mark Seemann(@ mark-seemann)在他的伟大着作Composition Root
中建议的单点依赖解析,即Dependency Injection in .NET
。您的CompositionRoot可能如下所示:
public class CompositionRoot
{
private static IKernel _ninjectKernel;
public static void Wire(INinjectModule module)
{
_ninjectKernel = new StandardKernel(module);
}
public static T Resolve<T>()
{
return _ninjectKernel.Get<T>();
}
}
public class ApplicationModule : NinjectModule
{
public override void Load()
{
Bind(typeof(IRepository<>)).To(typeof(GenericRepository<>));
}
}
您可以在Program
CompositionRoot.Wire(new ApplicationModule());
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(CompositionRoot.Resolve<Form1>());
现在您的按钮处理程序可能如下所示:
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(_productionRepository.ToString());
}
注意:如果您想测试具有不同依赖关系的应用程序(可能就是这种情况),那么您可以使用不同的布线配置创建另一个模块。在测试中,您将拥有另一个带有存根和模拟的布线逻辑。 我也不喜欢我的模型上的NInject属性,如果你使用构造函数注入 - 你可以摆脱它们。我的实体是简单的POCO。
public interface IProductionRepository
{
}
public class ProductionRepository : IProductionRepository
{
public override string ToString()
{
return "Foo";
}
}
Mark也为具有DI模式的WinForms以及它如何实现提供了一个很好的案例,我真的建议他的书。