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

发布于 2024-12-22 22:37:21 字数 8199 浏览 1 评论 0原文

我目前正在研究设计模式书中的这段代码片段:

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 时(在本示例中,我将引发 OrderSumissEvent),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() 的 StructureMap 的输出,并且看起来 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 注入,也不必处理将 StructureMap 与静态类一起使用(如果这有意义的话),所以我有点不明白为什么这段代码不起作用。

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

谢谢, 麦克风

I'm currently working through this code snippet from a design patterns book:

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));
    }
}

This deals with wiring up DomainEvents, and this particular code snippet is responsible allowing me to raise an event via the Raise method on DomainEvents.

Here is the code in my Bootstrapper file:

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

When I go to access DomainEvents.Raise from my Service layer (in this example, I'm raising the OrderSumittedEvent), DomainEvents is null (when it should be set via StructureMap):

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

Unless I explicitly set the DomainEvents.DomainEventHandlerFactory by hand to StructureMapDomainEventHandlerFactory like this:

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 });
    }
}

Below is the output of StrucutureMap using .WhatDoIHave(), and it appears that StructureMap does have a configured instance of StructureMapDomainEventHandlerFactory for type IDomainEventHandlerFactory. Here is the dump:

================================================================================================================================================================================================================================================================================================================================================================================================
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                                                                                                                                       
================================================================================================================================================================================================================================================================================================================================================================================================

I've used StructureMap, but I haven't used Setter Injection, nor have I had to deal with using StructureMap with static classes (if that even makes sense), so I'm a little lost as to why this code won't work.

Is it possible to use Setter Injection with a static implementation of a class like this?
Am I not using StructureMap properly?
Should StructureMap be responsible for creating the DomainEvents class as a Singleton, and I can get rid of the static implementation?

Thanks,
Mike

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

作死小能手 2024-12-29 22:37:21

是否可以将 Setter 注入与这样的类的静态实现一起使用?

不可以。只有可创建的类才有可能。

我没有正确使用 StructureMap 吗?

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

StructureMap 是否应该负责将 DomainEvents 类创建为单例,并且我可以摆脱静态实现?

看起来此设计的核心功能是使用单个实例,因此事件仅被触发一次。我不确定您想要什么设计模式,但在许多情况下,您可以用 ActionFunc 替换事件,并且如果您使用正确地使用单例生活方式,您可能可以注册一个可以在所有类之间共享的单个实例,而不是诉诸静态类。

如果绝对需要静态事件,您可以在应用程序启动代码中注入 IDomainEventHandlerFactory 的实例,方法是解析该实例并在完成注册代码后手动设置它(在您的 组合根)。

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

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

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

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.");
        }
    }
}

Is it possible to use Setter Injection with a static implementation of a class like this?

No. It is only possible with createable classes.

Am I not using StructureMap properly?

You are not. Dependency injection deals with creating and providing instances. By definition static classes are non-createable in code and therefore, non-injectable.

Should StructureMap be responsible for creating the DomainEvents class as a Singleton, and I can get rid of the static implementation?

It looks like a core feature of this design is to use a single instance so the event is only fired once. I am not sure what design pattern you are going for, but in many cases you can substitute Action<T> or Func<T> for events, and if you use the singleton lifestyle properly you can probably register a single instance that can be shared between all of your classes rather than resorting to a static class.

If the static event is absolutely required, you can inject an instance of IDomainEventHandlerFactory in your application startup code by resolving the instance and setting it manually after you have completed your registration code (in your composition root).

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

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

To ensure your application doesn't abuse the setter by calling it more than once or using it before it is set, you can put some guard clauses in your static class.

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.");
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文