Introduction
CodeProject and its community are a great resource that I have used
for a number of years now. With this article (my first) I will attempt to
give something back.
Background
I have been using Unity for awhile, and it has always bothered me to have a method for type registration that could be really long.
Example of long registration method:
public IUnityContainer InitializeContainer()
{
var Container = new UnityContainer();
Container.RegisterType(typeof(IResolver<>), typeof(UnityResolver<>));
Container.RegisterType(typeof(IEventResolver<>), typeof(EventResolver<>));
Container.RegisterType<IEnrollmentRepository, EnrollmentRepository>();
Container.RegisterType<IFaqRepository, FaqRepository>();
Container.RegisterType<IHousingUnitRepository, HousingUnitRepository>();
Container.RegisterType<IInformationRepository, InformationRepository>();
Container.RegisterType<INoteRepository, NoteRepository>();
Container.RegisterType<IProgramRepository, ProgramRepository>();
Container.RegisterType<IScratchPaperRepository, ScratchPaperRepository>();
Container.RegisterType<IStatusRepository, StatusRepository>();
Container.RegisterType<ISoftwareRepository, SoftwareRespository>();
Container.RegisterType<IStudentRepository, StudentRepository>();
Container.RegisterType<ITestRepository, TestRepository>();
Container.RegisterType<IDialogService, DialogService>();
Container.RegisterType<IFaqService, FaqService>();
Container.RegisterType<IEnrollmentService, EnrollmentService>();
Container.RegisterType<IInformationService, InformationService>();
Container.RegisterType<IJsepService, JsepService>();
Container.RegisterType<INoteService, NoteService>();
Container.RegisterType<ISettingsService, SettingsService>();
Container.RegisterType<IScratchPaperService, ScratchPaperService>();
Container.RegisterType<ISoftwareService, SoftwareService>();
Container.RegisterType<IStudentService, StudentService>();
Container.RegisterType<ITestService, TestService>();
Container.RegisterType<ILookupService, LookupService>();
Container.RegisterType<IReportService, ReportService>();
Container.RegisterType<IDbContext, StudentTrakkerContext>();
Container.RegisterType<IUnitOfWork, UnitOfWork>();
return container;
}
This method could be refactored to use the fluent interface, thus making it a little easier to read.
public IUnityContainer InitializeContainer()
{
var Container = new UnityContainer();
Container.RegisterType(typeof(IResolver<>), typeof(UnityResolver<>))
.RegisterType(typeof(IEventResolver<>), typeof(EventResolver<>))
.RegisterType<IEnrollmentRepository, EnrollmentRepository>()
.RegisterType<IFaqRepository, FaqRepository>()
.RegisterType<IHousingUnitRepository, HousingUnitRepository>()
.RegisterType<IInformationRepository, InformationRepository>()
.RegisterType<INoteRepository, NoteRepository>()
.RegisterType<IProgramRepository, ProgramRepository>()
.RegisterType<IScratchPaperRepository, ScratchPaperRepository>()
.RegisterType<IStatusRepository, StatusRepository>()
.RegisterType<ISoftwareRepository, SoftwareRespository>()
.RegisterType<IStudentRepository, StudentRepository>()
.RegisterType<ITestRepository, TestRepository>()
.RegisterType<IDialogService, DialogService>()
.RegisterType<IFaqService, FaqService>()
.RegisterType<IEnrollmentService, EnrollmentService>()
.RegisterType<IInformationService, InformationService>()
.RegisterType<IJsepService, JsepService>()
.RegisterType<INoteService, NoteService>()
.RegisterType<ISettingsService, SettingsService>()
.RegisterType<IScratchPaperService, ScratchPaperService>()
.RegisterType<ISoftwareService, SoftwareService>()
.RegisterType<IStudentService, StudentService>()
.RegisterType<ITestService, TestService>()
.RegisterType<ILookupService, LookupService>()
.RegisterType<IReportService, ReportService>()
.RegisterType<IDbContext, StudentTrakkerContext>()
.RegisterType<IUnitOfWork, UnitOfWork>();
return container;
}
The method above is a little cleaner, but to my eye could still use some work, so lets refactor to the following:
public IUnityContainer InitializeContainer()
{
var container = new UnityContainer();
container.RegisterModule<PersistenceModule>()
.RegisterModule<ServiceModule>();
return container;
}
Neat and concise like code should be.
Using the code
In order to achieve the above cleanliness, we will create an interface IUnityConfigurationModule
, a couple classes that implement said interface,
and the RegisterModule
extension method.
First off is the interface:
IUnityConfigurationModule.cs:
using Microsoft.Practices.Unity;
namespace Champion.Core.Interfaces
{
public interface IUnityConfigurationModule
{
void Configure(IUnityContainer contatiner);
}
}
The IUnityConfigurationModule
interface contains a contract of one method: Configure
. The Configure
method is where our type registrations will occur.
PersistenceModule.cs:
using Champion.Core.Interfaces;
using Champion.Core.Persistence;
using Microsoft.Practices.Unity;
namespace Champion.Core.Persistence
{
public class PersistenceModule : IUnityConfigurationModule
{
public void Configure(IUnityContainer container)
{
container.RegisterType<IDbContext, ToyServiceCenterContext>()
.RegisterType<IUnitOfWork, UnitOfWork>()
.RegisterType<IAnnouncementRepository, AnnouncementRepository>()
.RegisterType<IEnrollmentRepository, EnrollmentRepository>()
.RegisterType<IFaqRepository, FaqRepository>()
.RegisterType<IHousingUnitRepository, HousingUnitRepository>()
.RegisterType<IInformationRepository, InformationRepository>()
.RegisterType<INoteRepository, NoteRepository>()
.RegisterType<IProgramRepository, ProgramRepository>()
.RegisterType<IScratchPaperRepository, ScratchPaperRepository>()
.RegisterType<IStatusRepository, StatusRepository>()
.RegisterType<ISoftwareRepository, SoftwareRespository>()
.RegisterType<IStudentRepository, StudentRepository>()
.RegisterType<ITestRepository, TestRepository>();
}
}
}
ServiceModule.cs:
using Champion.Core.Interfaces;
using Champion.Core.Services;
using Microsoft.Practices.Unity;
namespace Champion.Core.Services
{
public class ServiceModule : IUnityConfigurationModule
{
public void Configure(IUnityContainer container)
{
container.RegisterType<IDialogService, DialogService>()
.RegisterType<IFaqService, FaqService>()
.RegisterType<IEnrollmentService, EnrollmentService>()
.RegisterType<IInformationService, InformationService>()
.RegisterType<IJsepService, JsepService>()
.RegisterType<INoteService, NoteService>()
.RegisterType<ISettingsService, SettingsService>()
.RegisterType<IScratchPaperService, ScratchPaperService>()
.RegisterType<ISoftwareService, SoftwareService>()
.RegisterType<IStudentService, StudentService>()
.RegisterType<ITestService, TestService>()
.RegisterType<ILookupService, LookupService>()
.RegisterType<IReportService, ReportService>();
}
}
}
Now that we have our configuration modules complete. It is time for the RegisterModule
extension method that brings it all together.
UnityExtensions.cs:
using Champion.Core.Interfaces;
using Microsoft.Practices.Unity;
namespace Champion.Core.Extensions
{
public static class UnityExtensions
{
public static IUnityContainer RegisterModule(this IUnityContainer container, IUnityConfigurationModule module)
{
if (module != null)
{
module.Configure(container);
}
return container;
}
public static IUnityContainer RegisterModule<T>(this IUnityContainer container) where T : class, IUnityConfiguratiModule, new()
{
T module = new T();
module.Configure(container);
return container;
}
}
}
You'll notice two methods here. The first one, you use by passing in an instance of a class that implements IUnityConfigurationModule
.
Example of first method:
container.RegisterModule(new PersistenceModule());
Then we have the second method that uses generics to provide
a cleaner implementation.
Example of second method:
container.RegisterModule<PersistenceModule>();
So there we have it. My take on cleaning up type registration code.
Points of Interest
Inspiration for this article came from Rusell East's Blog, and his IModule
implementation.
I usually create the module class inside the individual assemblies where the
types being registered reside. This of course will require those particular
assemblies to have a reference to Unity. If that is something you would prefer
to avoid you could always have the module classes reside in your main project
and add references to the required assemblies.
Conclusion
Creating this article has been an eye-opener for me into how difficult
it is to write an article. Kudos to all you prolific writers.
I look forward to your comments, suggestions, rants, etc.
History
- 4/15/13 - Initial post.
- 4/16/13 - Cleaned up the code examples to make them more readable, and in one instance believable.
- 4/17/13 - My perfectionist side is coming out. More cleanup.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.