Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Luca Briguglia committed Nov 23, 2019
2 parents 17fadfd + ef6dffe commit 74cbef4
Show file tree
Hide file tree
Showing 37 changed files with 743 additions and 82 deletions.
15 changes: 11 additions & 4 deletions Kledex.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
LICENSE = LICENSE
package.json = package.json
README.md = README.md
EndProjectSection
EndProject
Expand Down Expand Up @@ -68,10 +67,12 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{1282A8FB-D7A5-4562-8B9B-1C27B83EE580}"
ProjectSection(SolutionItems) = preProject
docs\Basics.md = docs\Basics.md
docs\Caching.md = docs\Caching.md
docs\Caching-Queries.md = docs\Caching-Queries.md
docs\Command-Sequence.md = docs\Command-Sequence.md
docs\Command-Validation.md = docs\Command-Validation.md
docs\Commands.md = docs\Commands.md
docs\Configuration.md = docs\Configuration.md
docs\Domain.md = docs\Domain.md
docs\Domain-Commands.md = docs\Domain-Commands.md
docs\Events.md = docs\Events.md
docs\index.md = docs\index.md
docs\Installation.md = docs\Installation.md
Expand All @@ -81,7 +82,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{1282A8FB-D
docs\Release-Notes.md = docs\Release-Notes.md
docs\Samples.md = docs\Samples.md
docs\UI.md = docs\UI.md
docs\Validation.md = docs\Validation.md
docs\With-Event-Sourcing.md = docs\With-Event-Sourcing.md
docs\Without-Event-Sourcing.md = docs\Without-Event-Sourcing.md
EndProjectSection
Expand All @@ -95,6 +95,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "img", "img", "{05D6EE8E-C35
docs\assets\img\SendCommandFlow.svg = docs\assets\img\SendCommandFlow.svg
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kledex.Sample.CommandSequence", "samples\Kledex.Sample.CommandSequence\Kledex.Sample.CommandSequence.csproj", "{6DB19E10-1942-44CC-B592-01A34CEE8C77}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -177,6 +179,10 @@ Global
{60755BA7-4F80-4AEC-8B0E-32414C1C6553}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60755BA7-4F80-4AEC-8B0E-32414C1C6553}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60755BA7-4F80-4AEC-8B0E-32414C1C6553}.Release|Any CPU.Build.0 = Release|Any CPU
{6DB19E10-1942-44CC-B592-01A34CEE8C77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6DB19E10-1942-44CC-B592-01A34CEE8C77}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6DB19E10-1942-44CC-B592-01A34CEE8C77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6DB19E10-1942-44CC-B592-01A34CEE8C77}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -203,6 +209,7 @@ Global
{60755BA7-4F80-4AEC-8B0E-32414C1C6553} = {A9692D21-8091-4A3F-8F7C-54B821EFDF97}
{7883593A-6225-4485-8EAE-E4EF3B799285} = {1282A8FB-D7A5-4562-8B9B-1C27B83EE580}
{05D6EE8E-C356-4BF1-A015-90471F4E682E} = {7883593A-6225-4485-8EAE-E4EF3B799285}
{6DB19E10-1942-44CC-B592-01A34CEE8C77} = {FF129AB8-1B8D-4BAA-AB1F-39D2FA497397}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {154500C3-9A83-4F15-9D78-E1C285AD80AE}
Expand Down
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ With Kledex you can automatically dispatch events to a message bus (Service Bus

| Package | Latest Stable |
| --- | --- |
| [Kledex](https://www.nuget.org/packages/Kledex) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex) |
| [Kledex.Store.Cosmos.Mongo](https://www.nuget.org/packages/Kledex.Store.Cosmos.Mongo) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.Store.Cosmos.Mongo) |
| [Kledex.Store.Cosmos.Sql](https://www.nuget.org/packages/Kledex.Store.Cosmos.Sql) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.Store.Cosmos.Sql) |
| [Kledex.Store.EF.MySql](https://www.nuget.org/packages/Kledex.Store.EF.MySql) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.Store.EF.MySql) |
| [Kledex.Store.EF.PostgreSql](https://www.nuget.org/packages/Kledex.Store.EF.PostgreSql) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.Store.EF.PostgreSql) |
| [Kledex.Store.EF.Sqlite](https://www.nuget.org/packages/Kledex.Store.EF.Sqlite) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.Store.EF.Sqlite) |
| [Kledex.Store.EF.SqlServer](https://www.nuget.org/packages/Kledex.Store.EF.SqlServer) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.Store.EF.SqlServer) |
| [Kledex.Store.EF.InMemory](https://www.nuget.org/packages/Kledex.Store.EF.InMemory) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.Store.EF.InMemory) |
| [Kledex.Bus.ServiceBus](https://www.nuget.org/packages/Kledex.Bus.ServiceBus) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.Bus.ServiceBus) |
| [Kledex.Bus.RabbitMQ](https://www.nuget.org/packages/Kledex.Bus.RabbitMQ) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.Bus.RabbitMQ) |
| [Kledex.Validation.FluentValidation](https://www.nuget.org/packages/Kledex.Validation.FluentValidation) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.Validation.FluentValidation) |
| [Kledex.Caching.Memory](https://www.nuget.org/packages/Kledex.Caching.Memory) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.Caching.Memory) |
| [Kledex.Caching.Redis](https://www.nuget.org/packages/Kledex.Caching.Redis) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.Caching.Redis) |
| [Kledex.UI](https://www.nuget.org/packages/Kledex.UI) | [![Nuget Package](https://img.shields.io/badge/nuget-2.2.1-blue.svg)](https://www.nuget.org/packages/Kledex.UI) |
| [Kledex](https://www.nuget.org/packages/Kledex) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex) |
| [Kledex.Store.Cosmos.Mongo](https://www.nuget.org/packages/Kledex.Store.Cosmos.Mongo) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.Store.Cosmos.Mongo) |
| [Kledex.Store.Cosmos.Sql](https://www.nuget.org/packages/Kledex.Store.Cosmos.Sql) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.Store.Cosmos.Sql) |
| [Kledex.Store.EF.MySql](https://www.nuget.org/packages/Kledex.Store.EF.MySql) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.Store.EF.MySql) |
| [Kledex.Store.EF.PostgreSql](https://www.nuget.org/packages/Kledex.Store.EF.PostgreSql) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.Store.EF.PostgreSql) |
| [Kledex.Store.EF.Sqlite](https://www.nuget.org/packages/Kledex.Store.EF.Sqlite) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.Store.EF.Sqlite) |
| [Kledex.Store.EF.SqlServer](https://www.nuget.org/packages/Kledex.Store.EF.SqlServer) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.Store.EF.SqlServer) |
| [Kledex.Store.EF.InMemory](https://www.nuget.org/packages/Kledex.Store.EF.InMemory) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.Store.EF.InMemory) |
| [Kledex.Bus.ServiceBus](https://www.nuget.org/packages/Kledex.Bus.ServiceBus) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.Bus.ServiceBus) |
| [Kledex.Bus.RabbitMQ](https://www.nuget.org/packages/Kledex.Bus.RabbitMQ) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.Bus.RabbitMQ) |
| [Kledex.Validation.FluentValidation](https://www.nuget.org/packages/Kledex.Validation.FluentValidation) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.Validation.FluentValidation) |
| [Kledex.Caching.Memory](https://www.nuget.org/packages/Kledex.Caching.Memory) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.Caching.Memory) |
| [Kledex.Caching.Redis](https://www.nuget.org/packages/Kledex.Caching.Redis) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.Caching.Redis) |
| [Kledex.UI](https://www.nuget.org/packages/Kledex.UI) | [![Nuget Package](https://img.shields.io/badge/nuget-2.3.0-blue.svg)](https://www.nuget.org/packages/Kledex.UI) |
11 changes: 6 additions & 5 deletions docs/Basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ It's also possible to use the following interfaces directly without going throug

The following is the mapping between dispatcher methods and handlers:

| Method | Handler |
| --- | --- |
| SendAsync | ICommandHandlerAsync |
| PublishAsync | IEventHandlerAsync |
| GetResultAsync | IQueryHandlerAsync |
| Method | Parameter | Handler |
| --- | --- | --- |
| SendAsync | ICommand | ICommandHandlerAsync |
| SendAsync | ICommandSequence | ISequenceCommandHandlerAsync |
| PublishAsync | IEvent | IEventHandlerAsync |
| GetResultAsync | IQuery | IQueryHandlerAsync |

## Main Flow

Expand Down
8 changes: 6 additions & 2 deletions docs/Caching.md → docs/Caching-Queries.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Caching
# Caching Queries

With Kledex it is possible to automatically cache the result of a query using one of the available providers (Memory or Redis). First, you need to configure a cache provider as explained [here](Configuration#caching). Next, as per any normal queries, create the model for the result and a query. The only difference with a normal query is that it needs to inherit from the **CacheableQuery<>** abstract class (or implements the **ICacheableQuery<>** interface) in order to set the _Cache Key_ and the _Cache Time_:
With Kledex it is possible to automatically cache the result of a query using one of the available providers (Memory or Redis). First, you need to configure a cache provider as explained [here](Configuration#caching). Next, as per any normal queries, create the model for the result and the query. The only difference with a normal query is that it needs to inherit from the **CacheableQuery<>** abstract class (or implements the **ICacheableQuery<>** interface) in order to set the _Cache Key_ and the _Cache Time_:

```C#
public class Something
Expand Down Expand Up @@ -48,3 +48,7 @@ var something = await _dispatcher.GetResultAsync(query);
```

As you can see the only difference is in the query class.

## Related

- [Queries](Queries)
120 changes: 120 additions & 0 deletions docs/Command-Sequence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Command Sequence

With Kledex is possible to create a squence of commands that will be executed in the specified order.

First, create the commands that need to be part of the sequence:

```C#
public class FirstCommand : Command
{
}

public class SecondCommand : Command
{
}

public class ThirdCommand : Command
{
}
```

Next, as you would have done normally create the handlers for your commands.
The only difference is that the handlers need to implement the **ISequenceCommandHandlerAsync<>** interface.
The _HandlerAsync_ of this interface accepts an extra parameter which is a _CommandResponse_.
Kledex will pass automatically the command response of the previous command in the sequence.
For the first hanlder it would obviously be null.

First command handler:

```C#
public class FirstCommandHandler : ISequenceCommandHandlerAsync<FirstCommand>
{
public Task<CommandResponse> HandleAsync(FirstCommand command, CommandResponse previousStepResponse)
{
Console.WriteLine("Message from first command handler");

return Task.FromResult(new CommandResponse
{
Result = "First result"
});
}
}
```

Second command handler:

```C#
public class SecondCommandHandler : ISequenceCommandHandlerAsync<SecondCommand>
{
public Task<CommandResponse> HandleAsync(SecondCommand command, CommandResponse previousStepResponse)
{
Console.WriteLine($"Message from second command handler. Result from first handler: {previousStepResponse.Result}");

return Task.FromResult(new CommandResponse
{
Result = "Second result"
});
}
}
```

Third command handler:

```C#
public class ThirdCommandHandler : ISequenceCommandHandlerAsync<ThirdCommand>
{
public Task<CommandResponse> HandleAsync(ThirdCommand command, CommandResponse previousStepResponse)
{
Console.WriteLine($"Message from third command handler. Result from second handler: {previousStepResponse.Result}");

return Task.FromResult(new CommandResponse
{
Result = "Third result"
});
}
}
```

Last, create a class that inherits from the _CommandSequence_ abstract class and add all your commands:

```C#
public class SampleCommandSequence : CommandSequence
{
public SampleCommandSequence()
{
AddCommand(new FirstCommand());
AddCommand(new SecondCommand());
AddCommand(new ThirdCommand());
}
}
```

Use the dispatcher to execute the command sequence:

```C#
await dispatcher.SendAsync(new SampleCommandSequence());
```

You can also get a result from the sequence which will be the value of the Result property of the command response of the last command in the sequence (in our example of the ThirdCommand):

```C#
var result = await dispatcher.SendAsync<string>(new SampleCommandSequence());
```

The following is the output generated:

```
Message from first command handler
Message from second command handler. Result from first handler: First result
Message from third command handler. Result from second handler: Second result
Final result: Third result
```

You can find the sample code [here](https://github.com/lucabriguglia/Kledex/tree/master/samples/Kledex.Sample.CommandSequence)

## Related

- [Commands](Commands)
- [Command Validation](Command-Validation)
- [Domain Commands With Event Sourcing](With-Event-Sourcing)
- [Domain Commands Without Event Sourcing](Without-Event-Sourcing)
13 changes: 10 additions & 3 deletions docs/Validation.md → docs/Command-Validation.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Validation
# Command Validation

Kledex can automatically call a validation service before a command is sent to the command handler. In order to do that a validation provider needs to be installed and configured as described [here](Configuration#validation). You can configure to validate all commands by setting the option _ValidateCommands_ to _true_ when registering the main package as described [here](Configuration#main) or on a case by case basis by setting the _Validate_ property to _true_ at the command level:

Expand All @@ -16,7 +16,7 @@ public class CreateProduct : DomainCommand<Product>
}
```

The only validation provider currenlty available is the _FluentValidation_ provider. Thereofore, you need to create a class that inherits from the **AbstractValidator<>** class of _FluentValidation_:
The only validation provider currenlty available is the _FluentValidation_ provider. Therefore, you need to create a class that inherits from the **AbstractValidator<>** class of _FluentValidation_:

```C#
public CreateProductValidator()
Expand All @@ -34,6 +34,13 @@ public CreateProductValidator()
}
```

Kledex will automatically resolve and execute it.
Kledex will automatically resolve and execute it. To know more about FluentValidation please visit their [website](https://fluentvalidation.net).

Note that the assemblies that contain the validators need to be registered the same way command, query and event handlers are as explained [here](Configuration#main).

## Related

- [Commands](Commands)
- [Command Sequence](Command-Sequence)
- [Domain Commands With Event Sourcing](With-Event-Sourcing)
- [Domain Commands Without Event Sourcing](Without-Event-Sourcing)
11 changes: 8 additions & 3 deletions docs/Commands.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Commands

The dispatcher will automatically publish any events returned by the handler unless the property **PublishEvents** is set to _false_ on a global or a command level.
The dispatcher will automatically publish any events returned by the handler unless the property **PublishEvents** is set to _false_ on a global or a command level (see [Configuration](Configuration#main)).

First, create a command that inherits from the **Command** class:

Expand Down Expand Up @@ -87,6 +87,11 @@ public class DoSomethingHandler : ICommandHandlerAsync<DoSomething>
}
```

Note the two optional properties can be set in the commands: **UserId** and **Source**.
Note that two optional properties can be set in the commands: **UserId** and **Source**.

It is possible to validate the command automatically before it is sent to the command handler. [Click here to know more](Validation).
## Related

- [Command Validation](Command-Validation)
- [Command Sequence](Command-Sequence)
- [Domain Commands With Event Sourcing](With-Event-Sourcing)
- [Domain Commands Without Event Sourcing](Without-Event-Sourcing)
6 changes: 6 additions & 0 deletions docs/Domain-Commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Domain Commands

Working with your domain model:

- [Domain Commands With Event Sourcing](With-Event-Sourcing)
- [Domain Commands Without Event Sourcing](Without-Event-Sourcing)
5 changes: 0 additions & 5 deletions docs/Domain.md

This file was deleted.

4 changes: 3 additions & 1 deletion docs/Queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ var query = new GetSomething { Id = 123 };
var something = await _dispatcher.GetResultAsync(query);
```

It is possible to automatically cahce the result using one of the cache providers. [Click here to know more](Caching).
## Related

- [Caching Queries](Caching-Queries)
14 changes: 13 additions & 1 deletion docs/UI.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# UI

Work in progress...
The UI package is an experimental package that can be used to display information about an aggregate and its events:

```C#
var model = await _dispatcher.GetResultAsync(new GetAggregateModel
{
AggregateRootId = id
});
```

The model will contain the list of all events of the aggregate ordered by time stamp descending.
Further improvements will be made in coming versions.

You can find a sample usage [here](https://github.com/lucabriguglia/Kledex/blob/master/samples/Kledex.Sample.EventSourcing/Pages/Edit.cshtml.cs).
9 changes: 7 additions & 2 deletions docs/With-Event-Sourcing.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# With Event Sourcing
# Domain Commands With Event Sourcing

By using the _SendAsync_ method, the dispatcher will automatically publish the events set in the response of the handler and save those events to the domain store (alongside aggregate and command).

Expand Down Expand Up @@ -185,4 +185,9 @@ await dispatcher.SendAsync(new UpdateProductTitle
A new event is saved and the read model is updated using the event handler.
Next time the aggregate is loaded from history using the repository, two events will be applied in order to recreate the current state.

It is possible to validate the command automatically before it is sent to the command handler. [Click here to know more](Validation).
## Related

- [Commands](Commands)
- [Command Validation](Command-Validation)
- [Command Sequence](Command-Sequence)
- [Domain Commands Without Event Sourcing](Without-Event-Sourcing)
Loading

0 comments on commit 74cbef4

Please sign in to comment.