Spring.NET & Immediacy CMS (or how to inject to server side controls without using PageHandlerFactor
- by Simon Rice
Is there any way to inject dependencies into an Immediacy CMS control using Spring.NET, ideally without having to use to ContextRegistry when initialising the control?
Update, with my own answer
The issue here is that Immediacy already has a handler defined in web.config that deals with all aspx pages, & so it's not possible add an entry for Spring.NET's PageHandlerFactory in web.config as per a normal webforms app. That rules out making the control implement ISupportsWebDependencyInjection. Furthermore, most of Immediacy's generated pages are aspx pages that don't physically exist on the drive. I have changed the title of the question to reflect this.
What I have done to get Dependency Injection working is:
Add the usual entries to web.config for Spring.NET as outlined in the documentation, except for the adding the entry to the <httpHandlers> section. In this case I've got my object definitions in Spring.config.
Create the following abstract base class that will deal with all of the Dependency Injection work:
DIControl.cs
public abstract class DIControl : ImmediacyControl
{
protected virtual string DIName
{
get
{
return this.GetType().Name;
}
}
protected override void OnInit(EventArgs e)
{
if (ContextRegistry.GetContext().GetObject(DIName, this.GetType()) != null)
ContextRegistry.GetContext().ConfigureObject(this, DIName);
base.OnInit(e);
}
}
For non-immediacy controls, you can make this server side control inherit from Control or whatever subclass of that you like.
For any control with which you wish to use with Spring.NET's Inversion of Control container, define it to inherit from DIControl & add the relelvant entry to Spring.config, for example:
SampleControl.cs
public class SampleControl : DIControl, INamingContainer
{
public string Text
{
get;
set;
}
protected string InjectedText
{
get;
set;
}
public SampleControl()
: base()
{
Text = "Hello world";
}
protected override void RenderContents(HtmlTextWriter output)
{
output.Write(string.Format("{0} {1}", Text, InjectedText));
}
}
Spring.config
<objects xmlns="http://www.springframework.net">
<object id="SampleControl" type="MyProject.SampleControl, MyAssembly">
<property name="InjectedText" value="from Spring.NET" />
</object>
</objects>
You can optionally override DIName if you wish to name your entry in Spring.config differently from the name of your class.
Provided everything's done correctly, you will have the control writing out "Hello world from Spring.NET!" when used in a page.
This solution uses Spring.NET's ContextRegistry from within the control, but I would be surprised if there's no way around that for Immediacy at least since the page objects themselves aren't accessible. However, can this be improved at all from a Spring.NET perspective? Is there maybe an Immediacy plugin that already does this that I'm completely unaware of? Or is there an approach that does this in a more elegant way? I'm open to suggestions.