Skip to content

Commit

Permalink
Merge pull request #15 from carl-berg/simplified-interface
Browse files Browse the repository at this point in the history
New common IRequest interface
  • Loading branch information
carl-berg committed Aug 24, 2018
2 parents 07ee183 + 4f979a4 commit f453234
Show file tree
Hide file tree
Showing 23 changed files with 355 additions and 249 deletions.
190 changes: 106 additions & 84 deletions README.md
Expand Up @@ -5,97 +5,123 @@ A mediator implementation in C#, inspired by [a blog post series](http://lostech
## Using the mediator
Executing a query:

var something = mediator.Request(new GetSomething());
var something = mediator.Request(new GetSomething.Query());

//Async version
var result = await mediator.Request(new GetSomethingAsync());
// async version
var result = await mediator.Request(new GetSomething.AsyncQuery());

Executing a command:

var result = mediator.Send(new DoSomething());

//Async version
var result = await mediator.Send(new DoSomethingAsync());
var result = mediator.Send(new DoSomething.Command());

// async version
var result = await mediator.Send(new DoSomething.AsyncCommand());

## Queries
public class GetSomething : IQuery<Something>
{
public GetSomething(/* query parameters */)
{
// ...
}
}

//Async version
public class GetSomethingAsync : IAsyncQuery<Something>
public class GetSomething
{
public GetSomething(/* query parameters */)
{
// ...
}
}
public class Query : IQuery<Result>
{
public Query(/* query parameters */)
{
// ...
}
}

//Async version
public class AsyncQuery : IAsyncQuery<Result>
{
public AsyncQuery(/* query parameters */)
{
// ...
}
}

public class Handler :
IQueryHandler<Query, Result>,
IAsyncQueryHandler<AsyncQuery, Result>
{
public SomethingHandler( /* interesting dependencies here */)
{
// ...
}

public Result Handle(Query query)
{
// ...
}

public async Task<Result> Handle(AsyncQuery query)
{
// ...
}
}

public class Result { }
}

## Commands
public class DoSomething : ICommand<Something>
{
public DoSomething(/* command parameters */)
{
// ...
}
}

//Async version
public class DoSomethingAsync : IAsyncCommand<Something>
{
public DoSomething(/* command parameters */)
{
// ...
}
}
public class DoSomething
{
public class Command : ICommand<Result>
{
public Command(/* command parameters */)
{
// ...
}
}

## Query Handler
public class SomethingQueryHandler :
IQueryHandler<GetSomething, Something>,
IAsyncQueryHandler<GetSomethingAsync, Something>
{
public SomethingHandler( /* interesting dependencies here */)
{
// ...
}

public Something Handle(GetSomething query)
{
// ...
}

public async Task<Something> Handle(GetSomethingAsync query)
{
// ...
}
}
public class AsyncCommand : IAsyncCommand<Result>
{
public AsyncCommand(/* command parameters */)
{
// ...
}
}

## Command Handler
public class SomethingCommandHandler :
ICommandHandler<DoSomething, SomethingResult>,
IAsyncCommandHandler<DoSomethingAsync, SomethingResult>
{
public SomethingHandler(/* interesting dependencies here */)
{
// ...
}

public SomethingResult Handle(DoSomething command)
{
// ...
}

public async Task<SomethingResult> Handle(DoSomethingAsync command)
{
// ...
}
}
public class Handler :
ICommandHandler<Command, Result>,
IAsyncCommandHandler<AsyncCommand, Result>
{
public Handler(/* interesting dependencies here */)
{
// ...
}

public Result Handle(Command command)
{
// ...
}

public async Task<Result> Handle(AsyncCommand command)
{
// ...
}
}

public class Result { }
}

## Simple Mediator
The mediator also implements a simpler interface `ISimpleMediator` in case you find the Command/Query names to obtuse and simply want to use a single request method. The simple mediator can be used like this:

var something = await mediator.Request(new Feature.Request());

with something like this as the implementation:

public class Feture
{
public class Request : IAsyncRequest<Response> { }

public class Handler : IAsyncRequestHandler<Request, Response>
{
public Response Handle(Request request) => new Response();
}

public class Response { }
}

