Как указать инъекции сеттера для статического класса, используя StructureMap?
В настоящее время я работаю над этим фрагментом кода из книги шаблонов проектирования:
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, и именно этот фрагмент кода отвечает за то, что я могу вызвать событие через Raise
метод на DomainEvents.
Вот код в моем файле Bootstrapper:
public class ControllerRegistry : Registry
{
public ControllerRegistry()
{
ForRequestedType<IDomainEventHandlerFactory>().TheDefault.Is.OfConcreteType<StructureMapDomainEventHandlerFactory>();
ForRequestedType<IDomainEventHandler<OrderSubmittedEvent>>().AddConcreteType<OrderSubmittedHandler>();
}
}
Когда я иду к доступу DomainEvents.Raise
из моего слоя службы (в этом примере я поднимаю OrderSumittedEvent
), DomainEvents
является null
(когда это должно быть установлено через 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 });
}
}
Ниже приведен вывод StrucutureMap с использованием .WhatDoIHave()
и кажется, что 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 ответ
Можно ли использовать Setter Injection со статической реализацией такого класса?
Нет. Это возможно только для создаваемых классов.
Я правильно не использую StructureMap?
Ты не. Внедрение зависимостей связано с созданием и предоставлением экземпляров. По определению статические классы не могут быть созданы в коде и, следовательно, не могут быть введены.
Должен ли StructureMap отвечать за создание класса DomainEvents как Singleton, и я могу избавиться от статической реализации?
Похоже, что основной особенностью этого дизайна является использование одного экземпляра, поэтому событие вызывается только один раз. Я не уверен, какой шаблон дизайна вы собираетесь, но во многих случаях вы можете заменить Action<T>
или же Func<T>
для событий, и если вы используете образ жизни синглтона должным образом, вы, вероятно, можете зарегистрировать один экземпляр, который может использоваться всеми вашими классами, вместо того, чтобы прибегать к статическому классу.
Если статическое событие абсолютно необходимо, вы можете внедрить экземпляр IDomainEventHandlerFactory в код запуска вашего приложения, разрешив экземпляр и установив его вручную после завершения кода регистрации (в корне композиции).
// Provide the DI container with configuration
var container = DIConfig();
// Set the static event
DomainEvents.DomainEventHandlerFactory = container.Resolve<IDomainEventHandlerFactory>();
Чтобы ваше приложение не злоупотребляло сеттером, вызывая его более одного раза или используя его до того, как оно установлено, вы можете поместить несколько защитных предложений в ваш статический класс.
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.");
}
}
}