如何使用StructureMap为静态类指定setter注入?

时间:2011-12-27 14:41:26

标签: dependency-injection structuremap static-members

我目前正在使用设计模式书中的代码片段:

public static class DomainEvents
{
    public static IDomainEventHandlerFactory DomainEventHandlerFactory { get; set; }

    public static void Raise<T>(T domainEvent) where T : IDomainEvent
    {
        DomainEventHandlerFactory.GetDomainEventHandlersFor(domainEvent).ForEach(h => h.Handle(domainEvent));
    }
}

这涉及到连接DomainEvents,这个特定的代码片段负责允许我通过DomainEvents上的Raise方法引发事件。

以下是我的Bootstrapper文件中的代码:

public class ControllerRegistry : Registry
{
        public ControllerRegistry()
        {
            ForRequestedType<IDomainEventHandlerFactory>().TheDefault.Is.OfConcreteType<StructureMapDomainEventHandlerFactory>();
            ForRequestedType<IDomainEventHandler<OrderSubmittedEvent>>().AddConcreteType<OrderSubmittedHandler>();
        }
    }

当我从我的服务层访问DomainEvents.Raise时(在此示例中,我正在提升OrderSumittedEvent),DomainEventsnull(应该是通过StructureMap设置):

public class OrderService
{
    public void Create(Order order)
    {
        DomainEvents.Raise(new OrderSubmittedEvent() { Order = order });
    }
}

除非我这样明确地将DomainEvents.DomainEventHandlerFactory设置为StructureMapDomainEventHandlerFactory

public class OrderService
{
    public void Create(Order order)
    {
        // this is the manual assignment I have to make into the DomainEventHandlerFactory of
        // the static DomainEvents class. Basically, this is what StructureMap should take care
        // of for me, but is not.
        DomainEvents.DomainEventHandlerFactory = new StructureMapDomainEventHandlerFactory();

        DomainEvents.Raise(new OrderSubmittedEvent() { Order = order });
    }
}

下面是使用.WhatDoIHave()的StrucutureMap的输出,并且看起来StructureMap确实为StructureMapDomainEventHandlerFactory类型配置了IDomainEventHandlerFactory的实例。这是转储:

================================================================================================================================================================================================================================================================================================================================================================================================
PluginType                                                                                  Name                                                                                                                          Description                                                                                                                                                           
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Func`1<TResult> (Func`1<TResult>)                                                                                                                                                                                                                                                                                                                                                               
Scoped as:  Transient

                                                                                        311731d7-60c7-46de-9ef4-24608f21df04                                                                                                                                                                                                                                                                
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IDomainEventHandlerFactory (DE.Infrastructure.Domain.Events.IDomainEventHandlerFactory)     dbcb010c-fa92-4137-85b8-161ab17c2c98                                                                                          Configured Instance of DE.Infrastructure.Domain.Events.StructureMapDomainEventHandlerFactory, DE.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Scoped as:  Transient

                                                                                            dbcb010c-fa92-4137-85b8-161ab17c2c98                                                                                          Configured Instance of DE.Infrastructure.Domain.Events.StructureMapDomainEventHandlerFactory, DE.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IDomainEventHandler`1<OrderSubmittedEvent> (IDomainEventHandler`1<OrderSubmittedEvent>)     DE.Services.DomainEventHandlers.OrderSubmittedHandler, DE.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null     Configured Instance of DE.Services.DomainEventHandlers.OrderSubmittedHandler, DE.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null                      
Scoped as:  Transient

                                                                                            DE.Services.DomainEventHandlers.OrderSubmittedHandler, DE.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null     Configured Instance of DE.Services.DomainEventHandlers.OrderSubmittedHandler, DE.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null                      
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IContainer (StructureMap.IContainer)                                                        e24f9e45-caaf-48b6-89f7-d8125310102a                                                                                          Object:  StructureMap.Container                                                                                                                                       
Scoped as:  Transient

                                                                                            e24f9e45-caaf-48b6-89f7-d8125310102a                                                                                          Object:  StructureMap.Container                                                                                                                                       
================================================================================================================================================================================================================================================================================================================================================================================================

我已经使用过StructureMap,但是我还没有使用过Setter Injection,也没有必须处理将StructureMap与静态类一起使用(如果这样甚至有意义的话),所以我有点迷失为什么这个代码不行。

是否可以将Setter Injection与这样的类的静态实现一起使用? 我没有正确使用StructureMap吗? StructureMap应该负责将DomainEvents类创建为Singleton,我可以摆脱静态实现吗?

谢谢, 麦克

1 个答案:

答案 0 :(得分:0)

  

是否可以将Setter Injection与此类的静态实现一起使用?

没有。它只能通过可创建的类来实现。

  

我没有正确使用StructureMap吗?

你不是。依赖注入处理创建和提供实例。根据定义,静态类在代码中是不可创建的,因此是不可注入的。

  

StructureMap应该负责将DomainEvents类创建为Singleton,我可以摆脱静态实现吗?

看起来这个设计的核心功能是使用单个实例,因此事件只被触发一次。我不确定你的设计模式是什么,但在很多情况下你可以用Action<T>Func<T>代替事件,如果你正确使用单身生活方式,你可以注册一个可以在所有类之间共享,而不是诉诸静态类。

如果绝对需要静态事件,您可以通过解析实例并在完成注册代码后手动设置(在composition root中),在应用程序启动代码中注入IDomainEventHandlerFactory实例。

// Provide the DI container with configuration
var container = DIConfig();

// Set the static event
DomainEvents.DomainEventHandlerFactory = container.Resolve<IDomainEventHandlerFactory>();

为确保您的应用程序不会通过多次调用它或在设置之前使用它来滥用setter,您可以在静态类中添加一些guard子句。

public static class DomainEvents
{
    private static IDomainEventHandlerFactory domainEventHandlerFactory;

    public static IDomainEventHandlerFactory DomainEventHandlerFactory 
    { 
        get
        {
            return domainEventHandlerFactory;
        }
        set
        {
            if (value == null)
                throw new ArgumentNullException("value");
            if (domainEventHandlerFactory != null)
                throw new ArgumentException("DomainEventHandlerFactory is already set and cannot be set again.");
            domainEventHandlerFactory = value;
        }
    }

    public static void Raise<T>(T domainEvent) where T : IDomainEvent
    {
        ThrowIfNotInitialized()
        DomainEventHandlerFactory.GetDomainEventHandlersFor(domainEvent).ForEach(h => h.Handle(domainEvent));
    }

    private static void ThrowIfNotInitialized()
    {
        if (domainEventHandlerFactory == null)
        {
            throw new MvcSiteMapException("Not initialized. You must set DomainEventHandlerFactory at application start.");
        }
    }
}