Skip to content

Latest commit

 

History

History
123 lines (90 loc) · 3.36 KB

CommandQuery.md

File metadata and controls

123 lines (90 loc) · 3.36 KB

CommandQuery ⚙️

build CodeFactor

Command Query Separation for .NET and C#

Commands

Commands change the state of a system but [traditionally] do not return a value. They write (create, update, delete) data.

Commands implement the marker interface ICommand and command handlers implement ICommandHandler<in TCommand>.

public class FooCommand : ICommand
{
    public string Value { get; set; }
}

public class FooCommandHandler : ICommandHandler<FooCommand>
{
    private readonly ICultureService _cultureService;

    public FooCommandHandler(ICultureService cultureService)
    {
        _cultureService = cultureService;
    }

    public async Task HandleAsync(FooCommand command, CancellationToken cancellationToken)
    {
        if (string.IsNullOrEmpty(command.Value)) throw new FooCommandException("Value cannot be null or empty", 1337, "Try setting the value to 'en-US'");

        _cultureService.SetCurrentCulture(command.Value);

        await Task.CompletedTask;
    }
}

Commands can also return a result.

public class BazCommand : ICommand<Baz>
{
    public string Value { get; set; }
}

public class Baz
{
    public bool Success { get; set; }
}

public class BazCommandHandler : ICommandHandler<BazCommand, Baz>
{
    private readonly ICultureService _cultureService;

    public BazCommandHandler(ICultureService cultureService)
    {
        _cultureService = cultureService;
    }

    public async Task<Baz> HandleAsync(BazCommand command, CancellationToken cancellationToken)
    {
        var result = new Baz();

        try
        {
            _cultureService.SetCurrentCulture(command.Value);

            result.Success = true;
        }
        catch
        {
            // TODO: log
        }

        return await Task.FromResult(result);
    }
}

Commands with result implement the marker interface ICommand<TResult> and command handlers implement ICommandHandler<in TCommand, TResult>.

Queries

Queries return a result and do not change the observable state of the system (are free of side effects). They read and return data.

Queries implement the marker interface IQuery<TResult> and query handlers implement IQueryHandler<in TQuery, TResult>.

public class BarQuery : IQuery<Bar>
{
    public int Id { get; set; }
}

public class Bar
{
    public int Id { get; set; }

    public string Value { get; set; }
}

public class BarQueryHandler : IQueryHandler<BarQuery, Bar>
{
    private readonly IDateTimeProxy _dateTime;

    public BarQueryHandler(IDateTimeProxy dateTime)
    {
        _dateTime = dateTime;
    }

    public async Task<Bar> HandleAsync(BarQuery query, CancellationToken cancellationToken)
    {
        var result = new Bar { Id = query.Id, Value = _dateTime.Now.ToString("F") };

        return await Task.FromResult(result);
    }
}

Samples