19

我目前正在开展一个项目,我们正在将旧的 DataSet、存储过程 WinForm 应用程序转换为使用实体框架,以便新网站可以访问相同的对象模型和存储库。

无论如何,我正在尝试在表单中实现依赖注入,以便我们可以使用模拟存储库进行单元测试。我使用 Ninject 的原因很简单,因为我之前在 MVC 网站中使用过它,但是至少可以说,尝试在 WinForm 应用程序中实现这一点被证明是有问题的,由于 WinForms 中缺乏关于 DI 的信息而更加受阻网络。

到目前为止,我已经创建了 Ninject Factory 和存储库,但我没有太多运气将存储库注入表单。

因此,任何人都可以帮助我或提出任何建议吗?

下面我的部分代码可能会有所帮助:

忍者工厂:

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

带有存储库的表单:

Public Class TaskForm
    Inherits BaseBusinessDialogForm

    Private _repository As TaskRepository
    Private _task As Production.Task = Nothing

    Public Sub New(ByVal task As Production.Task)

        InitializeComponent()

        _repository = New TaskRepository(ConnectString)

        If task.TaskID = 0 Then
            _task = task
        Else
            _task = _repository.GetByID(task.TaskID)
        End If

        MyBase.BusinessObject = _task
        Me.TaskBindingSource.DataSource = MyBase.BusinessObject

    End Sub

启动包含上述表单的 MDI 表单的类:

Dim kernel As IKernel = New StandardKernel(New NinjectFactory())
''Dim kernel As IKernel = New StandardKernel(New NinjectFactoryTest())
mfrmMDI = kernel.Get(Of Forms.MDI)()

Application.DoEvents()
mfrmMDI.ShowDialog()

我知道我的问题有点含糊,但我不确定问题出在哪里或我需要完成什么。

非常感谢

4

1 回答 1

37

您创建组合根作为您的解决方案的一个入口点。您将 INjectModule 作为参数传递,以便您可以对其进行配置以进行不同的测试。Composition Root 的好处之一是,并非所有程序集都依赖于 NInject,并且您将有一个单点来更改解析逻辑。当您将来可能会更改 IoC 容器或引入一些动态拦截时,这确实是一个很酷的模式。

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

ApplicationModule在 main 方法中,您作为参数传递并解析Form1并启动它。

[STAThread]
static void Main()
{
    CompositionRoot.Wire(new ApplicationModule());

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    Application.Run(CompositionRoot.Resolve<Form1>());
}

Form1构造函数中,您使用特定的封闭通用参数传递所需的存储库

public partial class Form1 : Form
{
    private IRepository<Process> _processRepository;

    public Form1(IRepository<Process> productionRepository)
    {
        this._processRepository = productionRepository;        
        InitializeComponent();
    }  

    private void button1_Click(object sender, EventArgs e)
    {
        MessageBox.Show(_processRepository.ToString());
    }
}

您的存储库可能非常复杂,但我不会向它们添加任何功能,而不是ToString()方法,以便我们可以查看是否正确解析了依赖项。请注意,存储库上没有任何属性。

public interface IRepository<T>
{
}

public class GenericRepository<T> : IRepository<T>
{
    public override string ToString()
    {
        return "MyRepository with type : "+typeof(T).Name;
    }
}

现在,当您运行您的应用程序时,您会看到所有内容都已连接好,并且消息框显示一个封闭的类型为Process

在此处输入图像描述

于 2013-01-04T12:41:51.347 回答