This blog post describes dependency injection with the Sitecore ASP.NET CMS.
The dependency injection design pattern allows you to configure types to insert dynamically into a running program. The factory pattern provides an API to instantiate objects. Sitecore provides an implementation of the factory pattern that uses reflection to fulfill dependency injection using type definitions that you can configure. Dependency injection is a key point of extensibility for Sitecore: you can override almost anything, and what you override is frequently a small part, which makes extension and customization both easy and maintainable. Learn more about dependency injection or the factory pattern.
Most important to type configuration is the type signature. A type signature consists of three components:
Where potentially valuable, each of these values appears in a separate field or attribute. More commonly, Sitecore uses a single string such as the following:
Numerous Sitecore features use items in a database to configure objects to instantiate dynamically, and the technique for passing parameters immediately after instantiation depends on the type of the object. For example, the layout engine uses layout details to determine the layout, sublayout, and rendering definition items to use to present a content item based on criteria of the HTTP request, and what parameters to pass to those presentation components. Data validation uses definition items to specify the classes used to implement validation, and properties to set when instantiating those classes. The rules engine provides a browser-based user interface to properties. For more information about the layout engine, see the Presentation Component Reference. For more information about the rules engine, see the Rules Engine Cookbook and my blog post Using the Sitecore Rules Engine in a Custom Context: Setting the Context Device. For more information about validation, see the chapter about validation in the Client Configuration Cookbook and my blog posts Validate that the Value of One DateTime Field Follows Another with Sitecore and Validate a Sitecore Checklist, Multilist, Treelist, or TreelistEx Field.
In addition to using items to define types and parameters for instantiation, Sitecore also uses entries in the web.config and its include files to define types to instantiate. For more information about the web.config approach to dependency injection, see my blog post The Sitecore ASP.NET CMS Configuration Factory.
This blog post does not describe the Unity dependency injection container used by products including Sitecore E-Commerce Fundamental Edition (SEFE). For more information about Unity, see the Sitecore E-Commerce Developer Cookbook as well as the and Extending Sitecore E-Commerce - Pricing and Extending Sitecore E-Commerce - Order Lines posts on the Getting to Know Sitecore blog by Adam Conn.
John - thank you for the articles on DI within Sitecore. I am currently looking for a DI solution that would allow me to inject service dependencies into the sub layouts and layouts I am currently using. Do you know if Spring.Net or others such as Castle have been used with Sitecore 6?
@Brian: I seem to remember someone having success with Castle Windsor, but I don't remember the details. I found a few things that mention both Sitecore and Castle Windsor, but I don't even know if I've heard of Spring .NET, and I don't know if anyone has used Castle Windsor Sitecore 6 or for your specific purpose, sorry.
John, tgans so much fir the reply . No worries, I was able to get it to work. Spring does require an HttpModule as well as a PageHandler, but it appears to work well. The only modification I had to make was an added web.config in the /sitecore path to remove the PageHandler. As must as Sitecore does in the page life cycle I was concerned about any adverse impacts ... Is it possible that adding a PageHandler for *.aspx will interfere with Sitecore? I am also considering Unity ... Thanks again!
@Brian: It's possible, but I wouldn't expect interference. To my knowledge, Sitecore really extends the page lifecycle, and attempts not to interfere with anything. Primarily, it invokes pipelines at various points, but also uses the renderLayout pipeline to assemble the control tree instead of the default approach (I assume it extends the default approach rather than replacing it). So I can't be sure, but I assume it shouldn't interfere. Curious why you had to add web.config to /sitecore though - is that just an optimization?
@John - when I added in the PageHandler, I was able to open the Sitecore application, but I had one small problem. If I went to view the contents of a folder by selecting it in the content tree, the pane on the right would reflect an error (I think it was a 404 error) - when I removed the PageHandler the problem was corrected. Here is the handler I removed: <add name="SpringPageHandler" verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, Spring.Web" /> If you need more I am happy to provide - I am now able to inject service dependencies from my components into the web application sub layouts.
@Brian: If time ever allows and I remember to come back, or if you tell me it's important, I will try to investigate the page handler issue. Otherwise, just glad you got it working.
@Brian: One thing that comes to mind is the order of page handlers in web.config - you might try ensuring that spring comes after any Sitecore handlers, and you might be able to eliminate that web.config. Then again, that might not have any impact, might break spring.net, etc.
John - you were totally right....moving the PageHandler below the Sitecore elements did the trick...thanks so much for the help! Now :) the only problem I have left...trying to get injection to work within a custom event handler / custom link provider....I am fairly certain the spring engine is using an HttpModule to fire the injection, so apparently it isn't available at that time. Any thoughts?
@Brian: Can you use some kind of generic event handler that somehow invokes spring? I'm totally guessing/stumbing here, as I don't really understand your context, don't know spring, and don't really understand dependency injection in full. Not sure why you can't use the configuration factory for example for the link provider and events, even if just to override the defaults with something that invokes spring. I thought there was a way to trap all events if that might help, but I don't remember exactly how - maybe something about tapping into lower layers (like the data layer).
Actually, I think you're right on it…what is happening is that Sitecore is creating the LinkProvider earlier than Spring is loaded. And apparently that is treated as a singleton (or static reference) from the LinkManager. So, at the time of instantiation, the Spring system isn't ready. I added some code to the GetItemUrl that checks the dependency I am trying to inject - if it's null, fetch it from the container, the first call to the method sets the item. Works fine, but I want to keep away from coding any DI framework specifics into the classes - Spring's configuration should allow me to do all of this via XML. … I'll check out the configuration factory - it looks like that might work for me … also would it be possible for me to implement something in the Sitecore pipeline that would load the Spring factory earlier?
@Brian: You might be able to add a processor to the <initialize> pipeline (I think that's the first one Sitecore runs) to load spring. Or you might look into a standard ASP.NET solution - maybe you can do something with global.asax or something to load spring before Sitecore even gets to <initialize>. Thanks for doing the research here.
@Brian : Are you sure you removed : <add name="SpringPageHandler" verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, Spring.Web" /> Shouldn't it be a Sitecore handler instead? Or ?
Janus - no, I didn't remove the handler....everything works well except for the fact that I cannot use auto-injection of items in the pipeline - simply because Spring doesn't know about the items - they aren't "managed" in the container. I can manually fetch the items from the Spring context by name - that works fine.
@Brian, so to understand this.... You're able to use Spring.NET and inject types into the user controls via property-injection from Spring.NET and thereby access the lower levels of services as one normally would do when utilizing DI? The reason I ask is because I cannot get it to work with Sitecore 6.5, the injected types are null, so I always find myself doing the antipattern GetObject.... :( inside .ascx/ .aspx btw.. what do you mean by items? Thank you for your quick answer, despite it was an old post I found you at :)
@janus, yes I am able to use Spring to inject services into sub layouts - even using auto-wiring by name, etc. Yes, the word "item" in this case doesn't mean Sitecore item - what I meant to say was that the classes that are added into the pipeline are not seen by Spring, and therefore I cannot use auto-wiring on them. I do think there is a way to do this - Spring is available when the classes are constructed, but I am not sure how to tell spring to manage these classes as well. I think it would be similar to how Spring manages membership providers, but I just don't have time to work on it at the moment.