In my current ASP.NET MVC project, I'm focused on testability and programming to interfaces rather than concrete implementations, so I have a ton of interfaces.
I'm using the Microsoft Unity IOC Container, so my dependency injection initialization code looked like this:
1: using System;
2: using System.Collections.Generic;
3: using System.Reflection;
4: using Duff.Localization;
5: using Duff.Database;
6: using Microsoft.Practices.Unity;
7:
8: namespace Duff.Web
9: {
10: public static class ObjectFactoryInitializer
11: {
12: public static void Initialize()
13: {
14: RegisterTypes(ObjectFactory.UnityContainer);
15: }
16:
17: private static void RegisterTypes(IUnityContainer container)
18: {
19: container
20: .RegisterType<IBeerRepository, BeerRepository>()
21: .RegisterType<ICacheHandlerFactory, CacheHandlerFactory>()
22: .RegisterType<ICompanyRepository, CompanyRepository>()
23: .RegisterType<IContextState, ContextState>()
24: .RegisterType<ICostCenterRepository, CostCenterRepository>()
25: .RegisterType<IExceptionHandler, ExceptionHandler>()
26: .RegisterType<IBreweryRepository, BreweryRepository>()
27: .RegisterType<IHtmlEncoder, HtmlEncoder>()
28: .RegisterType<ILogger, ErcLogger>()
29: .RegisterType<ILookupHelper, LookupHelper>()
30: .RegisterType<IPaginationHelper, PaginationHelper>()
31: .RegisterType<IResourceStringGetter, ResourceStringGetter>()
32: .RegisterType<IRetentionCodeRepository, RetentionCodeRepository>()
33: .RegisterType<IRetentionScheduleLocationRepository, RetentionScheduleLocationRepository>()
34: .RegisterType<IRetentionScheduleServiceFactory, RetentionScheduleServiceFactory>()
35: .RegisterType<IDuffAuthorizationChecker, DuffAuthorizationChecker>()
36: .RegisterType<IRmsConfiguration, WebConfig>()
37: .RegisterType<IUserHelper, UserHelper>()
38: .RegisterType<IUserState, UserState>()
39: .RegisterType<IUserRepository, UserRepository>();
40: }
41: }
42: }
For all but two of the interfaces, the class names I want to resolve to are just the interface names without the "I" prefix (e.g. "IBeerRepository" to "BeerRepository"). Wouldn't it be nice if I could just tell my program to look at my assemblies, find all of the interface / class names that match like this, and automatically register them?
I knew this was possible with StructureMap, but not "out of the box" with Unity. Wouldn't it be nice if someone wrote a convention-based configuration implementation for Unity so I wouldn't have to?
Well, that someone was Derek Greer. With his Convention-based Registration Extension for Unity, I can do this:
1: using System;
2: using System.Collections.Generic;
3: using System.Reflection;
4: using Duff.Localization;
5: using Duff.Database;
6: using Microsoft.Practices.Unity;
7: using UnityConventionExtension;
8: using UnityConventionExtension.Conventions;
9:
10: namespace Duff.Web
11: {
12: public static class ObjectFactoryInitializer
13: {
14: public static void Initialize()
15: {
16: RegisterTypes(ObjectFactory.UnityContainer);
17: }
18:
19: private static void RegisterTypes(IUnityContainer container)
20: {
21: container
22: // register types where the "mapped to" class name is
23: // just the interface name without the "I" prefix:
24: .AddNewExtension<ConventionExtension>()
25: .Configure<IConventionExtension>()
26: .Configure(x =>
27: {
28: x.Conventions.Add<InterfaceImplementionNameMatchConvention>();
29: AddMyAssembliesForConventionBasedRegistration(x.Assemblies);
30: }).Register()
31:
32: // register other types:
33: .RegisterType<IRmsConfiguration, WebConfig>()
34: .RegisterType<ILogger, ErcLogger>();
35: }
36:
37: private static void AddMyAssembliesForConventionBasedRegistration
38: (ICollection<Assembly> assemblyList)
39: {
40: Assembly domainAssembly = Assembly.GetAssembly(typeof(IBeerRepository));
41: Assembly localizationAssembly = Assembly.GetAssembly(typeof(IResourceStringGetter));
42: Assembly repositoryAssembly = Assembly.GetAssembly(typeof(BeerRepository));
43:
44: assemblyList.Add(Assembly.GetExecutingAssembly());
45: assemblyList.Add(domainAssembly);
46: assemblyList.Add(repositoryAssembly);
47: assemblyList.Add(localizationAssembly);
48: }
49: }
50: }
It's actually more lines of code at the moment, but there are a lot more interfaces to come, and I won't have to write any more IOC registration code for them unless the interface/class names don't my usual convention.
(Why didn't I just use StructureMap? Maybe next project. I've used Unity before, so I'm comfortable with it. This is my first time using ASP.NET MVC, MVCContrib, Automapper and a couple of other tools that are new to me, so I don't want everything to be a learning experience.)
Thanks, Derek!