30の|フィールドイベント:モジュールを切り離す達成、事業の結束を強化します
私たちは、層は、フィールドイベントとフィールドイベント処理の領域にインタフェースを定義して抽象化
IDomainEvent
namespace GeekTime.Domain
{
public interface IDomainEvent : INotification
{
}
}
これは、INotificationはMediatRフレームワークは、イベント配信では達成するために使用されるインターフェースである空のインターフェース、単に特定のオブジェクトがフィールドイベントであるかどうかをマーク空インタフェースであります
namespace MediatR
{
public interface INotification
{
}
}
IDomainEventHandler続きます
namespace GeekTime.Domain
{
public interface IDomainEventHandler<TDomainEvent> : INotificationHandler<TDomainEvent>
where TDomainEvent : IDomainEvent
{
//这里我们使用了INotificationHandler的Handle方法来作为处理方法的定义
//Task Handle(TDomainEvent domainEvent, CancellationToken cancellationToken);
}
}
このインタフェースは、このTDomainEvent制約は上院へとハンドラのハンドルのみIDomainEventを言うことですIDomainEvent、である必要があり、一般的なパラメータがTDomainEventであり、同じIDomainEventHandlerインタフェースを継承します
実際には、この方法はそれはそれはどのようなものであったかの定義であることを伝えるために、わかりましたので、再定義する必要はありませんINotificationHandlerで定義されています
エンティティでのイベントコードのアドレス領域
private List<IDomainEvent> _domainEvents;
public IReadOnlyCollection<IDomainEvent> DomainEvents => _domainEvents?.AsReadOnly();
public void AddDomainEvent(IDomainEvent eventItem)
{
_domainEvents = _domainEvents ?? new List<IDomainEvent>();
_domainEvents.Add(eventItem);
}
public void RemoveDomainEvent(IDomainEvent eventItem)
{
_domainEvents?.Remove(eventItem);
}
public void ClearDomainEvents()
{
_domainEvents?.Clear();
}
フィールドイベントは読み取り専用に暴露して、複数のものが実体を操作するプロセスの途中で発生する可能性があるため、フィールドは、ソリッドモデルのイベントコードの外で読まれるべきで、それはリストでなければなりません、プロパティ記憶エンティティに来るのかコレクション
そこはまた、いくつかの方法が提供される、フィールドのイベントを追加し、フィールドのイベントを削除し、フィールドのイベントをクリア
これらのメソッドは、ドメインモデル内で呼び出されます
ご注文は、以前に定義を見ることができます
public Order(string userId, string userName, int itemCount, Address address)
{
this.UserId = userId;
this.UserName = userName;
this.Address = address;
this.ItemCount = itemCount;
this.AddDomainEvent(new OrderCreatedDomainEvent(this));
}
public void ChangeAddress(Address address)
{
this.Address = address;
//this.AddDomainEvent(new OrderAddressChangedDomainEvent(this));
}
私たちは新しい秩序を構築する場合と、実際には、ここにあなたがOrderCreatedDomainEventというイベントを定義することができ、我々はコンストラクタは、実際には、私たちの行動が注文を呼び出すとき、コンストラクタのパラメータには、このフィールドのイベントは、注文され、イベントAddDomainEventを追加するので、ここでは、新しい注文を作成します
同様の例ChangeAddressが呼び出されて、ここでは、実際にこの子のうちのようなOrderAddressChangedDomainEventフィールドイベントを定義することができます
あなたはこれらのイベントは、ドメインモデル内で起こっているので、ドメインモデルのメソッド内に完了しなければならない、とのコールを作成するためのコードの外にすべきではない工事のフィールドを参照し、イベントを追加することができます
その後OrderCreatedDomainEventの定義を見て
namespace GeekTime.Domain.Events
{
public class OrderCreatedDomainEvent : IDomainEvent
{
public Order Order { get; private set; }
public OrderCreatedDomainEvent(Order order)
{
this.Order = order;
}
}
}
どのように私たちが治療を受けるために私たちのフィールドイベント、フィールドのイベントを扱うか、アプリケーション層で定義する必要があります
namespace GeekTime.API.Application.DomainEventHandlers
{
public class OrderCreatedDomainEventHandler : IDomainEventHandler<OrderCreatedDomainEvent>
{
ICapPublisher _capPublisher;
public OrderCreatedDomainEventHandler(ICapPublisher capPublisher)
{
_capPublisher = capPublisher;
}
public async Task Handle(OrderCreatedDomainEvent notification, CancellationToken cancellationToken)
{
await _capPublisher.PublishAsync("OrderCreated", new OrderCreatedIntegrationEvent(notification.Order.Id));
}
}
}
それはIDomainEventHandlerを継承し、このインターフェイスは、イベントハンドラ上記のインタフェース領域で、そのジェネリックパラメータの型は、イベントが処理されるOrderCreatedDomainEvent
プレゼンテーションの単純化のために、ここでの論理は、我々は新しい秩序を作成するとき、我々はEventBusにイベントを発行し、このイベントがOrderCreatedと呼ばれているということです
私たちは、CreateOrder OrderControllerでCreateOrderCommandを定義します
[HttpPost]
public async Task<long> CreateOrder([FromBody]CreateOrderCommand cmd)
{
return await _mediator.Send(cmd, HttpContext.RequestAborted);
}
CreateOrderCommand
namespace GeekTime.API.Application.Commands
{
public class CreateOrderCommand : IRequest<long>
{
//ublic CreateOrderCommand() { }
public CreateOrderCommand(int itemCount)
{
ItemCount = itemCount;
}
public long ItemCount { get; private set; }
}
}
CreateOrderCommandHandler
public async Task<long> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
{
var address = new Address("wen san lu", "hangzhou", "310000");
var order = new Order("xiaohong1999", "xiaohong", 25, address);
_orderRepository.Add(order);
await _orderRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
return order.Id;
}
私たちは、注文内のCreateOrderCommandHandlerを作成し、その後、SaveEntitiesAsyncのUnitOfWorkのと呼ばれる倉庫の中に保存します
直接実行されるプログラムは、私たちのメソッドを呼び出して、起動し、我々はOrderCreatedDomainEventHandlerに記憶メモリが完了したときに、解放(MediatorExtension)フィールドイベント、そして公開コードに、我々は最初のシステム(CreateOrderCommandHandler)を処理するための作成に入った見ることができます、それは、我々のドメインモデルの作成が完了して保存するには、私たちのフィールドイベントハンドラにのみトリガされた後と言うことです
、(EFContext)の前にUnitOfWorkのを達成するために説明する私たちのSaveEntitiesAsyncすると、コードの1行だけありSaveChangesAsyncで、ここでのコードの行を追加するには、フィールドのイベントコードが送られDispatchDomainEventsAsync
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default)
{
var result = await base.SaveChangesAsync(cancellationToken);
//await _mediator.DispatchDomainEventsAsync(this);
return true;
}
これはMediatorExtension DispatchDomainEventsAsync見られています
namespace GeekTime.Infrastructure.Core.Extensions
{
static class MediatorExtension
{
public static async Task DispatchDomainEventsAsync(this IMediator mediator, DbContext ctx)
{
var domainEntities = ctx.ChangeTracker
.Entries<Entity>()
.Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any());
var domainEvents = domainEntities
.SelectMany(x => x.Entity.DomainEvents)
.ToList();
domainEntities.ToList()
.ForEach(entity => entity.Entity.ClearDomainEvents());
foreach (var domainEvent in domainEvents)
await mediator.Publish(domainEvent);
}
}
}
我々は、フィールドのイベントは、実際にこのようなプロセスで送ることがわかります。私たちは、現在のエンティティ・コンテキストは、私たちの実体を追跡中に入る節約したい、そして私たちの現在のイベントにオブジェクトエンティティからトラックに取得するには、イベントがあれば存在します、それを出し、その後、エンティティイベントをクリアし、その後、これらのイベントは、対応するハンドラを見つけるために、ミドルウェアを通じて1、およびプロセスずつ送り出さ
実際に定義フィールドのイベントは非常に簡単で、単にドメインモデル内のディレクトリのイベントを作成し、そのフィールドのイベントがここで定義されている、フィールドイベントはIDomainEventを継承する必要があり、プロセッサのフィールドイベントはDomainEventHandler、このディレクトリ内のアプリケーション層で定義されていますここでは、各イベントのために私たちのハンドラを定義することができます
要約します
イベントの分野でモデルを作成します。イベントの全体のフィールドは、フィールドのビジネスロジックによってトリガーされるので、我々は、イベントのドメインモデル構造の外に移動し、ドメインモデルに渡されていない、むしろトリガーのモデル外の動作よりも
私たちは、各イベント処理クラスに定義され、特定のディレクトリに、証明しているように、他には、イベントハンドラクラスの特定の領域を定義する必要があり、フィールドイベント用です
もう一つは、私たちのフィールドイベントに対処するために、同じトランザクション内にある、実際には、我々はまた、時間が内部事務のさまざまな分野でのイベントに対処するために必要であれば、我々は一貫性を考慮する必要があり、別のトランザクションで対処することを選択できます質問は、中央のエラーメッセージの損失の問題を考えます
この作品は、ある非営利- -同一条件許諾4.0の国際ライセンス契約クリエイティブ・コモンズのライセンスのために。
転載、使用、再投稿へようこそますが、(リンクを含む:鄭Zimingによって署名記事を保つために必ずhttp://www.cnblogs.com/MingsonZheng/を)、商業目的のために使用してはならない、紙のライセンス変更に基づいて、同じ作業を公開してください。
ご質問があれば、私に連絡してください([email protected])。