Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
[DataContract(Name = "1b6187f0-88c7-46d5-a22d-b39301765412")]
public class Performer: ValueObject<Performer>
{
Performer() {}
public Performer(string name, string coverImage)
{
// null check
Name = name;
CoverImage = coverImage;
}
[DataMember(Order = 1)]
public string Name { get; private set; }
[DataMember(Order = 2)]
public string CoverImage { get; private set; }
}public class Concert : AggregateRoot<ConcertState>
{
Concert() {} // keep the private parameterless constructor
public Concert(string name, Venue venue, DateTimeOffset startTime, TimeSpan duration)
{
// business logic for creating a concert
Apply(new ConcertAnnounced(...));
}
public void RegisterPerformer(Performer performer)
{
// business logic for registering a performer
Apply(new PerformerRegistered(...));
}
// ...
}[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);
}
}public class ConcertState : AggregateRootState<Concert, ConcertId>
{
public ConcertState()
{
Performers = new List<Performer>();
}
public override ConcertId Id { get; set; }
public string Name { get; private set; }
public Venue Venue { get; private set; }
public DateTimeOffset StartTime { get; private set; }
public TimeSpan Duration { get; private set; }
public List<Performer> Performers { get; private set; }
public void When(ConcertAnnounced @event)
{
// change the state here ...
}
public void When(PerformerRegistered @event)
{
// change the state here ...
}
}[DataContract(Name = "e96d90d0-4943-43f4-8a84-cd90b1217d06")]
public class ConcertId : AggregateRootId
{
const string RootName = "concert";
public ConcertId(AggregateUrn urn) : base(RootName, urn) { }
public ConcertId(string idBase, string tenant) : base(idBase, RootName, tenant) { }
protected ConcertId() { }
}[DataContract(Name = "e96d90d0-4943-43f4-8a84-cd90b1217d06")]
public class ConcertId : AggregateRootId<ConcertId>
{
const string RootName = "concert";
ConcertId() { }
public ConcertId(string id, string tenant) : base(id, RootName, tenant) { }
protected override ConcertId Construct(string id, string tenant)
{
return new ConcertId(id, tenant);
}
}public class Wallet : Entity<UserAggregate, WalletState>
{
public Wallet(UserAggregate root, WalletId entityId, string name, decimal amount) : base(root, entityId)
{
state.EntityId = entityId;
state.Name = name;
state.Amount = amount;
}
public void AddMoney(decimal value, UserId userId)
{
if (value > 0)
{
IEvent @event = new AddMoney(state.EntityId, userId, value, DateTimeOffset.UtcNow);
Apply(@event);
}
}
}public class WalletState : EntityState<WalletId>
{
public override WalletId EntityId { get; set; }
public string Name { get; set; }
public decimal Amount { get; set; }
}[DataContract(Name = "1d23c591-219f-491e-bfb1-a775fe2751b6")]
public class WalletId : EntityId<UserId>
{
protected override ReadOnlySpan<char> EntityName => "wallet";
WalletId() { }
public WalletId(string id, UserId idBase) : base(id.AsSpan(), idBase) { }
}ProjectionDefinition<TState, TId>IBlobIdProjectionDefinition<TState, TId>Subscribe()[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.";
}
}[DataContract(Name = "d4eb8803-2cc7-48dd-9ca1-4512b8d9b88f")]
public class TaskSaga : Saga,
IEventHandler<UserCreated>,
ISagaTimeoutHandler<Message>
{
public TaskSaga(IPublisher<ICommand> commandPublisher, IPublisher<IScheduledMessage> timeoutRequestPublisher) : base(commandPublisher, timeoutRequestPublisher)
{
}
public Task HandleAsync(UserCreated @event)
{
var message = new Message();
message.Info = @event.Name + "was created yesterday.";
message.PublishAt = DateTimeOffset.UtcNow.AddDays(1).DateTime;
message.Timestamp = DateTimeOffset.UtcNow;
RequestTimeout<Message>(message);
return Task.CompletedTask;
}
public Task HandleAsync(Message sagaTimeout)
{
Console.WriteLine(sagaTimeout.Info);
return Task.CompletedTask;
}
}
[DataContract(Name = "543e8e28-0dcb-4d41-98de-f701e403dbb2")]
public class Message : IScheduledMessage
{
public string Info { get; set; }
public DateTime PublishAt { get; set; }
public DateTimeOffset Timestamp { get; set; }
}[DataContract(Name = "c94513d1-e5ee-4aae-8c0f-6e85b63a4e03")]
public class TaskProjection : ProjectionDefinition<TaskProjectionData, TaskId>,
IEventHandler<TaskCreated>
{
public TaskProjection()
{
Subscribe<TaskCreated>(x => new TaskId(x.Id.NID));
}
public Task HandleAsync(TaskCreated @event)
{
Data task = new Data();
task.Id = @event.Id;
task.UserId = @event.UserId;
task.Name = @event.Name;
task.Timestamp = @event.Timestamp;
State.Tasks.Add(task);
return Task.CompletedTask;
}
public IEnumerable<Data> GetTaskByName(string name)
{
return State.Tasks.Where(x => x.Name.Equals(name));
}
}[DataContract(Name = "c135893e-b9e3-453a-b0e0-53545094ec5d")]
public class TaskProjectionData
{
public TaskProjectionData()
{
Tasks = new List<Data>();
}
[DataMember(Order = 1)]
public List<Data> Tasks { get; set; }
[DataContract(Name = "317b3cbb-593a-4ffc-8284-d5f5c599d8ae")]
public class Data
{
[DataMember(Order = 1)]
public TaskId Id { get; set; }
[DataMember(Order = 2)]
public UserId UserId { get; set; }
[DataMember(Order = 3)]
public string Name { get; set; }
[DataMember(Order = 4)]
public DateTimeOffset CreatedAt { get; set; }
[DataMember(Order = 5)]
public DateTimeOffset Timestamp { get; set; }
}
}// TODO: give a relevant example
[DataContract(Name = "af157a4d-7608-4c9d-8e42-63bd483a8ad4")]
public class ExampleEfProjection : IProjection,
IEventHandler<ExampleCreated>
{
public DbContext Context { get; set; }
public void Handle(ExampleCreated @event)
{
var exampleDto = new ExampleDto(@event.Id, @event.Name);
Context.Examples.Add(exampleDto);
Context.SaveChanges();
}
}// TODO: give a relevant example
[DataContract(Name = "bae8bd10-9903-4960-95c4-b4fa4688a860")]
public class ExampleByIdProjection : ProjectionDefinition<ExampleByIdProjectionState, ExampleId>,
IEventHandler<ExampleCreated>,
IAmNotSnapshotable
{
// ...
}public class GetExampleController : ControllerBase
{
private IProjectionReader projectionReader;
public GetExampleController(IProjectionReader projectionReader)
{
this.projectionReader = projectionReader;
}
public async Task<IActionResult> GetExample(GetExampleRequest request)
{
var id = ExampleId.New(request.Tenant, request.Id);
var result = await projectionReader.GetAsync<ExampleByIdProjection>(id);
if (result.IsSuccess)
return Ok(new GetExampleResponse(result.Data.State));
else
return BadRequest(result.Error);
}
public class GetExampleResponse
{
// ...
}
}public class ConcertAppService : AggregateRootApplicationService<Concert>,
ICommandHandler<AnnounceConcert>,
ICommandHandler<RegisterPerformer>
{
...
public void Handle(AnnounceConcert command)
{
if (Repository.TryLoad<Concert>(command.Id, out _))
return;
var concert = new Concert(...);
Repository.Save(concert);
}
public void Handle(RegisterPerformer command)
{
Update(command.Id, x => x.RegisterPerformer(...));
}
...
}[DataContract(Name = "a44e9a38-ab13-4f86-844a-86fefa925b53")]
public class AlertPort : IPort,
IEventHandler<UserCreated>
{
public Task HandleAsync(UserCreated @event)
{
//Implement your custom logic here
return Task.CompletedTask;
}
}