views:

220

answers:

1

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:

  1. 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.
  2. 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.

  3. 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"&gt;
        <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.

  4. 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.

+1  A: 

As an ex Immediacy employee i used to see this sort of problem all the time.

Think of immediacy as being a standard .net web app that sits on top of the framework. They have simply extended the base classes for things like the Page class and added some globally useful objects.

Immediacy does have its own base classes for controls ect but there's nothing stopping you creating your own controls based on the standard .net classes.

One trick I have seen where you need to do something specific that may break an immediacy function is to create a child application then call up pages from it within a custom control that you add to the main app.

This way your child app can do what it likes without breaking anything and the parent immediacy app and simply reads a stream from that app.

in its simplest form the trick is to simply create a control that does one thing ...

WebClient wc = new WebClient();
this.Controls.Add(Page.ParseControl( wc.DownloadString("/childapp/yourcustomthing.aspx") ));

The cleanest other way to do this is to implement the required child component as an ashx handler from what i've seen.

The only issue that may bring up is that you lose the immediacy framework of objects in your child app, but you could easily pass in some key information via querystrings then build your own "depency cache" that contains the stuff you need.

It's not an ideal I know but immediacy does have a habit of making life difficult when you need to do anything above and beyond dropping in lists / similar plugins to pages or templates.

Wardy
Simon Rice
Sounds interesting, I probably could have provided a similar solution to the one you found yourself but not being up to speed with Spring.Net I didn't want to give the wrong advice. Immediacy is generally quite flexible, another idea might have been to put in your own handler and in that call the immediacy one as well as running your own code ... could have been quite code heavy though. It's slowly becoming more and more like sharepoint ... so big that people are scared to go near it, it's a refreshing change to see people taking on such a task.
Wardy