在Windows Forms应用程序中使用Castle.Windsor [英] Using Castle.Windsor with Windows Forms Applications

查看:89
本文介绍了在Windows Forms应用程序中使用Castle.Windsor的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

到目前为止,我一直在使用ASP.NET MVC在Castle.Windsor中学习IoC / DI,但是我有一个在Windows Forms中完成的辅助项目,我想知道是否存在一种有效的方法来为此使用它。

Up until this point, I have been learning IoC/DI with Castle.Windsor using ASP.NET MVC, but I have a side project that is being done in Windows Forms, and I was wondering if there is an effective way to use it for that.

我的问题在于创建表单,服务等。在ASP.NET MVC中,有一种激活器可以在后台进行此操作,但是Windows窗体中不是这种情况。我必须创建一个像 var form = new fclsMain(); 这样的新表单,所以一个像..

My problem is in the creation of forms, services, etc. In ASP.NET MVC, there is a sort of 'Activator' that does this under the hood, but this isn't the case in Windows Forms. I have to create a new Form like var form = new fclsMain();, so a Form like ..

class fclsMain : System.Windows.Forms.Form
{
 private readonly ISomeRepository<SomeClass> someRepository;
 fclsMain(ISomeRepository<SomeClass> someRepository)
 {
  this.someRepository = someRepository;
 }
}

秋天有点短。我基本上必须要做...

Falls kind of short. I would basically have to do ...

var form = new fclsMain(IoC.Resolve< ISomeRepository< SomeClass>));

正如我在至少三个问题中所指出的那样,这并不明智,因为据称这不是IoC的正确用法。

Which as I have had pointed out in at least three of my questions isn't smart, because it's supposedly not the 'correct' usage of IoC.

那么我如何使用Castle.Windsor和Windows Forms?有某种设计Form Activator的方法吗?我真的迷路了,如果我无法创建一个可以解析的静态 IoC 容器,我该怎么办?

So how do I work with Castle.Windsor and Windows Forms? Is there some way to design a Form Activator or something? I'm really lost, if I can't make a static IoC container that I can resolve from, what can I do?

推荐答案

为了在整个应用程序中使用相同的Castle容器,请创建一个静态类,如:

In order to use the same Castle container throughout your entire application, create a static class like:

public static class CastleContainer {
    private static IWindsorContainer container;

    public static IWindsorContainer Instance {
        get {
            if (container == null) {
                container = new WindsorContainer();
            }
            return container;
        }
        // exposing a setter alleviates some common component testing problems
        set { container = value; }
    }

    // shortcut to make your life easier :)
    public static T Resolve<T>() {
        return Instance.Resolve<T>();
    }

    public static void Dispose() {
        if (container != null) 
            container.Dispose();
        container = null;
    }
}

然后在<$中注册/安装所有组件c $ c> Main()方法。您也可以挂接到应用程序关闭事件,以调用 Dispose()(尽管这不是很关键)。

Then register/install all your components in the Main() method. You can also hook into the application shutdown event to call Dispose() (although this isn't critical).

城堡实际上在其快速入门指南中使用Windows Forms应用。

Castle actually uses a Windows Forms app in their quick-start guide.

我在上面显示的模式是服务定位器的一种变体,有些人指的是作为反模式。它的声誉很差,因为除其他原因外,它还会引用Windsor来丰富您的代码库。理想情况下,您应该只调用一次 container.Resolve< ...>()即可创建根表单。所有其他服务和表单是通过构造函数注入的。

The pattern I showed above is a variant of the service locator, which some people refer to as an anti-pattern. It has a bad reputation because, among other reasons, it liters your code base with references to Windsor. Ideally, you should only have a single call to container.Resolve<...>() to create your root form. All other services & forms are injected via constructors.

实际上,您可能需要再调用一些Resolve,尤其是当您不想在启动时加载应用程序的每个角落时。在网络世界中,最佳实践是将容器移交给网络框架。在Windows Forms世界中,您将需要实现自己的服务定位器(如上所述)。 (是的,将容器交给ASP.NET MVC框架仍然是服务定位器模式)。

Realistically, you'll probably need a few more calls to Resolve, especially if you don't want to load every single corner of the application at startup. In the web world, the best practice is to hand off the container to the web framework. In the Windows Forms world you'll need to implement your own service locator, like above. (Yes, handing the container to the ASP.NET MVC framework is still a service locator pattern).

我已经编辑了上面的代码示例,以使静态容器可以注入;没有资源在静态上下文中被占用。如果确实要创建自己的服务定位器,则可能还需要创建一个像这样的测试实用程序,以使测试更加容易。

I've edited the above code example so that the static container is injectable; no resources are tied up in a static context. If you do end up creating your own service locator, you might also want to create a test utility like this one to make testing easier.

public static class TestUtilities 
{
    public static IContainer CreateContainer(Action<IContainer> extraConfig = null) 
    {
        var container = new WindsorContainer();
        // 1. Setup common mocks to override prod configuration
        // 2. Setup specific mocks, when provided
        if (extraConfig != null)
            extraConfig(container);
        // 3. Configure container with production installers
        CastleContainer.Instance = container;
        return container;
    }
}

这为创建一个看起来像新容器的捷径非常类似于生产版本,但是某些服务已替换为模拟。一些示例测试可能看起来像:

This makes a shortcut for creating a new container that looks a lot like the production version, but with some services replaced with mocks. Some example tests might look like:

[Test]
public void SubComponentWorksGreat() 
{
    using (var container = TestUtilities.CreateContainer())
    {
        var subComponent = container.Resolve<SubComponent>();
        // test it...
    }
}

[Test]
public void SubComponentWorksGreatWithMocks() 
{
    var repoMock = new Mock<IRepository>();
    using (var container = TestUtilities.CreateContainer(c => 
            c.Register(Component.For<IRepository>().Instance(repoMock.Object))))
    {
        var subComponent = container.Resolve<SubComponent>();
        // test it with all IRepository instances mocked...
    }
}

最后一个音符。为每个测试创建一个完整的容器可能会很昂贵。另一种选择是创建完整的容器,但仅使用嵌套容器进行实际测试。

One last note. Creating a full container for every test can get expensive. Another option is to create the full container but only using nested containers for the actual tests.

这篇关于在Windows Forms应用程序中使用Castle.Windsor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