如何使用 StructureMap 摆脱代码中的 ObjectFactory
How to get rid of ObjectFactory in code using StructureMap
使用最新的 StructureMap 版本 (3.1.6.191) 升级我们的解决方案后,我收到了很多过时的警告。这些警告来自 StructureMap,其中 ObjectFactory
class 将在未来版本 (4.0+) 中弃用。
我正在使用 WCF,我们希望使用 IInstanceProvider
:
的实现让 StructureMap 挂接到 WCF 管道中
public class StructureMapInstanceProvider : IInstanceProvider
这个class使用ObjectFactory
来获取一个实例,当我的容器没有静态class来解析它时,我们如何获取一个类型的实例?
ObjectFactory
即将消失,因为许多人认为 anti-pattern 从应用程序内部访问容器(称为服务定位器模式)。这会将您的代码与容器紧密耦合,并且难以维护配置,因为确定 class 需要哪些依赖项并不容易。
依赖注入不同于使用服务定位器。使用依赖注入,对象图在 composition root 中的应用程序开始附近解析。一旦创建了应用程序,它就没有对 IoC 容器的引用,因此与它没有紧密耦合。依赖项在 class 构造函数中明确定义,因此您无需进一步查看 class 在注册时需要哪些依赖项。
在运行期间,您不可避免地需要创建 classes 的实例。为此,您可以求助于使用容器创建这些实例的众多 Creational Patterns (of which Abstract Factory is most common and IInstanceProvider
implements) or alternatively, you can 之一。
我推荐阅读这本书 Dependency Injection in .NET。有一个部分 (7.3) 专门介绍了通过实现 ServiceHost
、ServiceHostFactory
和 IInstanceProvider
.
将 WCF 与组合根连接起来
这是使用 StructureMap 的 WCF 组合根的基本示例(尽管我尚未验证它是否有效)。
StructureMap 注册表
这里是您向容器注册类型的地方。如果愿意,您可以使用多个注册表。
public class MyRegistry : Registry
{
public MyRegistry()
{
// Register all types
this.For<ISomeService>().Use<SomeService>();
}
}
服务主机工厂
这是我们实例化容器和注册类型映射的地方。
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);
}
}
服务主机
这是我们注入容器的地方。是的,我们至少需要在一个地方这样做。这里没问题,因为这是插入 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" %>
使用的参考资料:
使用最新的 StructureMap 版本 (3.1.6.191) 升级我们的解决方案后,我收到了很多过时的警告。这些警告来自 StructureMap,其中 ObjectFactory
class 将在未来版本 (4.0+) 中弃用。
我正在使用 WCF,我们希望使用 IInstanceProvider
:
public class StructureMapInstanceProvider : IInstanceProvider
这个class使用ObjectFactory
来获取一个实例,当我的容器没有静态class来解析它时,我们如何获取一个类型的实例?
ObjectFactory
即将消失,因为许多人认为 anti-pattern 从应用程序内部访问容器(称为服务定位器模式)。这会将您的代码与容器紧密耦合,并且难以维护配置,因为确定 class 需要哪些依赖项并不容易。
依赖注入不同于使用服务定位器。使用依赖注入,对象图在 composition root 中的应用程序开始附近解析。一旦创建了应用程序,它就没有对 IoC 容器的引用,因此与它没有紧密耦合。依赖项在 class 构造函数中明确定义,因此您无需进一步查看 class 在注册时需要哪些依赖项。
在运行期间,您不可避免地需要创建 classes 的实例。为此,您可以求助于使用容器创建这些实例的众多 Creational Patterns (of which Abstract Factory is most common and IInstanceProvider
implements) or alternatively, you can
我推荐阅读这本书 Dependency Injection in .NET。有一个部分 (7.3) 专门介绍了通过实现 ServiceHost
、ServiceHostFactory
和 IInstanceProvider
.
这是使用 StructureMap 的 WCF 组合根的基本示例(尽管我尚未验证它是否有效)。
StructureMap 注册表
这里是您向容器注册类型的地方。如果愿意,您可以使用多个注册表。
public class MyRegistry : Registry
{
public MyRegistry()
{
// Register all types
this.For<ISomeService>().Use<SomeService>();
}
}
服务主机工厂
这是我们实例化容器和注册类型映射的地方。
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);
}
}
服务主机
这是我们注入容器的地方。是的,我们至少需要在一个地方这样做。这里没问题,因为这是插入 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" %>
使用的参考资料: