views:

48

answers:

1

How do I deal with:

Current code looks like;

class Class1 : ISomeInterface
    IFooService _service;
    void SomeMethod(){
        _service = new FooService(this);
        .....
}

class FooService : IFooService
    public FooService(ISomeInterface class1Implementer)
    {
        _class1Implementer = class1Implementer
    }

I want to inject the FooService into Class1 with Autofac. How is this registration done? Thanx.

+1  A: 

Since Class1 provides data (a reference to itself) to the 'IFooService` you have to introduce a factory delegate that accepts those data. Consider the following code:

class Class1 : ISomeInterface
{
    private readonly IFooService _service;
    public Class1(Func<ISomeInterface, IFooService> fooServiceFactory)
    {
        _service = fooServiceFactory(this);
        .....
    }
}

Now, the registration goes simply like this:

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

var something = container.Resolve<ISomeInterface>();

Autofac will automagically resolve the Func<..> type to match the IFooService type and the ISomeInterface constructor parameter.

Update: related to the ongoing discussion in comments. Decoupling SomeMethod from the ISomeInterface implementation:

// Class1 is now oblivious to IFooService
class Class1 : ISomeInterface
{
    public Class1()
    {
    }
}

// Class2 now holds the SomeMethod logic 
class Class2 : ISomeOtherInterface
{
    private readonly IFooService _fooService;
    public Class2(IFooService fooService)
    {
         _fooService = fooService;
    }

    public void SomeMethod()
    {
         // do something with _fooService
    }
}

If SomeMethod cannot be separated from Class1 I would still go for the factory alternative. Here is a slight modification though that results in IFooService will not be resolved until actually needed, that is when SomeMethod is called.

class Class1 : ISomeInterface
{
    private readonly Func<ISomeInterface, IFooService> _fooServiceFactory;
    public Class1(Func<ISomeInterface, IFooService> fooServiceFactory)
    {
        _fooServiceFactory = fooServiceFactory;
    }

    void SomeMethod()
    {
        var fooService = _fooServiceFactory(this);
        ....
    }
}

Again Autofac factory features shine. No additional registrations are necessary to get the Func<ISomeInterface, IFooService> delegate working.

Peter Lillevold
+1 I hadn't noticed the "this" argument myself when I wrote my own answer. But shouldn't "void SomeMethod" be "public Class1", to declare a constructor?
Wim Coenen
@Wim - thanks! I mentally assumed that method to be a constructor and never actually read the name :) Now fixed!
Peter Lillevold
@Wim - yes, probably meant a CTOR, but, I was mostly stuck finding the pattern for doing this sort of thing.
theBruce
@Peter - Thanks.
theBruce
Actually, given this insight into delegate factories, I was able to do what I needed via property injection - worked like a charm...love it! Thanx again.
theBruce
@theBruce - glad to be of assistance :) But property injection you say? I always get suspicious with property injection. Care to elaborate in your question? IMO, P.I. should only be used to achieve "optional" dependencies...
Peter Lillevold
" I always get suspicious with property injection." :-) Actually, the "service" in the case I was pursuing is optional, required only by a single method. The case became general for me because I couldn't figure out how to accomplish the injection. In web pages I have to use property injection, btw. Thanks for your interest Peter.
theBruce
@theBruce - yes, I use PI with ASP.Net pages too, though that is because of technical constraints. In my own code I've rarely found the need for optional dependencies, refactoring away the "optional" part tends to give "better" code. But for you, perhaps it is the only sane way, I will not judge your code without knowing more about it :)
Peter Lillevold
@Peter: Well, I am interested in how you would refactor away the "optional" part in the code given, where the IFooService is required by only SomeMethod.
theBruce
@theBruce - I'm thinking, since the service is actually *required* by `SomeMethod` I would argue that the service isn't optional at all. Not if you consider `Class1` as a whole. If you optionally inject the service, the `Class1` service will possibly be in a state where calling `SomeMethod` would fail. That said, if the following events are strongly tied together: 1) `SomeMethod` will be called and 2) `IFooService` exist (and would be injected), I would argue that the `SomeMethod` logic actually belongs in a class of its own, with `IFooService` as a required dependency.
Peter Lillevold
@Peter - IFooService has a dependency on an ISomeInterface, so...Show me the code :)
theBruce
@theBruce - a couple of alternatives there in my answer. Anxious to hear if they manage to thwart your property injection :D
Peter Lillevold