I thought I would jot down some information that frequently comes up when I am asked to recommend plans of attack on projects. The first recommendation I always give for any Sitecore project is: define as much as you possibly can in Sitecore configuration. Doing so introduces seams in your code: code that does not have to change when its underlying behavior changes — think interfaces. 😉
When defining types in Sitecore configuration, you are leveraging Sitecore’s built-in Dependency Injection framework: Sitecore’s Configuration Factory will magically inject instances of classes — yes, you would define these in configuration files — into properties of classes that are used for your pipeline processors, event handlers, and other Sitecore configuration-defined objects.
For example, suppose we have the following interface for classes that change state on an instance of a phony subclass of Sitecore.Pipelines.PipelineArgs:
namespace Sitecore.Sandbox.Pipelines.SomePipeline { public interface ISomeThing { void DoStuff(SomeProcessorArgs args); } }
Let’s create a fake class that implements the ISomeThing interface above:
namespace Sitecore.Sandbox.Pipelines.SomePipeline { public class SomeThing : ISomeThing { public void DoStuff(SomeProcessorArgs args) { // it would be nice if we had code in here } } }
We can then define a class property with the ISomeThing interface type in a class that serves as a pipeline processor:
using Sitecore.Diagnostics; namespace Sitecore.Sandbox.Pipelines.SomePipeline { public class SomeProcessor { public void Process(SomeProcessorArgs args) { DoSomethingWithArgs(args); } private void DoSomethingWithArgs(SomeProcessorArgs args) { Assert.IsNotNull(SomeThing, "SomeThing must be set in your configuration!"); SomeThing.DoStuff(args); } private ISomeThing SomeThing { get; set; } // this is populated magically! } }
The class above would serve as a processor for the dummy <somePipeline> defined in the following configuration file:
<?xml version="1.0" encoding="utf-8" ?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <pipelines> <somePipeline> <processor type="Sitecore.Sandbox.Pipelines.SomePipeline.SomeProcessor, Sitecore.Sandbox"> <SomeThing type="Sitecore.Sandbox.Pipelines.SomePipeline.SomeThing, Sitecore.Sandbox" /> </processor> </somePipeline> </pipelines> </sitecore> </configuration>
In the configuration file above, we defined a <SomeThing /> element within the processor element of the <somePipeline> pipeline, and this directly maps to the SomeThing property in the SomeProcessor class shown above. Keep in mind that names matter here, so the name of the configuration element must match the name of the property.
Until next time, have a Sitecoretastic day!
Good article, but I bet you wanted to use Assert.ArgumentNotNull.
Good call Alen. I need to fo change my code to that.
Thanks Alen. Now need to go fix my code.
Hi
I get that dependency injection might be a good thing if you’re shipping a product like Sitecore but in a normal web application it’s way too much complexity. Now you have to run the pipeline every time you want whatever happens in DoStuff and there’s a lot of boilerplating every time you want to add a class. You also have to create a custom Args-class for your pipeline or a generic one. There’s better ways to test your code with various mocking frameworks that makes dependency injection redundant. Since you or someone on the team is the owner of the code, there’s nothing wrong with changing it if the business requirements changes.
Please don’t use Sitecore’s pipelines as dependency injection. If you’re working with Sitecore you’re creating a web application and not an off the shelf product that needs to enable its customers to change things without touching the underlying code.
Make it simple! It’s so much more fun.
I strongly disagree with this.
I work for a Sitecore partner that builds Sitecore modules, and we install “base” instances of these modules into customers’ instances.
The team that builds these modules is not the same team that installs/customizes them.
Further, we have another team that does maintenance, so seams are required to make changes easily and quickly, and not impact “base” functionality of our modules.
Most of the time, we have to customize core features of these “base” modules — this all depends on the particular client’s requirements — and using this approach has saved us time, and prevented lots of headaches.
I would rather use what’s available to me “out of the box” over having to rewrite an entire pipeline processor.
I’d say it is Sitecore best practice because it allows changing behavior without code modification, for example, if you have different implementation for different environments/services then it makes sense to configure which to use this way.
I see. You should really emphasize that what you’re talking about here is modules that are supposed to be used in multiple projects, because utilizing Sitecore’s dependency injection for every day work would quickly make your solution hard to maintain. You’re acting as a library-writer here and this is not something many Sitecore developers do nor should do.
I think this should be done for maintenance reasons as well — even outside of module work: maintainability should be on our minds whenever we work on any project.
I feel that many Sitecore developers don’t use this approach because they don’t know about it, ergo the reason why I wrote this post.
Alright. I hope my comment will serve as a warning for those developers to not take this route.
I think it’s a good approach for all Sitecore development. Even if you aren’t building modules, it’s always sensible work in a way that allows for the site to change an grow organically over time.
Great article Mike. Nice example at sitecore’s flexibility. Look forward to giving this a try.
Mike does this work for Commands? Can I do this?
The private method ReadCommands() of Sitecore.Shell.Framework.Commands.CommandManager in Sitecore.Kernel.dll uses Sitecore.Reflection.ReflectionUtil.CreateObject(String, Object[]). This method does not create nested types, so this paradigm will not work with Commands.
In the past, I had passed in a type via a parameter in the Parameters collection within the Sitecore.Shell.Framework.Commands.CommandContext instance passed to my Command’s Execute() method, though you will have to instantiate the type yourself using Sitecore.Configuration.Factory.CreateObject(…).
Thank you. This Command is in a Sitecore object and I was wondering if I can set a property of that command using config. Didn’t work for me. Then I thought, let’s ask the expert :). Thanks for the help.
I raised a ticket with Sitecore support today about nested types not working with commands. I should have known you’d already have the answer.
[…] Leverage the Sitecore Configuration Factory: Populate Class Properties with Instances of Types Defin… […]
[…] This blog post is a little overdue, but I’ve seen in recent times some discussion about how to implement, what IoC container to use, etc. As stated by Anders Laub in his post Simple IoC container using only the Sitecore API, the opinions on this can be religiously charged, almost fanatic. This post presents the case of not adding a third party IoC framework into an already complicated project – instead use the Sitecore API as a framework for your IoC. There are a lot of fans of using the Sitecore API as the IoC – Mike Reynolds has written about it, Leverage the Sitecore Configuration Factory: Inject Dependencies Through Class Constructors and Leverage the Sitecore Configuration Factory: Populate Class Properties with Instances of Types Defin…. […]