If you are reading this, chances are you have used some form of DI in your Sitecore Solution. If you’ve used some of the standard IoC containers in an MVC application, you’ve also most likely used a custom dependency resolver. Using Simpleinjector, you can make a pretty simple custom dependency resolver for Sitecore – see here. In pre Sitecore 8.1, you would also need to make a custom controller factory, so that you can resolve using your own container. There are number of posts that shows you how to build a cool custom controller factory:
- Nathaniel Mann custom controller factory using Castle.Windsor
- John West’s Controller Injection Post
- Chaining DI by BrainJocks
What’s new in Sitecore 8.1?
Pre Sitecore 8.1, you had to make a custom controller factory because Sitecore by default did not use the DependencyResolver to create a controller instance. It was something like this:
if (TypeHelper.LooksLikeTypeName(controllerName)) { Type type = TypeHelper.GetType(controllerName); if (type != (Type) null) return TypeHelper.CreateObject(type); } return this.InnerFactory.CreateController(requestContext, controllerName);
In Sitecore 8.1, it uses the current DependencyResolver (as set by your application in App_Start) to create the controller instance – if it fails (i.e. didn’t find the concrete type in your container), then it still uses TypeHelper (Sitecore.Mvc.Helpers) to create the instance.
if (TypeHelper.LooksLikeTypeName(controllerName)) { Type type = TypeHelper.GetType(controllerName); if (type != (Type) null) { IController controller = DependencyResolver.Current.GetService(type) as IController ?? TypeHelper.CreateObject<IController>(type); if (controller != null) return controller; } } return this.InnerFactory.CreateController(requestContext, controllerName);
What this really means is that you don’t have to use your own custom controller factory anymore. You still need to use the fully qualified class name for the controller, though.
An update to how setup a custom dependency resolver
In my earlier post, I wrote about a simple custom dependency resolver using SimpleInjector. Steven van Deursen, one of the founders of SimpleInjector showed me a better way to do this, so that it would be compatible with upcoming changes in v3 and future changes. It involves wrapping your own implementation with a wrapper, so that creation of all instances are delegated to the SimpleInjectorDependencyResolver. Instead of implementing the GetService method yourself, you use the wrapper’s GetService method – this way, any updates done to SimpleInjector is seamless. So now, the class would look like this:
public class CustomDependencyResolver : IDependencyResolver { private IDependencyResolver wrappedResolver; public SitecoreDependencyResolver(IDependencyResolver wrappedResolver) { this.wrappedResolver = wrappedResolver; } public object GetService(Type serviceType) { try { return this.wrappedResolver.GetService(serviceType); } catch { return Sitecore.Mvc.Helpers.TypeHelper.CreateObject<IController>(serviceType, new object[0]); } } public IEnumerable<object> GetServices(Type serviceType) { return this.wrappedResolver.GetServices(serviceType); } }
And then when setting the DependencyResolver in App_Start, it would look like this:
public static class SimpleInjectorInitializer { //Initialize the container and register it as MVC Dependency Resolver. public static void Initialize() { var container = new Container(); InitializeContainer(container); container.RegisterMvcControllers(Assembly.GetExecutingAssembly()); container.Verify(); DependencyResolver.SetResolver(new CustomDependencyResolver(new SimpleInjectorDependencyResolver(container))); } private static void InitializeContainer(Container container) { // Register your classes (anything other than the MVC controllers) // For instance: // container.Register<IUserRepository, SqlUserRepository>(); } }
Happy Coding!
nice can you also suggest some books which cover all the sitecore 8.1 features and solution..
There aren’t very many books, but the Sitecore community fills in quite a bit. You can look up the community.sitecore.net site. The few books that are available: http://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Daps&field-keywords=sitecore+8
I definitely recommend the John West book for beginners
Hi Mickey.
I followed your implementation for SimpleInjector with Sitecore but when I try to use it with Glass Mapper I get the following error:
—————————————————————————————
The given key was not present in the dictionary.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
Source Error:
Line 31: // container.Register();
Line 32:
Line 33: container.Register(() => new SitecoreContext());
Line 34: container.Register();
Source File: C:\Test\Source\TestSI\DependencyInjection\SimpleInjector\SimpleInjectorInitializer.cs Line: 33
—————————————————————————————-
Do you have any ideas why is not working when I try to get an instance of SitecoreContext?
Thank you,
Stefan
Does it give you this error even if you don’t register SitecoreContext()? Also, I don’t think you need the empty Container.Register() at the end, and not sure that method exists without any parameter.
You could also just register all your classes from your assemblies like this: http://www.akshaysura.com/2015/08/17/testable-and-reusable-sitecore-mvc-solution-using-simpleinjector-glass-4-nunit-and-nsubstitute/
Thanks for the replay. That Container.Register() at the end was from an old stack trace error (sorry for my bad copy-paste skill) but the error remains for the SitecoreContext. I will try to use the approach from that link but your implementation was more straight forward. Thanks again.
I forgot. to answer your first question. It works if I don’t register the SitecoreContext. I tested with a simple Interface+Class and works just fine.