Raising events

Now, let's see how domain events are being used in our entity. First, we need to raise events from our methods. To do this, we need some event list inside the entity so we can keep events that are being created. Otherwise, there is little point in creating event instances in first place.

Since we expect this functionality of keeping events in some sort of a list inside the entity, we can move this to a base class for entities, which we didn't have before.

Let's create an abstract class and call it Entity.

using System.Collections.Generic;
using System.Linq;

namespace Marketplace.Framework
{
public abstract class Entity
{
private readonly List<object> _events;

protected Entity() => _events = new List<object>();

protected void Raise(object @event) => _events.Add(@event);

public IEnumerable<object> GetChanges() => _events.AsEnumerable();

public void ClearChanges() => _events.Clear();
}
}

Since raised events will represent changes in the entity, methods that retrieve the list of events and clear this list, are called GetChanges and ClearChanges.

The next step is to add this base class to our entity and start raising events from methods.

using Marketplace.Framework;

namespace Marketplace.Domain
{
public class ClassifiedAd : Entity
{
public ClassifiedAdId Id { get; }

public ClassifiedAd(ClassifiedAdId id, UserId ownerId)
{
Id = id;
OwnerId = ownerId;
State = ClassifiedAdState.Inactive;

EnsureValidState();

Raise(new Events.ClassifiedAdCreated
{
Id = id,
OwnerId = ownerId
});
}

public void SetTitle(ClassifiedAdTitle title)
{
Title = title;
EnsureValidState();

Raise(new Events.ClassifiedAdTitleChanged
{
Id = Id,
Title = title
});
}

public void UpdateText(ClassifiedAdText text)
{
Text = text;
EnsureValidState();

Raise(new Events.ClassifiedAdTextUpdated
{
Id = Id,
AdText = text
});
}

public void UpdatePrice(Price price)
{
Price = price;
EnsureValidState();

Raise(new Events.ClassifiedAdPriceUpdated
{
Id = Id,
Price = Price.Amount,
CurrencyCode = Price.Currency.CurrencyCode
});
}

public void RequestToPublish()
{
State = ClassifiedAdState.PendingReview;
EnsureValidState();

Raise(new Events.ClassidiedAdSentForReview{Id = Id});
}

// Rest of the entity code remains the same
}
}

So now, if we imagine how our entity is used from the application service layer (which we will be discussing in details later in this book), it could look like this:

public async Task Handle(RequestToPublish command)
{
var entity = await _repository.Load<ClassifiedAd>(command.Id);
entity.RequestToPublish();
await _repository.Save(entity);

foreach (var @event in entity.GetChanges())
{
await _bus.Publish(@event);
}
}

This code is not production ready, as you could imagine, but serves the purpose of demonstration of how domain events can be used for integration between different parts of the system. If we publish events to some message bus and other components in our system subscribe to those messages, they can execute reactive behavior and make some changes in their domain models, or execute some particular actions, like sending emails, text messages or real-time notifications. With modern single-page application frameworks that embrace client-side state management, you can even update information that your users have currently in their browsers, to enable real-time updates in web applications as well.

One small remark about the code that instantiates events. There we assign values of value objects to primitive types directly. It is done using implicit conversion feature of C#, and the implementation looks like this:

using System;

namespace Marketplace.Domain
{
public class ClassifiedAdId
{
private readonly Guid _value;

public ClassifiedAdId(Guid value)
{
if (value == default)
throw new ArgumentNullException(nameof(value),
"Classified Ad id cannot be empty");

_value = value;
}

public static implicit operator Guid(ClassifiedAdId self) => self._value;
}
}

Implicit conversion allows us to simplify the assignments between entity properties and event properties significantly although they are of incompatible types.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.17.137