arrow-left

All pages
gitbookPowered by GitBook
1 of 5

Loading...

Loading...

Loading...

Loading...

Loading...

Events

An event is something significant that has happened in the domain. It encapsulates all relevant data of the action that happened.

circle-check

You can/should/must...

  • an event must be immutable

  • an event must represent a domain event that already happened with a name in the past tense

  • an event can be dispatched only by one aggregate

To create an event with Cronus, just use the IEvent markup interface.

circle-info

Cronus uses the ToString() method for logging, so you can override it to generate user-readable logs. Otherwise, the name of the event class will be used for log messages.

Signals

https://github.com/Elders/Cronus/issues/262arrow-up-right

Messages

Public Events

https://github.com/Elders/Cronus/issues/277arrow-up-right

[DataContract(Name = "728fc4e7-628b-4962-bd68-97c98aa05694")]
public class TaskCreated : IEvent
{
    TaskCreated() { }

    public TaskCreated(TaskId id, UserId userId, string name, DateTimeOffset timestamp)
    {
        Id = id;
        UserId = userId;
        Name = name;
        CreatedAt = DateTimeOffset.UtcNow;
        Timestamp = timestamp;
    }

    [DataMember(Order = 1)]
    public TaskId Id { get; private set; }

    [DataMember(Order = 2)]
    public UserId UserId { get; private set; }

    [DataMember(Order = 3)]
    public string Name { get; private set; }

    [DataMember(Order = 4)]
    public DateTimeOffset CreatedAt { get; private set; }

    [DataMember(Order = 5)]
    public DateTimeOffset Timestamp { get; private set; }

    public override string ToString()
    {
        return $"Task with id '{Id}' and name '{Name}' for user [{UserId}] at {CreatedAt} has been created.";
    }
}

Commands

A command is a simple immutable object that is sent to the domain to trigger a state change. There should be a single command handler for each command. It is recommended to use imperative verbs when naming commands together with the name of the aggregate they operate on.

Application Serviceschevron-right

It is possible for a command to get rejected if the data it holds is incorrect or inconsistent with the current state of the aggregate.

circle-check

You can/should/must...

  • a command must be immutable

  • a command should clearly state a business intent with a name in the imperative form

  • a command can be rejected due to domain validation, error or other reason

  • a command must update only one aggregate

hashtag
Defining a command

You can define a command with Cronus using the ICommand markup interface. All commands get serialized and deserialized, that's why you need to keep the parameterless constructor and specify data contracts.

circle-info

Cronus uses the ToString() method for logging, so you can override it to generate user-readable logs. Otherwise, the name of the command class will be used for log messages.

hashtag
Publishing a command

To publish a command, inject an instance ofIPublisher<ICommand> into your code and invoke the Publish() method passing the command. This method will return true if the command has been published successfully through the configured transport. You can also use one of the overrides of the Publish() method to delay or schedule a command.

Serializationchevron-right
[DataContract(Name = "857d960c-4b91-49cc-98fd-fa543906c52d")]
public class CreateTask : ICommand
{
    public CreateTask() { }

    public CreateTask(TaskId id, UserId userId, string name, DateTimeOffset timestamp)
    {
        if (id is null) throw new ArgumentNullException(nameof(id));
        if (userId is null) throw new ArgumentNullException(nameof(userId));
        if (name is null) throw new ArgumentNullException(nameof(name));
        if (timestamp == default) throw new ArgumentNullException(nameof(timestamp));

        Id = id;
        UserId = userId;
        Name = name;
        Timestamp = timestamp;
    }

    [DataMember(Order = 1)]
    public TaskId Id { get; private set; }

    [DataMember(Order = 2)]
    public UserId UserId { get; private set; }

    [DataMember(Order = 3)]
    public string Name { get; private set; }

    [DataMember(Order = 4)]
    public DateTimeOffset Timestamp { get; private set; }

    public override string ToString()
    {
        return $"Create a task with id '{Id}' and name '{Name}' for user [{UserId}].";
    }
}
[ApiController]
[Route("[controller]/[action]")]
public class TaskController : ControllerBase
{
    private readonly IPublisher<ICommand> _publisher;

    public TaskController(IPublisher<ICommand> publisher)
    {
        _publisher = publisher;
    }

    [HttpPost]
    public IActionResult CreateTask(CreateTaskRequest request)
    {
        string id = Guid.NewGuid().ToString();
        string Userid = Guid.NewGuid().ToString();
        TaskId taskId = new TaskId(id);
        UserId userId = new UserId(Userid);
        var expireDate = DateTimeOffset.UtcNow;
        expireDate.AddDays(request.DaysActive);

        CreateTask command = new CreateTask(taskId, userId, request.Name, expireDate);

        if (_publisher.Publish(command) == false)
        {
            return Problem($"Unable to publish command. {command.Id}: {command.Name}");
        };
        return Ok(id);
    }
}