3

My service uses a utility class and that utility class has several public properties. Is there something special I need call to ensure these public properties are setup?

The service uses a ASP.NET host. Inside of Global.ASAX I have declared a new AppHostBase:

public class MyServiceHost : AppHostBase
{
    public MyServiceHost() : base("My Service Host", typeof(ServiceLibrary).Assembly) {}

    public override void Configure(Funq.Container container)
    {
        container.Register<IDbConnectionFactory>(dbConFactory);

        container.RegisterAutoWired<UtilityLibrary>();
        container.RegisterAutoWired<RepositoryLibrary>();
    }
}

Within both my repository library and utility library is a main class. This may class receives the Container and registers more specific utilities and repositories:

public class UtilityLibrary
{
    public UtilityLibrary(Funq.Container container)
    {
        container.RegisterAutoWired<WidgetAActions>();
        container.RegisterAutoWired<WidgetBActions>();
    }
}

In the example below, WidgetARepository was set in the constructor of the RepositoryLibrary class. The RepositoryLibrary class, which contains the WidgetARepository, was supplied to the Container in the Configure method of the AppHost (first snippet above). Even still, the WidgetARepository (below) is never set:

public class WidgetAActions
{
    public WidgetARepository WidgetARepository { get; set; }

    public WidgetA Get(string id)
    {
        var item = this.WidgetARepository.Get(id);
        if (item == null) { return null; }

        // Do something else

        return item;
    }
}

Must I manually call Resolve()? This seems like it would defeat the purpose of injection by doing this.

Ryan D'Baisse
  • 837
  • 11
  • 29

1 Answers1

3

If you are using wanting to use the Funq Container Autowire IoC outside of the ServiceStack service then you need to call Container.AutoWire yourself to have the container inject the relevant dependencies. This call is made behind the scenes in the ServiceStack request pipeline.

For ServiceStack v4:

HostContext.Container.AutoWire(objectToPopulate);

For ServiceStack v3:

AppHostBase.Instance.Container.AutoWire(objectToPopulate);

I would typically add this call to the construtor method of the object I want populated with the injections. So in your case:

public class WidgetAActions
{
    public WidgetARepository WidgetARepository { get; set; }

    public WidgetAActions()
    {
        // (Substitute with v3 usage if required.)
        HostContext.Container.AutoWire(this);
    }

    ...
}

Hope this helps.


Edit: Have you considered having the container inject the corresponding repository to WidgetAActions's constructor?

container.RegisterAutoWired<WidgetAActions>(c => new WidgetAActions(c.Resolve<WidgetARepository>()));

public class WidgetAActions
{
    public WidgetARepository WidgetARepository { get; private set; }

    public WidgetAActions(WidgetARepository repository)
    {
        WidgetARepository = repository;
    }

    ...
}

Edit: Or you could resolve and set the public property of your object to the repository and then you don't have to have a constructor:

container.RegisterAutoWired<WidgetAActions>(c => 
    new WidgetAActions { WidgetARepository = c.Resolve<WidgetARepository>() }
);

public class WidgetAActions
{
    public WidgetARepository WidgetARepository { get; set; }

    ...
}

Or you could call autowire at time of resolving WidgetAActions:

container.RegisterAutoWired<WidgetAActions>(c => {
    var actions = new WidgetAActions();
    container.AutoWire(actions); // All dependencies injected
    return actions;
});

public class WidgetAActions
{
    public WidgetARepository WidgetARepository { get; set; }

    ...
}
Scott
  • 21,211
  • 8
  • 65
  • 72
  • Technically, these are still within the scope of the service. The UtilityLibrary class references the RepositoryLibrary class. Both are registered with the container in the service's AppHost. The only factor that might be a bit unusual (don't see why it would be) is that the UtilityLibrary and RepositoryLibrary both have constructors that add their child classes to the Container. In this scearnio, WidgetARepository would be a child class of RepositoryLibrary. – Ryan D'Baisse Feb 16 '14 at 20:27
  • 1
    @RyanD'Baisse I can see that you are certainly adding your `UtilityLibrary`, `RepositoryLibrary`, `WidgetAActions` and `WidgetBActions` to the container, but the `Container.AutoWire` doesn't run recursively. So when the ServiceStack service runs it will autowire your `WidgetAActions` because you included it in your services. But it can't see the dependencies within `WidgetAActions`. You have to call the `AutoWire` as I suggested. Or use `HostContext.Container.Resolve()` if there is only one dependency. – Scott Feb 16 '14 at 21:06
  • @RyanD'Baisse I have added an alternative method that passes the repository to the constructor of `WidgetAActions` when the container resolves `WidgetAActions`. – Scott Feb 16 '14 at 21:12
  • When you say "I have added an alternative method..." are you referring to your example (above) or to the ServiceStack codebase. Probably an odd question, but I'm new to ServiceStanck and wasn't sure if you're a contributor. – Ryan D'Baisse Feb 17 '14 at 00:12
  • @RyanD'Baisse Yes I mean I have added above. I haven't yet contributed to ServiceStack's features but I am a member of the ServiceStack Experts group and actively answer questions on SO about ServiceStack. Besides I don't think this is a feature that can be changed in ServiceStack, the change would have to be in Funq. As I said you are asking to autowire dependencies in one object, then to autowire the dependencies within all the dependencies that are injected into that one object. That's recursive autowire. It's not a good idea to do that. The IoC isn't magic, it uses reflection to ... – Scott Feb 17 '14 at 08:29
  • ... determine what dependencies are needed in an object by reflecting the public members types, then it looks through the container and instantiates those dependencies into the object. If it then reflected over each dependency, and possibly deeper still, that's a lot of reflection - which is expensive when `autowire` is a convenience method for manually resolving. I have added (above) another method you could use instead of the constructor method. But `autowire` doesn't allow you to nest dependencies and not do some hookup. – Scott Feb 17 '14 at 08:33
  • @RyanD'Baisse So that's 4 methods now in the answer for autowiring up the dependencies. 2 that don't require changing the dependency code, and 2 that require minor change to the constructor. Other than that I am sure you are out of options, but those are the correct way to do it. Please let me know if it helps. – Scott Feb 17 '14 at 08:43
  • 1
    Great answers @Scott! Just used one of them! – Stephen Patten Nov 16 '14 at 19:45
  • 1
    @Stephen Nice one glad it was useful. – Scott Nov 16 '14 at 21:25