José F. Romaniello

Las aventuras y desventuras de un codificador.

If you were reading my previous posts you will notice that I am injecting entities in my IoC. This way the container can inject services in your entities. The other reason to inject entities in your container is when you container integrates very well with a proxy generator (as you can read in my examples of AOP).

The problem is entities are not injectable, the container should inject services in entities but not entities in services nor entities in entities.

So, this is my code snippet for Windsor Container.
The facility:

public class NonInjectableFacility : AbstractFacility
{
    public const string NonInjectablePropertyKey = "noninjectable";

    private readonly ArrayList _nonInjectables = new ArrayList();

    private void Kernel_ComponentModelCreated(ComponentModel model)
    {
        if (model.ExtendedProperties.Contains(ExtendWithPropertyKey))
        {
            _nonInjectables.Add(model.Service);
            foreach (ComponentModel componentModel in Kernel.GraphNodes.OfType<ComponentModel>())
                RemoveNonInjectables(componentModel);
        }
        RemoveNonInjectables(model);
    }

    private void RemoveNonInjectables(ComponentModel model)
    {
        List<PropertySet> propertiesToRemove = model.Properties
            .Where(p => _nonInjectables.Contains(p.Property.PropertyType))
            .ToList();

        foreach (PropertySet propToRemove in propertiesToRemove)
            model.Properties.Remove(propToRemove);
    }

    protected override void Init()
    {
        Kernel.ComponentModelCreated += Kernel_ComponentModelCreated;
    }
}

A registration extension:

public static class FluentRegister
{
    public static ComponentRegistration<T> NonInjectable<T>(
this ComponentRegistration<T> registration) { registration.ExtendedProperties(
Property.ForKey(NonInjectableFacility.NonInjectablePropertyKey).Eq(true)); return registration; } }

And the test:

[Test]
public void should_work()
{
    var c = new WindsorContainer();
    c.AddFacility<NonInjectableFacility>();

    c.Register(Component.For<IInjectableService>()
                   .ImplementedBy<InjectableService>());

    c.Register(Component.For<Service>());

    c.Register(Component.For<ITopMostService>()
                   .ImplementedBy<TopMost>().NonInjectable());

    c.Resolve<Service>().TopMostService.Should().Be.Null();
}

Note: Windsor has an attribute called [DoNotWire].

I took some ideas from Mauricio Scheffer’s answer in this thread and also I’ve stolen others ideas from this post of Tuna Toksoz.

| More

2 comentarios:

Sebastian Talamoni dijo...

Thanks Jose, great article.
As you know we just started using IoC in our MVVM apps and this was a time-saver!

BTW: I think there is a small issue. Inf the facility when you use "ExtendWithPropertyKey" maybe you meant "NonInjectablePropertyKey"<span style=""><span style="border-collapse: collapse; line-height: 38px; -webkit-border-horizontal-spacing: 5px; -webkit-border-vertical-spacing: 5px;">
</span></span>


        private void Kernel_ComponentModelCreated(ComponentModel model)
        {
            if (model.ExtendedProperties.Contains(NonInjectablePropertyKey))

José F. Romaniello dijo...

Thank you for your comment!
About the "ExtendedWithPropertyKey" , you are right. I will fix it soon.

Publicar un comentario