This post follows on from my introductory post about Sitecore configuration, where I talked about using settings and retrieving XML fragments. In this post I talk about how you can use Sitecore configuration to instantiate and populate objects of your choosing. This is useful for cutting down on the amount of mapping code you have to write, without needing to put attributes all over the place.
Almost everyone who has used Sitecore has used this way of configuring objects, even if they were not aware of it at the time. The most common examples that you’ll come across are pipeline processors, event handlers, and commands. Basically: pretty much anywhere in the configuration where you have to specify a type attribute on your element. Internally, Sitecore will be sending these nodes to the Factory.CreateObject method, which is what handles the actually instantiation of the classes that you are directing it toward.
In practice, you’ll often use this in conjunction with an interface or base class if you’re doing something completely custom. For the purposes of this post, let’s keep it simple and assume we have the following class:
public class MyClass { public string Name { get; set; } public MyClass() { } public MyClass(string name) : this() { Name = name; } public void DoStuff() { // Logic } }
The class is not a pipeline processor, or an event handler, it’s just a plain old class whose instantiation we plan to control through configuration. The very simplest use of configuration to create an object is to create a node with a type attribute in the configuration as follows:
<configuration> <sitecore> <customClass type="MyType, MyAssembly" /> </sitecore> </configuration>
You can get Sitecore to instantiate the class – as directed – by doing the following:
public class Program { public void Main() { var myClass = Factory.CreateObject("customClass", true); } }
A default constructor is assumed, although it is possible to provide constructor parameters by adding child <param> elements. The following configuration snippet will look for a parameter with a single string argument on the indicated type:
<configuration> <sitecore> <customClass type="MyType, MyAssembly"> <param description="name">foo</param> </customClass> </sitecore> </configuration>
The constructor parameters are resolved in the order they are given; while you can provide a description attribute, it ultimately has no effect on resolution. I would suggest caution when doing this, because it’s very easy to break things by rearranging the constructor parameters. If the classes you are using are your own, then I would suggest scrapping the constructor in favour of properties, as Sitecore can also populate these through a similar mechanism.
In order to populate certain named properties of your newly-created object, you can add child nodes that match the name of the property you wish to set. The name of the child element must match that of the property you wish to set, but is not case sensitive. The following example demonstrates this:
<configuration> <sitecore> <customClass type="MyType, MyAssembly"> <name>foo</name> </customClass> </sitecore> </configuration>
The above XML will create the instance of MyType and then set the Name property. This offers a much nicer way to populate your objects. It is still susceptible to breakage if the property is renamed, but it’s less fragile than using the constructor method that I showed earlier.
The benefit of setting up your objects like this is that your code will end up being more generic, which should promote re-use in the longer term. It also reduces the need to hard-code values, which makes them easier to change per-environment, or without necessarily doing a full release of the application (in emergencies, for example).
The last thing I wanted to touch on in this particular post is that you are not restricted to creating one object at a time. Sitecore’s instantiation and assignment logic can create instances of custom types when it is assigning properties (or creating constructor parameters). For example, if the Name property above were actually an instance of a custom QualifiedName class, you could easily change the XML configuration as follows:
<configuration> <sitecore> <customClass type="MyType, MyAssembly"> <name type="QualifiedName, MyAssembly"> <qualifiedName>bar</qualifiedName> </name> </customClass> </sitecore> </configuration>
As far as I am aware, there is no practical limit on the complexity of the instantiation imposed by Sitecore. At the same time, though, too much configuration is quite likely to impact maintainability simply because people won’t bother with learning how to manage it.
There’s a fair amount of more advanced usage you can get out of the Sitecore configuration, which you can plainly see if you just look at the vanilla Sitecore configuration – after all, anything that it does you can do too (for the most part, anyway). I plan to cover the more useful ones in the final post of this series.