I want to write more SOA+MassTransit tutorials covering a wide range of scenarios for scalable and robust web applications, but I need a good jumping off point for the reader and myself to start from. So I’ll be making some Starter Kits available on Github to help provide an equal and familiar starting point for my tutorials. This is a learning process for both you and me, and I want to give the best and most accurate advice.
I like to construct my projects roughly following Jeffery Palermo’s Onion Architecture. The onion architecture might seem like overkill to use for the simple example of the Starter Kit. However I will be writing more tutorials, and when they get more complex, this organizational architecture will help keep things concise, and should (I hope) make it easier for the reader (you) to follow along.
Onion Architecture Approach (Quickly Explained)
One important concept is that layers can only have dependencies on their current layer, or more Inner Layers (or external nuget dependencies if necessary). So for example the Contracts and Domain Models should really only reference .NET Framework, nothing else.
Centre: This layer will typically contain our Contracts (Interfaces) and Domain Models or POCO (for ORM). There should be no business logic or type verification. This should be done in another (more outer) layer.
Middle: This layer houses services that contain implementation for our contracts. This layer could be further split into Domain Services and Application Services, but for simplicity we will just leave them as the Middle layer for now. I’ve provided some examples in the diagram such as; MassTransit Consumers, SignalR Hubs, CQRS services (eg. something like Mediatr).
Outer: The outer most layer typically has a variety of items, which end up tying together the services with concrete assemblies and infrastructure. For example, MassTransit (and projects I’ve worked on in the past) use a logging mechanism called LibLog. I am a huge fan of this, because it doesn’t restrict you to a specific logging implementation. So in the outer most layer, all you have to do is add your dependency to NLog, EntLib, or log4net, and configure it (using code or app.config), and your off to the races. None of your inner layers have any dependency on any logging system (LibLog works by simply adding a *.cs file to your projects). The same idea applies for other infrastructure you wire up such as; what ORM you use, the Storage type, the DB provider, the unit testing (and mocking) libraries, which CQRS pattern, or what logging framework to use.
Starter Kit – Autofac, MassTransit, Mvc
The Starter Kit can be found here, and below is the architecture.
Update Oct. 24, 2015: I’ve added another starter kit here, which includes SignalR.
The Starter Kit compiles and runs a simple message (publish and subscribe) example. You can see the message sent from the webpage in the console service running.
I want to take a moment to explain the logging option used. I’ve been around the block when it comes to logging for .NET, and by far the best technique I’ve encountered so far is LibLog. It lets you choose your favorite, and there is no DLL dependency in your libraries. Only the final executable that wires up the logger of your choice (log4net, nlog, entlib, etc…). So in the Starter Kit, I chose log4net, and if you look in StarterKit.Web (Web.config), or StarterKit.Service (App.config), you will see log4net’s configuration.
Logging Level in StarterKit
Because MassTransit, and Topshelf both use LibLog, our logs can become crowded if we set the global log level to debug. So you’ll notice in the *.config, that I set the root level to info and I set the StarterKit.* namespace level to debug.
<root> <level value="INFO" /> <appender-ref ref="RollingFile" /> </root> <logger name="StarterKit.*"> <level value="DEBUG" /> </logger>
This keeps the logs clean if you are trying to debug your code. And of course, if you are having trouble with MassTransit, and need to post logs in the google discuss group to get help, the library contributors might ask for logs so they can help diagnose your issue. In that case you would want to change the root level to debug and run + capture the logs.
So go clone the Starter Kit and start experimenting!