如何使用StructureMap摆脱代码中的ObjectFactory

时间:2015-09-23 06:37:52

标签: c# wcf dependency-injection structuremap

使用最新的StructureMap版本(3.1.6.191)升级我们的解决方案后,我收到了很多过时的警告。这些警告来自StructureMap,其中ObjectFactory类将在以后的版本中弃用(4.0 +)。

我正在使用WCF,我们希望使用IInstanceProvider的实现让StructureMap挂钩在WCF管道中:

public class StructureMapInstanceProvider : IInstanceProvider

这个类使用ObjectFactory来获取一个实例,当我的容器中没有静态类来解决它时,我们怎么能得到一个类型的实例呢?

1 个答案:

答案 0 :(得分:7)

ObjectFactory正在消失,因为许多人认为anti-pattern从应用程序中访问容器(称为服务定位器模式)。这会将您的代码紧密地耦合到容器中,并且难以维护配置,因为确定类所需的依赖项并不容易。

依赖注入与使用服务定位器不同。使用依赖注入,对象图在composition root中的应用程序开始附近得到解析。创建应用程序后,它没有引用IoC容器,因此没有与它紧密耦合。依赖关系在类构造函数中明确定义,因此您无需进一步查看类在注册时所需的依赖项。

在运行时,您不可避免地需要创建类的实例。为此,您可以转向许多Creational Patterns中的一个(其中抽象工厂最常见且IInstanceProvider实现),或者您可以inject a method使用容器来创建这些实例。

我建议您阅读这本书Dependency Injection in .NET。有一节(7.3)专门通过实现ServiceHostServiceHostFactoryIInstanceProvider将WCF与组合根连接起来。

以下是使用StructureMap的WCF组合根的基本示例(尽管我尚未验证它是否有效)。

StructureMap注册表

您可以在此处使用容器注册类型。如果您愿意,可以使用多个注册表。

public class MyRegistry : Registry
{
    public MyRegistry()
    {
        // Register all types
        this.For<ISomeService>().Use<SomeService>();
    }
}

ServiceHostFactory

这是我们实例化容器并注册类型映射的地方。

public class MyServiceHostFactory : ServiceHostFactory
{
    private readonly IContainer container;

    public MyServiceHostFactory()
    {
        this.container = new Container(r => r.AddRegistry<MyRegistry>());
    }

    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return new MyServiceHost(this.container, serviceType, baseAddresses);
    }
}

的ServiceHost

这是我们注入容器的地方。是的,我们需要至少在一个地方这样做。这里没关系,因为这是插入WCF的组合根的所有部分。

public class MyServiceHost : ServiceHost
{
    public MyServiceHost(IContainer container, Type serviceType, params Uri[] baseAddresses)
        : base(serviceType, baseAddresses)
    {
        if (container == null)
            throw new ArgumentNullException("container");

        var contracts = this.ImplementedContracts.Values;
        foreach (var c in contracts)
        {
            c.Behaviors.Add(new MyInstanceProvider(container, serviceType));
        }
    }
}

IInstanceProvider

我们仍然在应用程序的组合根目录中,因此我们可以注入容器来解析我们的实例。

此抽象工厂解析的服务不应该引用容器(既不是静态也不是注入)。

public partial class MyInstanceProvider : IInstanceProvider, IContractBehavior
{
    private readonly IContainer container;
    private readonly Type serviceType;

    public MyInstanceProvider(IContainer container, Type serviceType)
    {
        if (container == null)
            throw new ArgumentNullException("container");

        this.container = container;
        this.serviceType = serviceType;
    }

    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        return this.GetInstance(instanceContext);
    }

    public object GetInstance(InstanceContext instanceContext)
    {
        return this.container.GetInstance(this.serviceType);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        // Allow the lifetime management behavior of StructureMap to release dependencies
    }

    public void ApplyDispatchBehavior(
        ContractDescription contractDescription, ServiceEndpoint endpoint,
        DispatchRuntime dispatchRuntime)
    {
        dispatchRuntime.InstanceProvider = this;
    }
}

用法

只需在这些行中添加一些内容到.svc文件中即可注册自定义MyServiceHostFactory以解析您的WCF服务。

<%@ ServiceHost Factory = "MyNamespaceName.MyServiceHostFactory, MyAssemblyName" Service = "MyNamespaceName.MyWcfService" %>

使用的参考文献: