https://github.com/dreamnucleus/commands
https://github.com/dreamnucleus/commands
c-sharp command-processor commands dotnet dotnet-standard entity-framework
Last synced: 10 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/dreamnucleus/commands
- Owner: dreamnucleus
- License: mit
- Created: 2016-09-03T09:20:56.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2022-12-08T10:55:13.000Z (about 3 years ago)
- Last Synced: 2024-04-30T11:19:26.212Z (over 1 year ago)
- Topics: c-sharp, command-processor, commands, dotnet, dotnet-standard, entity-framework
- Language: C#
- Size: 317 KB
- Stars: 5
- Watchers: 2
- Forks: 1
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[](https://mckendry.visualstudio.com/Commands/_build/latest?definitionId=8) [](https://www.nuget.org/packages/DreamNucleus.Commands/)
# Commands
The aim of this library to help in writing a business layer for applications. It includes a pipeline and notifcations (specific to a type of command) to wrap incoming commands, outgoing results and exceptions.
The base components are:
* Command
* Command Handler
* Command Processor
* Result Processor
* Executing Pipeline
* Executed Pipeline
* Exception Pipeline
* Executing Notification
* Executed Notification
* Exception Notification
Below is a simple example of executing the GetBlogCommand and processing the result
```cs
return await resultProcessor.For(new GetBlogCommand(blogId))
.When(o => o.NotFound()).Return(r => new HttpResult(404))
.When(o => o.Success()).Return(r => new HttpResult(200))
.ExecuteAsync();
```
## NuGet
Packages availble for .NETFramework 4.5 and .NETStandard 1.6
https://www.nuget.org/packages/DreamNucleus.Commands/
```
Install-Package DreamNucleus.Commands
```
```
dotnet add package DreamNucleus.Commands
```
https://www.nuget.org/packages/DreamNucleus.Commands.Extensions/
```
Install-Package DreamNucleus.Commands.Extensions
```
```
dotnet add package DreamNucleus.Commands.Extensions
```
https://www.nuget.org/packages/DreamNucleus.Commands.Autofac/
```
Install-Package DreamNucleus.Commands.Autofac
```
```
dotnet add package DreamNucleus.Commands.Autofac
```
https://www.nuget.org/packages/DreamNucleus.Commands.Extensions.Redis/
```
Install-Package DreamNucleus.Commands.Extensions.Redis
```
```
dotnet add package DreamNucleus.Commands.Extensions.Redis
```
# Example
## Get Blog Command
```cs
// the interfaces let us know what will be returned or what exceptions can be thrown
public class GetBlogCommand : ISuccessResult, INotFoundResult
{
public int BlogId { get; }
public GetBlogCommand(int blogId)
{
BlogId = blogId;
}
}
public class BlogData
{
public int BlogId { get; set; }
public string Url { get; set; }
}
```
## Get Blog Command Handler
```cs
public class GetBlogCommandHandler : IAsyncCommandHandler
{
private readonly BloggingContext context;
public GetBlogCommandHandler(BloggingContext context)
{
this.context = context;
}
public async Task ExecuteAsync(GetBlogCommand command)
{
var blog = await context.Blogs.SingleOrDefaultAsync(b => b.BlogId == command.BlogId);
if (blog == null)
{
throw new NotFoundException();
}
return new BlogData
{
BlogId = blog.BlogId,
Url = blog.Url
};
}
}
```
## Audit Log Pipeline
```cs
// this could be used to write all incoming commands to a audit log
public class AuditLogPipeline : Pipeline
{
private readonly BloggingContext context;
public AuditLogPipeline(BloggingContext context)
{
this.context = context;
}
public override Task ExecutingAsync(IAsyncCommand command)
{
// log the incoming command
return base.ExecutingAsync(command);
}
public override async Task ExecutedAsync(IAsyncCommand command, object result)
{
// log the completed command and result
return base.ExecutedAsync(command, result);
}
public override Task ExceptionAsync(IAsyncCommand command, Exception exception)
{
// log an exception in the command
return base.ExceptionAsync(command, exception);
}
}
```
## Executed Notification
```cs
// this could be used to send an email to the owner... maybe good if you get one visitor a day
public class ExecutedNotification : IExecutedNotification
{
public Task OnExecutedAsync(GetBlogCommand command, BlogData result)
{
// add email request to a queue
return Task.FromResult(0);
}
}
```
## Using Command Processor (with Autofac)
```cs
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType().InstancePerLifetimeScope();
// these can be found and regsiters automatically
containerBuilder.RegisterType().As>();
var container = containerBuilder.Build();
var commandProcessor = new CommandProcessor(new LifetimeScopeService(container.BeginLifetimeScope()));
try
{
var blog = await commandProcessor.ProcessAsync(new GetBlogCommand(1));
}
catch (Exception)
{
// ignore
}
```
## Using Result Processor (with Autofac)
```cs
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType().InstancePerLifetimeScope();
// these can be found and regsiters automatically
containerBuilder.RegisterType().As>();
var container = containerBuilder.Build();
// these are default handlers, local handlers are looked for first
var resultRegister = new ResultRegister();
resultRegister.When().Return(r => new HttpResult(404));
var resultProcessor = new ResultProcessor(resultRegister.Emit(),
new LifetimeScopeService(container.BeginLifetimeScope()));
// exceptions are caught and processed using the handlers
var result = await resultProcessor.For(new GetBlogCommand(1))
.When(o => o.NotFound()).Return(r => new HttpResult(404))
.When(o => o.Success()).Return(r => new HttpResult(200))
.ExecuteAsync();
```
## Using Command Processor (with Autofac and Redis as transport)
```cs
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType().InstancePerLifetimeScope();
// these can be found and regsiters automatically
containerBuilder.RegisterType().As>();
var container = containerBuilder.Build();
var commandProcessor = new CommandProcessor(new LifetimeScopeService(container.BeginLifetimeScope()));
var connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync("localhost");
var redisCommandTransportClient = new RedisCommandTransportClient(connectionMultiplexer, "commands", "results");
var redisCommandTransportServer = new RedisCommandTransportServer(connectionMultiplexer, "commands", "group", "consumer");
var commandProcessorClient = new CommandProcessorClient(redisCommandTransportClient);
var commandProcessorServer = new CommandProcessorServer(commandProcessor, redisCommandTransportServer);
await commandProcessorServer.StartAsync();
try
{
// this command will be executed using redis as the transport between the client and server
var blog = await commandProcessorClient.ProcessAsync(new GetBlogCommand(1));
}
catch (Exception)
{
// ignore
}
await commandProcessorServer.StopAsync();
```