简单的注入器:注入外部Web服务

时间:2014-05-06 13:20:25

标签: c# .net dependency-injection ioc-container simple-injector

我在如何使用SimpleInjector正确配置DI方面遇到了一些困难。我有一个外部Web服务绑定位于Web.config文件中。我的外部Web服务位于服务层。我的Web层包含组合根,它调用我的域层来注册服务 - 域层然后将调用DAL层和服务层来注册它需要的服务。这将正常工作,然后在我的域层中,我可以使用我在域服务层构造函数中的服务层上创建的注入服务。

但是在我的服务层中,我有类似于下面的内容:

public class MyService : IMyService
{

    private readonly ExternalServiceClient _externalServiceClient;

    public MyService()
    {
        _externalServiceClient = new ExternalServiceClient("WSHttpBinding_IExternalService");
    }

这种设计可能不是最好的,因为它将MyService紧密地耦合到依赖外部ServiceClient - 我想要实现的是能够拥有自己的这个外部客户端的Stub,然后在实际的外部服务客户端或我之间轻松切换外部服务客户端的存根版本。

所以我的构造函数看起来像:

    private readonly ExternalServiceClient _externalServiceClient;

    public MyService(ExternalServiceClient externalServiceClient)
    {
        _externalServiceClient = externalServiceClient);
    }

其中 - externalServiceClient是新的

ExternalServiceClient("WSHttpBinding_IExternalService");或我的外部客户端的存根版本。

我不确定SimpleInjector是如何正确连接的,这样我可以轻松切换哪个ExternalClient传递给构造函数?

1 个答案:

答案 0 :(得分:2)

所以IMyService是你自己的抽象,ExternalServiceClient是一些生成的代理,而MyService只是代表ExternalServiceClient?如果是这种情况,我会说MyService实现与ExternalServiceClient强烈耦合。它不包含任何逻辑,只是一些允许隐藏抽象背后的ExternalServiceClient的基础结构。而不是创建存根ExternalServiceClient,您只需创建存根IMyService

此外,如果ExternalServiceClient是WCF生成的代理,您可能希望让MyService类控制ExternalServiceClient的创建和处置,尤其是WCF services need special care with disposing以来}。如果您让容器控制ExternalServiceClient的处置,那么无论您选择何种容器,都会使您的DI配置更难。

无论哪种方式,如果您决定将创建和处置移到MyService之外,最简单的注册方法如下:

container.Register<IMyService>(() => new MyService(
    new ExternalServiceClient("WSHttpBinding_IExternalService")));

此注册的问题是ExternalServiceClient未被处理。如果您使用其中一种Scoped生活方式在容器中明确注册ExternalServiceClient,容器将自动为您处理:

container.Register<IMyService, MyService>();

container.RegisterPerWebRequest<ExternalServiceClient>(
    () => new ExternalServiceClient("WSHttpBinding_IExternalService"));

然而,范围生活方式意味着ExternalServiceClient在整个请求中被重用,这可能不是您所需要的。因此,您可以将其注册为瞬态,并允许在请求结束时处理任何已创建的实例:

var scopedLifestyle = new WebRequestLifestyle();

container.Register<IMyService, MyService>();

container.Register<ExternalServiceClient>(
    () => new ExternalServiceClient("WSHttpBinding_IExternalService"));

container.RegisterInitializer<ExternalServiceClient>(client =>
{
    scopedLifestyle.RegisterForDisposal(container, client);
});

这个配置的问题当然是WCF代理是讨厌的fâckers,可能会从他们的Dispose方法中抛出异常,所以你需要做一些额外的处理才能做到这一点:

var scopedLifestyle = new WebRequestLifestyle();

container.Register<IMyService, MyService>();

container.Register<ExternalServiceClient>(
    () => new ExternalServiceClient("WSHttpBinding_IExternalService"));

container.RegisterInitializer<ExternalServiceClient>(client =>
{
    scopedLifestyle.WhenScopeEnds(container, () =>
    {
        try
        {
            client.Dispose();
        }
        catch 
        {
            // According to Marc Gravell we need to have a catch all here. 
        }
    });
});

这将有效地解决问题。