Walkthrough: The Unity StopLight QuickStart
The StopLight QuickStart demonstrates the ways that you can use Unity and the Unity container in your applications. The user interface is a simple Windows Forms application that displays the three colors of a stop light or traffic light—it shows red, yellow, and green, in turn, for specified periods. You can configure the display periods for each color. The following illustration shows the user interface.
The StopLight QuickStart demonstrates the following features of Unity:
- Registering mappings for types with the container
- Implementing the Model View Presenter pattern by injecting a presenter into the user interface
- Injecting a business component into objects using property (setter) injection
- Implementing a configurable pluggable architecture
The following diagram shows the classes and architecture of the StopLight QuickStart application.
Registering Mappings for Types with the Container
The StopLight QuickStart uses two services that the Unity container maps from interfaces to concrete service implementations. These two services are injected into classes that require them automatically when unity creates instances of the class.
The two interfaces are ILogger, which Unity maps to the concrete service class named TraceLogger, and IStoplightTimer, which Unity maps to the concrete service class named RealTimeTimer. The mapping registration occurs in the Program file that executes when the application starts. It uses the following code.
IUnityContainer container = new UnityContainer()
.RegisterType<ILogger, TraceLogger>()
.RegisterType<IStoplightTimer, RealTimeTimer>();
'Usage
Dim container As IUnityContainer = New UnityContainer() _
.RegisterType(Of ILogger, TraceLogger)() _
.RegisterType(Of IStoplightTimer, RealTimeTimer)()
This sets up two default (unnamed) mappings so that requests to the container for the ILogger interface will return a new instance of the TraceLogger component and requests to the container for the IStoplightTimer interface will return a new instance of the RealTimeTimer component.
Note
The TraceLogger component (in the ServiceImplementations folder) exposes a single method named Write that writes a specified message to the application's current System.Diagnostics.Trace instance.
The RealTimeTimer component is a single-shot timer implemented in the file RealTimeTimer (in the ServiceImplementations folder). It exposes a property named Duration (in milliseconds), a Start method, and it raises the OnExpired event when the timer reaches the specified duration.
After registering the required mappings, the code must force dependency injection to be applied to the child objects the application uses. The parent object for the application is the Windows Forms user interface class named StoplightForm. To ensure that all dependent objects are injected, the code in the Program class instantiates the StoplightForm using the Resolve method of the Unity container, as shown here.
Application.Run(container.Resolve<StoplightForm>());
'Usage
Application.Run(container.Resolve(Of StoplightForm)())
The Run method of the Application class accepts as a parameter an object that is the class to execute. The Resolve method of the Unity container generates an instance of the StoplightForm class, applying dependency injection to all child classes to create or reference the objects these child classes require.
Implementing the Model-View-Presenter Pattern
When the program starts, it loads and displays the user interface—the Windows Form named StoplightForm. This form implements the view for the Model View Presenter (MVP) pattern, so it must expose a property that is a reference to its associated presenter. To obtain a reference to its presenter, a class named StoplightPresenter, the form uses property (setter) injection by applying the Dependency attribute to the property, as show in this code.
public partial class StoplightForm : Form, IStoplightView
{
private StoplightPresenter presenter;
[Dependency]
public StoplightPresenter Presenter
{
get { return presenter; }
set
{
presenter = value;
presenter.SetView(this);
}
}
...
'Usage
Public Partial Class StoplightForm
Inherits Form
Implements IStoplightView
Private _presenter As StoplightPresenter
<Dependency()> _
Public Property Presenter() As StoplightPresenter
Get
Return _presenter
End Get
Set(ByVal value As StoplightPresenter)
_presenter = value
_presenter.SetView(Me)
End Set
End Property
...
This ensures that Unity will create the presenter before it creates and displays the view (the StoplightForm form). The dependent class type for dependency injection is the concrete class StoplightPresenter, so the Unity container can create this object without requiring a mapping in the container.
The view exposes event handlers that the presenter can use to manipulate the controls on the form and access the values.
Injecting a Business Component using Property (Setter) Injection
The presenter for the user interface, the class named StoplightPresenter, requires an instance of the class named Stoplight that represents the set of colors and methods of a real stop light. The Stoplight class uses an enumeration of the three colors (red, yellow, and green), exposes the Next method that the application can use to change the colors in a predefined sequence, and raises the StoplightChangedHandler event when a color change occurs. The argument for this event is an instance of the class named LightChangedEventArgs that exposes the current color.
To obtain an instance of this class, the StoplightPresenter exposes it as a property and applies the Dependency attribute to the property, as shown in the following code.
private Stoplight stoplight;
[Dependency]
public Stoplight Stoplight
{
get { return stoplight; }
set { stoplight = value; }
}
'Usage
Private _stoplight As StopLight.Logic.Stoplight
<Dependency()> _
Public Property Stoplight() As StopLight.Logic.Stoplight
Get
Return _stoplight
End Get
Set(ByVal value As StopLight.Logic.Stoplight)
_stoplight = value
End Set
End Property
The dependent class type for dependency injection is the concrete class, Stoplight, so the Unity container can create this object without requiring a mapping in the container.
The presenter also has a dependency on the StoplightSchedule class, which maintains references to the StoplightTimer and ILogger, exposes methods to update the durations for the colors and force a change to the next color, and responds to the OnTimerExpired event raised by the RealTimeTimer class.
To get a reference to a new instance of the StoplightSchedule class, the StoplightPresenter exposes it as a property named Schedule and applies the Dependency attribute to the property, as shown in the following code.
private StoplightSchedule schedule;
[Dependency]
public StoplightSchedule Schedule
{
get { return schedule; }
set { schedule = value; }
}
'Usage
Private _schedule As StoplightSchedule
<Dependency()> _
Public Property Schedule() As StoplightSchedule
Get
Return _schedule
End Get
Set(ByVal value As Stoplight)
_schedule = value
End Set
End Property
Again, the dependent type is a concrete class, in this case the StoplightSchedule class, and so the Unity container can create this object without requiring a mapping in the container.
Implementing a Configurable Pluggable Architecture
The Stoplight and StoplightSchedule classes have dependencies that are not concrete classes. Both of these classes have a dependency on one of the concrete implementations of the ILogger interface—either the NullLogger or the TraceLogger. At run time, the code can choose which concrete class to instantiate. It can use any class that implements the ILogger interface, which defines just the single method Write that takes a message and writes it to the appropriate output.
This is an example of a pluggable architecture. The actual class chosen at run time, and injected into the application, depends on the mapping in the Unity container. The QuickStart maps the ILogger interface to the concrete type TraceLogger using the method RegisterType<ILogger, TraceLogger>() in the main Program class. Therefore, to use a different concrete implementation, the developer just has to change the mapping. For example, to use a new class ReallyFastLogger, the developer would just change the mapping to RegisterType<ILogger, ReallyFastLogger>().
In addition, by using a configuration file to populate the Unity container or reading the configuration information from another source such as a database, the developer allows the user to change the actual concrete logging class without requiring recompilation of the application code.
The Stoplight and StoplightSchedule classes force injection of the currently mapped logger class by exposing it as a property named Logger (of type ILogger) that has the Dependency attribute applied, as shown in the following code.
private ILogger logger = new NullLogger();
[Dependency]
public ILogger Logger
{
get { return logger; }
set { logger = value; }
}
'Usage
Private _logger As ILogger = New NullLogger()
<Dependency()> _
Public Property Logger As ILogger
Get
Return _logger
End Get
Set(ByVal value As ILogger)
_logger = value
End Set
End Property