skip to the main content area of this page
Patterns and Practices

 

Unity IoC - Optional Dependency Injection Sample from Extending Unity Samples


If you downloaded the Extending Unity Samples from the Extending Unity Webcast, you will notice that one of the extensions is for Optional Dependency Injection using Unity. Unfortunately, if you are not up-to-speed on unit testing, the downloadable code may be a bit intimidating or hard to understand because you need to view the unit tests and configuration file to understand how it works.

I will attempt to make the Optional Dependency Extension easier to understand by using the OptionalDependencyAttribute in a simple console application.

Below is the Visual Studio 2008 Solution from the webcast with a quick Console Application I added to use the extension.

 

Unity Optional Dependency Injection

 

Optional Dependency Injection Using Constructor

I will be using the OptionalDependencyAttribute to specify that an ILogger is an optional dependency for the CustomersController. In other words, when Unity attempts to create the CustomersController and does not find an Logging Service registered in the container, we do not want it to throw an exception when it tries to create the CustomersController. Instead, Unity via the OptionalDependencyResolver will just catch the exception thrown during the build process and return null to be injected for the ILogger.

Here is my CustomersController Class with the optional dependency on a logging service in the constructor:

 

public class CustomersController
{
    private readonly ILogger _logger = NullLogger.Instance;

    public CustomersController([OptionalDependency] ILogger logger)
    {
        if (logger != null)
            _logger = logger;
    }

    public void InsertCustomer(string name)
    {
        _logger.Write(name);
    }
}

 

Notice the use of the [Optional Dependency] Attribute in the constructor. Now when I create my Unity Container and don't supply an ILogger Service, the value of null is injected into the constructor and no exceptions are thrown:

 

internal class Program
{
    private static void Main(string[] args)
    {
        // ILogger NOT Registered in Container...
        IUnityContainer container = new UnityContainer();
        
        CustomersController controller =
            container.Resolve<CustomersController>();
        
        controller.InsertCustomer("David Hayden");
    }
}

 

Personally, I would just register NullLogger in the UnityContainer as the default ILogger Service and remove the OptionalDependency Attribute, but I am just trying to show the use of the OptionalDependency Attribute here in the constructor. Adding dependencies in the constructor usually signals that indeed the dependency is required, so the OptionalDependency Attribute is probably better used on a Property.

 

Optional Dependency Injection Using a Property

You can add the OptionalDependency Attribute on a Property and that is probably a better practice anyway. The CustomersController Class would now look as shown below. Again we have to check for null as that is what will be injected into the property by Unity if it can't find a logging service registered in the container.

 

public class CustomersController
{
    private ILogger _logger = NullLogger.Instance;

    [OptionalDependency]
    public ILogger Logger
    {
        get { return _logger; }
        set
        {
            if (value != null)
                _logger = value;
        }
    }

    public void InsertCustomer(string name)
    {
        _logger.Write(name);
    }
}

 

What I Don't Like

The unfortunate problem here is that we need to check for null on an optional dependency. In general, you wouldn't specify an optional dependency via the constructor, and hence will probably be using it with settable properties ( or methods - I didn't try it, but assume it works). Rather than injecting null into a property-based optional dependency, Unity just shouldn't set the property if the dependency is not in the Unity Container.

Realistically, you will have some validation on your properties so they cannot be set to invalid values. The Logger Property will probably be checking for null and throwing an exception if it is set to null:

 

[OptionalDependency]
public ILogger Logger
{
    get { return _logger; }
    set
    {
        if (value == null)
            throw new ArgumentNullException(...);
        _logger = value;
    }
}

 

Yep, that won't work as Unity will inject a null value if the Logging Service is not registered in the container.

The other thing I don't like about the Optional Dependency Injection Implementation is that it is exception-based. If you look at the OptionalDependencyResolver you see the code that resolves the value:

 

public object Resolve(IBuilderContext context)
{
    NamedTypeBuildKey newKey = new NamedTypeBuildKey(type, name);
    IBuilderContext contextForResolution =
context.CloneForNewBuild(newKey,
null
); try { return contextForResolution.Strategies.ExecuteBuildUp(contextForResolution); } catch (BuildFailedException) { return null; } }

 

For an optional dependency that is not registered in the container you will get a BuildFailedException. This is caught by the resolver and it returns null, which is why the value of the optional dependency is injected with a null value if it is not registered with the container. Unfortunately this is the best you can do now, but this is an improper way of using Exceptions, which are only for exceptional ( unexpected ) situations. This is an Optional Dependency, so I would not say that the service not being registered is an exceptional situation :) Depending on the scope of your services, this could be throwing exceptions left-and-right during the life of your applications. Exceptions are expensive.

 

Conclusion

You can use the Optional Dependency Injection with XML configuration and named registrations as well. I won't be using the extension, but it does get me thinking about similar extensions that I will talk about later.

Hope this helps.

David Hayden

 


Tags: DependencyInjection, IoC, Unity


Topics



 

Popular Tags



Recent Links