DI property injection in Orchard

Tags: english, orchard, autofac

As everyone developing apps using Orchard surely know, constructor injection in Orchard is a built-in feature. It’s used extensively throughout the whole framework and makes the developer’s life way much easierUśmiech But there are scenarios where it’s not enough and one may want to do property injection instead. The most common reason is a danger of having circular dependencies, nasty thing hard to trace and sometimes very hard to fix…

Property injection comes to the rescue, but it’s not a thing that comes out-of-the-box in Orchard. It’s ok that the framework doesn’t try to forcibly fill my object properties – property injection should be used only as an alternative to ctor injection and only in certain scenarios.

There are two ways to fill object properties with instances from the container in Orchard, which I found the most useful:

  • On the object’s level (the one that has properties you need to fill) – using Autofac’s IComponentContext.InjectUnsetProperties(object) method.
  • On the global level – via Autofac.Module implementation, utilizing the former

Object-level property initialization

It’s a good way to go if you want to inject properties of a specific object only.

This approach requires you to have IWorkContextAccessor object injected into the constructor first. Let’s call this object ‘context’. Filling the object is as easy as calling context.Resolve<IComponentContext>().InjectUnsetProperties(this). You may do that wherever you want to, eg. in a place where your object initialization happens. Of course look out with calling that in a constructor – you may easily run into a circular dependency problem. It’s meant to be called after the object has been constructed.

Of course you may pass any object to InjectUnsetProperties method and have it’s properties filled.

Global-level property injection

Use this approach if you want to do property injection on all objects registered in the container.

It is a more complex solution as it requires you to create an implementation of Autofac.Module class and plug into the container-building processes. Nothing to fear, thoughUśmiech 

First of all we need to create and implementation of Autofac.Module class and override method AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration).

Next step is to hook up the Activated event of a given IComponentRegistration and pass an event handler to it that would inject all unset properties of a processed object. Here is the code:

public class MyModule : Module {
    protected override void AttachToComponentRegistration(
        IComponentRegistry componentRegistry, 
        IComponentRegistration registration)
    {
        registration.Activated += (s, e) 
            => e.Context.InjectUnsetProperties(e);
    }
}

Nothing more, nothing less – very simple stuff, I told youPuszczam oczko This is only a simple example, of course -  you can put more fancy logic inside if you need to (e.g.. act only on specific objects and such).

I’ve recently posted an answer on SO to question about achieving property injection in Orchard. It was about filling properties of a specific type only, leaving other properties untouched – a bit more sophisticated stuff. If that’s your case – take a look. The solution I provided was based on the Orchard.Logging.LoggingModule, which injects ILogger implementations.

1 Comment

  • Jimasp said

    This doesn't work for me. Maybe I'm missing something simple?

    (See http://orchard.codeplex.com/discussions/431713).