Ever wondered how to resolve your command / pipeline entry from your IoC container? One of the more common arguments I have seen for the Service Locator (anti) pattern is for exactly this reason, and it’s completely avoidable. This approach works perfectly well with the likes of Castle Windsor, Autofac, Unity or even Agnostic IoC. This also provides the added bonus of being able to unit test your pipelines, which in my humble opinion is possibly where it is needed most. It also allows you to utilise constructor injection in Sitecore Pipelines (which I have heard from seasoned Sitecore developers can’t be done 😉 ).
In this post I describe how to give control of your dependencies on pipeline & commands to your IoC container of choice using Sitecore factories.
Below, we find an example class to create a Sitecore factory class. This class allows Sitecore to initialise it’s pipeline / command entries in a standard way. In doing so, it provides a hook to allow you to simply resolve the type from an IoC container rather than using an Activator.CreateInstance call.
using System; using System.Diagnostics.CodeAnalysis; using Sitecore.Reflection; public class ContainerFactory : IFactory { private readonly IContainerManager containerManager; public ContainerFactory() : this(new LocatorContainerManager()) // service locate an appropriate container { } public ContainerFactory(IContainerManager containerManager) { this.containerManager = containerManager; } public object GetObject(string identifier) { Type type = Type.GetType(identifier); return this.containerManager.Resolve(type); } }
To use this in Sitecore thanks to its extensible configuration API, we need to patch it in. In order to use this to resolve pipelines in your code you just need to add the factory to your configuration node for the pipeline.
<sitecore> <events> <event name="item:saved"> <handler factory="ContainerFactory" ref="MyApp.MyHandler, MyApp" method="MyMethod"> <database>master</database> </handler> </event> </events> <pipelines> <MyPipeline> <processor type="1" factory="ContainerFactory" ref="MyApp.MyProcessor, MyApp" /> </MyPipeline> </pipelines> <factories> <factory id="ContainerFactory" type="MyApp.ContainerFactory"></factory> </factories> </sitecore>
As you can see, we just use the factory attribute to tell the entry how it is to be resolved. Simple as that.
This looks great, exactly what I’m looking for. One question, how are you releasing the resolved handler/pipeline?
As in to Windsor?
Yeah. According to RRR (Register, Resolve, Release) we need to release the resolved components and/or dispose of the container. See these two pages:
http://kozmic.net/2010/08/27/must-i-release-everything-when-using-windsor/
http://blog.ploeh.dk/2010/09/29/TheRegisterResolveReleasepattern/
I could be misunderstanding something, but I don’t think we want to wait til the end of the application to release event handlers and pipelines by disposing of the entire container. I was thinking those components should be released after their appropriate methods are executed.
But, like I said, maybe I’m missing something?
We use glass mapper’s NoTrackLifestyle. It behaves like a regulat transient resolve from other containers. It means that you can rely on the garbage collection to pick it up.
Cheers
Cool, thanks for the help!
No problem at all 😀
Pingback: Be careful with Sitecore pipeline processors lifecycle | ctor.io
Ok, one more question. I’ve got this working in pipelines and events. Now, for the first time, I need to use this in a command, specifically in the Page Editor. I’ve set up the command in the Core database and when I don’t use my IoC factory, the command works. When I move it all over to use IoC, and set up my config like this:
then I get an error. When I click the command in the page editor, MyFactory.GetObject() is never called. And nothing happens. When I look in the console in Chrome, I see an error: “mycommand is not defined.”
Have you used this with a command before? Any ideas what I’m doing wrong here?
Actually, I got it working with this:
http://maze-dev.blogspot.dk/2014/03/dependency-injection-in-custom-sitecore.html
Have you managed to get this working for injecting a processor into the pipeline?
I’m running 7.2 and following this article, https://www.sitecore.net/learn/blogs/technical-blogs/john-west-sitecore-blog/posts/2015/01/controller-constructor-injection-with-the-sitecore-aspnet-cms.aspx, trying the use the ContainerFactory to resolve dependencies passed to the InitializeControllerFactory processor in the pipeline.
This is throwing “Sitecore.Exceptions.InvalidStructureException: No group node for sub node: initialize”
[InvalidStructureException: No group node for sub node: initialize]
Sitecore.Xml.XmlUtil.GetAncestor(String ancestorName, XmlNode subNode, Boolean assert) +228
Sitecore.Pipelines.CorePipelineFactory.GetObjectFromName(String objectName, XmlNode processorNode) +104
Sitecore.Pipelines.CoreProcessor.GetMethod(Object[] parameters) +65
Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args) +351
Sitecore.Nexus.Web.HttpModule.Application_Start() +172
Sitecore.Nexus.Web.HttpModule.Init(HttpApplication app) +516
System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +530
System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +304
System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +404
System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +475
Yes – this method allows you to resolve processors from your IoC container. There are other posts on here about resolving controllers from your container.
Is this what you meant ?
https://cardinalcore.co.uk/2015/02/03/resolving-sitecore-controllers-from-your-ioc-container/
Yeah we ended up doing something similar, but was hoping to be able to have the ContainerFactory in this post resolve the patch in the initialize pipeline like this:
Using the ContainerFactory to resolve the processor threw the error I stated above in our instance, was wondering if anyone else had encountered this…
I faced the same issue like @cucumberryan when I did an upgrade to Sitecore 8.2 update 1. I wrote a blog post how to fix that – https://trnktms.wordpress.com/2016/12/14/no-group-node-for-sub-node/
Config examples are being stripped 🙂
Get the error resolving a processor in the pipeline trying to do this:
Not 100% sure what you are asking – there is this later post which may help:
https://cardinalcore.co.uk/2015/01/28/resolving-sitecore-configuration-entries-using-ioc-with-named-components/
if not – please feel free to get on contact direct (@cardinal252 on twitter) and I will try and help you out.
Ok – so – for completeness for future readers. This issue seems to occur if you miss the ‘type’ from the config.
Pingback: Sitecore Pipelines and Unity | Himadri's Technical Blog
Seems like the “factory” attribute doesn’t work for Sitecore 8.0. Sitecore just ignores it. Fortunately there’s “factoryMethod” attribute that works fine for me.
Pingback: No group node for sub node | Coffee First based .NET and Sitecore Dev