Search code examples
dependency-injectionparametersconstructorautofac

Autofac: how to register and resolve a type whose constructor requires a DirectoryInfo object?


I'm trying to do something which I suspect is pretty basic in Autofac (I'm just getting started on IoC/DI concepts and I'm still very wobbly-kneed), but I'm running into dead-ends. Any similar info I'm finding tends to cover far more complex scenarios (delegates, generics, etc.). Mine involves just a simple ol' DirectoryInfo constructor parameter.

I have a type that takes a DirectoryInfo object in its constructor, and I want to register and resolve that type with Autofac:

Imports System.IO

Friend Class UpdateCommand
  Implements IUpdateCommand

  Public Sub New(Root As DirectoryInfo)
  End Sub
End Class

Here's my registration code:

oBuilder = New ContainerBuilder
oBuilder.RegisterType(Of UpdateCommand).As(Of IUpdateCommand)()
oContainer = oBuilder.Build

But when I try to resolve it:

Using oScope As ILifetimeScope = oContainer.BeginLifetimeScope
  oUpdateCommand = oScope.Resolve(Of IUpdateCommand)
End Using

I get an error:

DependencyResolutionException: None of the constructors found on type 'VsLayout.UpdateCommand' can be invoked with the available services and parameters: Cannot resolve parameter 'System.IO.DirectoryInfo Root' of constructor 'Void .ctor(System.IO.DirectoryInfo, Years, Editions)'.

That exception message contains a link to the docs, which redirects and tells us this:

Finally, you may have a parameter in your constructor that isn’t actually a service and won’t be available in the container. For example, you usually don’t register plain string or integer values in the container, but if your constructor takes a value like this, it will fail to run. In that case, you can declare a Parameter on the registration to provide the extra parameter.

That link, in turn, tells us this:

You could use a lambda expression component for that

I was hoping that was going to be my Aha! moment, but I tried modifying my registration:

oBuilder.Register(Function(x)
                    oRoot = New DirectoryInfo("S:\SomeDirectory")

                    Return New UpdateCommand(oRoot)
                  End Function).As(Of IUpdateCommand)()

...and then I got a different error:

ComponentNotRegisteredException: The requested service System.Object has not been registered.

That one throws me completely for a loop. System.Object? Where is that supposed to come from? I am now officially lost.

How can I successfully register and resolve my UpdateCommand type? The docs don't seem to cover this nuance, at least not that I can find.

--EDIT--

Upon further review, I see that the docs do indeed cover this exact nuance:

// Using a TYPED parameter:
builder.RegisterType<ConfigReader>()
       .As<IConfigReader>()
       .WithParameter(new TypedParameter(typeof(string), "sectionName"));

For some reason I looked right past that one.


Solution

  • I was able to get my type to resolve using the syntax suggested in this answer, which showed up in the Related questions section as soon as I posted.

    Dim oParameter As Parameter
    
    oRoot = New DirectoryInfo("S:\VisualStudio")
    oParameter = New NamedParameter(NameOf(BaseCommand.Root), oRoot)
    
    oBuilder.RegisterType(Of UpdateCommand).As(Of IUpdateCommand).WithParameter(oParameter)
    

    It now resolves easily.