The best way to get AppTonic is to install it from nuget.org using NuGet.exe or the package manager console. You can also right click on your project or solution in Visual Studio and click "Manage NuGet Packages..." and search for AppTonic.
Messages are at the heart of AppTonic. For this guide, we'll be creating a message with just a simple
POCO implementing
the IRequest
marker interface from the AppTonic package.
The most fundamental request interfaces are IRequest
and IRequest<TResponse>
,
each indicating whether or not there is a response expected. While no additional request types are functionally nescessary,
marker interfaces for commands and queries, as well as handling mechanisms for async requests are included to reduce boilerplate
and create intention-revealing application code.
public class CreateUser : IRequest
{
public string Name { get; set; }
}
AppTonic supports two styles of composing your application. Take advantage of either your dependency injection container and/or use partial function application. We'll keep our focus on one style for the rest of the guide.
Add the IHandle<TRequest>
interface to a class and implement your desired
application logic in the Handle(CreateUser request)
method.
This class is the application service for handling this particular request.
public class UserService : IHandle<CreateUser>
{
public void Handle(CreateUser request)
{
var user = new User { Name = request.Name };
_userRepository.Add(user);
_userRepository.Save();
_logger.Info("UserService: User Created");
}
// Rest of class ommitted for brevity
}
Our first step before we configure the AppDispatcher
instance is to
have our dependency injection framework perform its usual composition, including resolving any our handler interfaces with its implementation.
In this case, resolving IHandle<CreateUser>
with our UserService
application service.
We also need to create the Common Service Locator adapter,
using the appropriate NuGet package for our preferred dependency injection framework.
class Program
{
static void Main()
{
// Configure your dependency injection container (Unity in this example)
var container = new UnityContainer();
container.RegisterType<IUserRepository, InMemoryUserRepository>();
container.RegisterType<ILogger, ConsoleLogger>();
// Register our application service - this process can automated,
// depending on your dependency injection framework
container.RegisterType(
typeof(IHandle<CreateUser>),
typeof(UserService));
// Create common service locator adapter
var unityServiceLocatorAdapter = new UnityServiceLocator(container);
// Initilaize the AppDispatcher
AppDispatcher.Initialize(app =>
{
app.UseCommonServiceLocator(unityServiceLocatorAdapter);
});
// Create a request
var request = new CreateUser { Name = "Jane Smith" };
// Dispatch your message to your service
AppDispatcher.Handle(request);
}
}
Although we haven't seen where partial application comes in yet, all we need to do to handle our message
is to create a method that our request CreateUser
as a parameter, along with any dependencies.
That's it - no additional interfaces to implement.
public static class UserServiceModule
{
public static void CreateUser(CreateUserRequest request,
Func<IUserRepository> userRepositoryFactory, ILogger logger)
{
using (var userRepository = userRepositoryFactory())
{
var user = User.Create(request);
userRepository.Add(user);
userRepository.Save();
logger.Info("UserServiceModule: User Created");
}
}
}
Configuring our AppDispatcher
without dependecy injection is very simple. In this example,
the composition root of our application, we create any instances or define factories that will be used for our application.
Finnally, all that is required is that we the appropariate RegisterHandler
method on our
configurator object, passing in closure that calls our application service, creating a partially applied function that
is registered in our AppDispatcher
instance. Now we can simple call AppDispatcher.Handle
and pass
in our request, and it will be handled using the dependencies passed in by the function closure we initially registered.
class Program
{
static void Main()
{
// Look ma, no dependency injection container!
var logger = new ConsoleLogger();
Func<IUserRepository> userRepositoryFactory =
() => new InMemoryUserRepository();
AppDispatcher.Initialize(app =>
{
app.RegisterHandler<CreateUser>(createUserRequest =>
{
UserServiceModule.CreateUser(createUserRequest,
userRepositoryFactory, logger);
});
});
var request = new CreateUser { Name = "Jane Smith" };
AppDispatcher.Handle(request);
}
}
Using the AppDispatcher in our program is easy. We can use the AppDispatcher
static class helper (as seen here), or we resolve an instance of the IAppDispatcher
from our dependency injection framework.
AppDispatcher.Initialize
method, which creates a single instance of
the AppDispatcher accessible from AppDisptacher.Instance
, or you can use the
AppDisptacherFactory.Create
method, which is used in the exact same manner as the
AppDispatcher.Initialize
method, to create multiple IAppDispatcher
instances, or to create an instance for injection into your IoC framework.
AppDispatcher.Initialize(app => {
// configuration
})
IAppDispatcher dispatcherOne = AppDispatcher.Instance;
IAppDispatcher dispatcherTwo = AppDispatcherFactory.Create(app => {
// configuration
})
public class UserController : ApiController
{
public void Post(CreateUser request) {
AppDispatcher.Handle(request);
}
}
public class UserController : ApiController
{
private readonly IAppDispatcher _app;
public UserController(IAppDispatcher app) {
_app= app;
}
public void Post(CreateUser request) {
_app.Handle(request);
}
}