Our solution is going to include the following projects:
Core
The Core project holds almost all of the interfaces used, as
well as your Model objects, which should be Plain Old CLR Objects (POCOs).
Infrastructure
The Infrastructure project holds your implementations of
various interfaces for things that need to communicate outside of your
process. These include web services, database access repositories, email
routines, system clocks, file system, etc. Just about anything
that I've discussed on my blog as being a dependency should have its
implementation in the Infrastructure project.
Infrastructure depends on Core.
UI
Your UI project. This might be a web project, Windows Form,
WPF, Silverlight, or even Console Application. You might even have multiple
UIs within your solution.
UI depends on Core and Infrastructure (at least
transitively). If you are not using a separate DependencyResolution project,
then UI will need to provide the actual implementations from Infrastructure to
plug into the interfaces it uses.
These are the only projects you *need* to have. However, I
usually include the following as well:
UnitTests
You might create multiple unit test projects. However, unit
tests should not reference Infrastructure, typically, because they are meant to
only test your code, not dependent code. Integration tests (see below) should
be used to test how your code interacts with other systems. If you only create
one UnitTests project for your whole solution, you will want it to reference
Core and any other project you are testing.
IntegrationTests
Integration tests are automated tests that verify how your
application works with other systems (like your database) outside of your
running process. It should reference your Core, Infrastructure, and
DependencyResolution projects and should ideally use the same object graph that
you will use in production (or something close to it).
DependencyResolution
This project is simply responsible for handling registration
of types and interfaces and resolving types that have dependencies. That is,
if you use the Strategy pattern to say that a particular class requires an
IFileSystem as part of its constructor, you can wire up the WindowsFileSystem
class to the IFileSystem interface in the DR project, and then use the DR
project to create your class such that it will automatically have its
dependency provided (as a WindowsFileSystem instance). This project will
generally comprise just a few classes and your Inversion of Control Container
of choice (e.g. StructureMap, Unity, NInject, etc).
DependencyResolution should reference Core and
Infrastructure.
These next screenshots show the sample solution, which
includes all of the moving parts, working DependencyResolution, working
Integration Tests, and working Unit Tests. The focus here is on the references
between the projects.
You can run the sample, which deals with events that have a
start and end date and a service that lists current, expired, or upcoming
events, either by running the console application or by running the unit or
integration tests. The console application pre-loads a few events and then
updates every 15 seconds with a listing of each category of event. The unit
tests verify whether a given test event is active, expired, or upcoming by
allowing you to fake the current time. The integration tests use the system
clock and an in memory listing of events, wired up via DependencyResolution, to
test the service.
In the interests of keeping the number of dependencies to a
minimum, I didn't install a mocking framework (Moq or Rhino Mocks, for example)
for use in the UnitTests project. I recommend running 'install-package moq'
from the Package Management Console to get started using Moq if you don't want
to hand-write lots of fake implementations. I also tend to prefer NUnit but
stuck with the built in MSTest, in order to keep dependencies to a minimum.
You can learn more about creating a
multi-project solution template for VS2010 here.