Sto tentando di implementare un sistema di eventi di dominio che attiva i suoi eventi solo quando l'unità di lavoro associata viene accettata correttamente.
Il motivo principale per cui voglio farlo è perché ho altri sottosistemi che leggono il database che si aspetta che tali modifiche siano in atto quando gestiscono l'evento.
Inoltre, non voglio che i gestori di eventi facciano il loro lavoro (invia email, ecc.) se il commit fallisce.
Il sistema è costituito da più applicazioni ASP.NET (WebForms, MVC e WebAPI).
public class Order
{
private Payment _payment;
public int ID { get; private set; }
public decimal Amount { get; private set; }
public void PayUsing(IPaymentProcessor processor)
{
if (_payment != null)
{
throw new InvalidOperationException(
"You can't pay for an order twice");
}
// the Process method may also raise domain events
_payment = processor.Process(Amount);
// Raise saves the event into a static Queue<T>
DomainEvents.Raise(new OrderPaidEvent(this));
}
}
public class OrderFulfillmentService
{
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
private readonly IPaymentProcessor _paymentProcessor;
public OrderFulfillmentService(
IUnitOfWorkFactory unitOfWorkFactory,
IPaymentProcessor paymentProcessor)
{
_unitOfWorkFactory = unitOfWorkFactory;
_paymentProcessor = paymentProcessor;
}
public void Fulfill(int orderId)
{
using (var unitOfWork = _unitOfWorkFactory.Create())
{
var order = unitOfWork.OrdersRepository.GetById(orderId);
order.PayUsing(_paymentProcessor);
unitOfWork.Commit();
// I only want the events to be raised if the Commit succeeds
}
}
}
Con l'implementazione corrente, è problematico perché in questo momento il dominio che si innalza deve metterlo in una coda in quanto non deve sparare immediatamente. La coda è statica e causa problemi ai sistemi multiutente. Non desidero accidentalmente generare eventi per altri utenti, il che rappresenta un problema preciso dato che tutti gli utenti accedono alla stessa coda.
Questa è la lista di soluzioni che ho esaminato e perché non funzioneranno nel mio scenario
-
Avere una classe non
DomainRaiser
non modificata che viene passata nel metodoPayUsing
.- Il passaggio a
DomainRaiser
è molto difficile da eseguire dagli oggetti dominio, a volte gli eventi possono essere generati modificando le proprietà e il passaggio di questo oggetto è complicato.
- Il passaggio a
-
Tutte le entità contengono un'enumerazione
Events
letta dalla chiamataUnitOfWork.Commit
come discusso su link- Tracciare tutte le singole entità eventualmente modificate è molto difficile, sto scaricando questo rilevamento delle modifiche sull'ORM. Anche questo raggruppa gli oggetti del dominio.
-
Uso di
HttpContext.Current.Items
per memorizzare eventi specifici dell'utente- Questo è attualmente il miglior suggerimento, tuttavia, non è possibile effettuare un test unitario e blocca il mio dominio all'utilizzo di asp.net, che in futuro ho in programma di rilasciare un'applicazione per desktop.
La mia domanda è: come faccio a fare la coda e a inviare questi eventi in un ambiente multi-utente in modo affidabile, tenendo conto del fatto che voglio solo lanciare eventi se l'unità di lavoro complessiva ha successo?