Моему приложению ASP.NET MVC3 / NHibernate требуется отключать и обрабатывать различные события, связанные с объектами моего домена. Например, объект Order
может иметь такие события, как OrderStatusChanged
или NoteCreatedForOrder
. В большинстве случаев эти события приводят к отправке электронной почты, поэтому я не могу просто оставить их в приложении MVC.
Я прочитал События домена Udi Dahan и десятки других мыслей о том, как делать такие вещи, и я решил использовать хост на основе NServiceBus, который обрабатывает сообщения о событиях. Я провел несколько проверок концепции, и это, кажется, работает хорошо.
У меня вопрос , какой прикладной уровень должен на самом деле вызывать события . Я не хочу запускать события до тех пор, пока рассматриваемый объект не будет успешно сохранен (не могу отправить электронное письмо о том, что заметка была создана в случае сбоя сохранения).
Другая проблема заключается в том, что в некоторых случаях событие связано с объектом, который находится под совокупным корнем. В приведенном выше примере Note
сохраняется путем добавления его в коллекцию Order.Notes
и сохранения заказа. Это создает проблему в том, что трудно оценить, какие события должны запускаться при сохранении Order
. Я бы хотел избежать необходимости извлекать текущую копию объекта и искать различия перед сохранением обновленной копии.
Уместно ли для пользовательского интерфейса вызывать эти события? Он знает, какие события произошли, и может инициировать их только после того, как сервисный уровень успешно сохранит объект. Что-то не так с контроллером, запускающим события домена.
Должно ли хранилище запускать события после успешного сохранения?
Должен ли я вообще отделять события, иметь в хранилище хранилище объект Event
, который затем выбирается службой опроса и , а затем превращается в событие для NServiceBus (или обрабатывается непосредственно из служба опросов)?
Есть ли лучший способ сделать это? Может быть, объекты моего домена помещают в очередь события, которые запускаются сервисным уровнем только после сохранения объекта?
Обновление: У меня есть сервисный уровень, но он кажется громоздким и чрезмерным, чтобы он прошел процесс сравнения, чтобы определить, какие события должны быть запущены при сохранении заданного совокупного корня. Поскольку некоторые из этих событий являются гранулированными (например, «статус заказа изменен»), я думаю, что мне придется извлечь копию объекта БД, сравнить свойства, чтобы создать события, сохранить новый объект, а затем отправить события в NServiceBus, когда операция сохранения успешно завершена.
Обновление
После того, как я опубликовал ответ ( значительно ниже ), я закончил тем, что встроил в мои доменные объекты свойство EventQueue
, которое было List<IDomainEvent>
. Затем я добавил события в качестве изменений в домене, и это позволило мне сохранить логику в домене, что я считаю уместным, поскольку я запускаю события, основываясь на том, что происходит внутри сущности.
Затем, когда я сохраняю объект на своем уровне обслуживания, я обрабатываю эту очередь и фактически отправляю события на служебную шину. Первоначально я планировал использовать устаревшую базу данных, в которой использовались идентифицирующие PK, поэтому мне пришлось пост-обрабатывать эти события для заполнения идентификатора сущности, но в итоге я решил переключиться на Guid.Comb
PK, который позволяет мне пропустить это. шаг.