Chase Florell
Chase Florell

Reputation: 47387

Autofac dynamic invocation with Func and Dependency Injection

Providing that I have a class as follows

public class Foo
{
    public Foo(string someTitle, IFooService fooService)
    { 
        // do stuff
    }
}

I know that I can instantiate it like this using DI and autofac

public class Bar
{
    public Bar(Func < string, IFooService, Foo > foo, IFooService fooService)
    {
        var foo = foo("some string", fooService);
    }
}

but I'm wondering if there's any way for Bar to not have to know anything about IFooService? I'd like to not have to inject IFooService into Bar just to satisfy the func.

Essentially something like this

// pseudo code - don't use
public class Bar
{
    public Bar(Func < string, Foo > foo)
    {
        var foo = foo("some string");
    }
}

What I'm really trying to do in my app is remove all instances of Service Location, and rely solely on Dependency Injection.

Upvotes: 1

Views: 1326

Answers (2)

Travis Illig
Travis Illig

Reputation: 23924

Autofac should be able to do exactly what you want by using the Func<T> implicit relationship.

Here is a small repro showing how you can omit the IFooService parameter in the Func<T> and as long as the other dependencies can be resolved by Autofac, you're good to go.

Sample types that do some crazy work...

public class Bar
{
    private Foo _foo;

    // This constructor looks like what you're aiming for...
    public Bar(Func<string, Foo> factory)
    {
        this._foo = factory("title");
    }

    public void ShowMeCoolStuff()
    {
        this._foo.DoWork();
    }
}

public class Foo
{
    private string _title;
    private IFooService _service;

    // The Foo class takes the title AND an IFooService...
    public Foo(string title, IFooService service)
    {
        this._title = title;
        this._service = service;
    }

    public void DoWork()
    {
        Console.WriteLine("Foo title = {0}", this._title);
        this._service.DoMoreWork();
    }
}

public interface IFooService
{
    void DoMoreWork();
}

public class FooService : IFooService
{
    public void DoMoreWork()
    {
        Console.WriteLine("FooService doing more work.");
    }
}

When you register, make sure all the dependencies are registered - Foo, Bar, something implementing IFooService:

var builder = new ContainerBuilder();
builder.RegisterType<Foo>();
builder.RegisterType<Bar>();
builder.RegisterType<FooService>().As<IFooService>();
var container = builder.Build();

When you resolve, everything chains down the line. This resolution...

var bar = container.Resolve<Bar>();
bar.ShowMeCoolStuff();

...will yield the following console output:

Foo title = title
FooService doing more work.

There is fairly robust documentation with examples over on the Autofac site.

Upvotes: 5

Steven
Steven

Reputation: 172666

That's where you use factories for:

public interface IFooFactory
{
    Foo CreateFoo(string value);
}

And bar can simply depend on IFooFactory.

The implementation can look as follows:

public class FooFactory : IFooFactory
{
    private readonly IFooService fooService;

    public FooFactory(IFooService fooService)
    { 
        this.fooService = fooService;
    }

    public Foo CreateFoo(string value)
    {
        return new Foo(value, this.fooService);
    }
}

But the given string seems like a runtime value, i.e. a value that changes from request to request or from call to call. Prevent mixing runtime values with design time dependencies as explained here, here and here. Instead, pass the runtime value as method argument to the Foo methods you are calling. That will completely remove the problem.

Upvotes: 2

Related Questions