## Dependency injection
The appeaser library is ment to be used together with dependency injection. As I am not a big believer in adding a dependency resolver for each dependency injection library out there (but in the future I might implement built in dependency injection of some kind), you can easily handle it yourself by implementing the `IMediatorHandlerFactory` interface like this:
Expand Down Expand Up @@ -127,10 +153,8 @@ The appeaser library is ment to be used together with dependency injection. As I
Scan(s =>
{
s.TheCallingAssembly();
s.ConnectImplementationsToTypesClosing(typeof(IQueryHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(IAsyncQueryHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(ICommandHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(IAsyncCommandHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(IRequestHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(IAsyncRequestHandler<,>));
});
}
}
Expand All @@ -146,10 +170,8 @@ The appeaser library is ment to be used together with dependency injection. As I
Scan(s =>
{
s.TheCallingAssembly();
s.ConnectImplementationsToTypesClosing(typeof(IQueryHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(IAsyncQueryHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(ICommandHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(IAsyncCommandHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(IRequestHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(IAsyncRequestHandler<,>));
});
}
}
Expand Up @@ -5,7 +5,7 @@

namespace Appeaser.Tests
{
public class LamarIntegrationTest
public class LamarIntegrationTest : TestBase
{
private Container _container;

Expand All @@ -15,13 +15,12 @@ public LamarIntegrationTest()
{
configure.ForSingletonOf<IMediatorHandlerFactory>().Use<LamarMediatorHandlerFactory>();
configure.For<IMediator>().Use<Mediator>();
configure.For<ISimpleMediator>().Use<Mediator>();
configure.Scan(s =>
{
s.AssemblyContainingType<LamarIntegrationTest>();
s.ConnectImplementationsToTypesClosing(typeof(IQueryHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(IAsyncQueryHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(ICommandHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(IAsyncCommandHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(IRequestHandler<,>));
s.ConnectImplementationsToTypesClosing(typeof(IAsyncRequestHandler<,>));
});
});
}
Expand All @@ -35,35 +34,43 @@ public void Can_Resolve_Mediator()
}

[Fact]
public void Can_Resolve_Request_Handlers()
public void Can_Resolve_Simple_Mediator()
{
var mediator = _container.GetInstance<ISimpleMediator>();
Assert.NotNull(mediator);
Assert.IsType<Mediator>(mediator);
}

[Fact]
public void Can_Resolve_Query_Handlers()
{
var mediator = _container.GetInstance<IMediator>();
var result = mediator.Request(new TestFeatureOne.Request());
Assert.NotNull(result);
var result = mediator.Request(new QueryFeature.Query());
Assert.Equal(UnitType.Default, result);
}

[Fact]
public async Task Can_Resolve_Async_Request_Handlers()
public async Task Can_Resolve_Async_Query_Handlers()
{
var mediator = _container.GetInstance<IMediator>();
var result = await mediator.Request(new TestFeatureOne.AsyncRequest());
Assert.NotNull(result);
var result = await mediator.Request(new QueryFeature.AsyncQuery());
Assert.Equal(UnitType.Default, result);
}

[Fact]
public void Can_Resolve_Command_Handlers()
{
var mediator = _container.GetInstance<IMediator>();
var result = mediator.Send(new TestFeatureTwo.Command());
Assert.NotNull(result);
var result = mediator.Send(new CommandFeature.Command());
Assert.Equal(UnitType.Default, result);
}

[Fact]
public async Task Can_Resolve_Async_Command_Handlers()
{
var mediator = _container.GetInstance<IMediator>();
var result = await mediator.Send(new TestFeatureTwo.AsyncCommand());
Assert.NotNull(result);
var result = await mediator.Send(new CommandFeature.AsyncCommand());
Assert.Equal(UnitType.Default, result);
}

public class LamarMediatorHandlerFactory : IMediatorHandlerFactory
Expand All @@ -80,31 +87,5 @@ public object GetHandler(Type handlerType)
return _container.TryGetInstance(handlerType);
}
}

public class TestFeatureOne
{
public class Request : IQuery<UnitType> { }
public class AsyncRequest : IAsyncQuery<UnitType> { }

public class Handler : IQueryHandler<Request, UnitType>, IAsyncQueryHandler<AsyncRequest, UnitType>
{
public UnitType Handle(Request request) => UnitType.Default;

public async Task<UnitType> Handle(AsyncRequest request) => await Task.FromResult(UnitType.Default);
}
}

public class TestFeatureTwo
{
public class Command : ICommand<UnitType> { }
public class AsyncCommand : IAsyncCommand<UnitType> { }

public class Handler : ICommandHandler<Command, UnitType>, IAsyncCommandHandler<AsyncCommand, UnitType>
{
public UnitType Handle(Command command) => UnitType.Default;

public async Task<UnitType> Handle(AsyncCommand command) => await Task.FromResult(UnitType.Default);
}
}
}
}

0 comments on commit f453234

Please sign in to comment.