DivineInject.GitHub.io

View the Project on GitHub DivineInject

Scopes

DivineInject only has one scope: singleton. This means that all dependencies managed by DivineInject are singleton instances, shared across your application. This would seem to force us to use only singletons across the application. However, it is quite likely you have objects in your domain which are not singletons: User, Session, Order etc. How do we create these objects?

User Scope Example

For example, perhaps we have a notion of user in our domain. We have one instance of the User object per registered user, this class has dependencies, which are managed by DivineInject. It might look like this:

internal class User
{
    private readonly IOrdersService _ordersService;

    public User(IOrdersService ordersService)
    {
        _ordersService = ordersService;
    }
}

We want to be able to create instances of this class, on demand. However, we don't want to break the "hollywood principle" (don't call us, we'll call you). To do this, we create a very simple factory interface, to create users:

internal interface IUserFactory
{
    User Create();
}

We could implement this interface, by explicitly calling DivineInject:

internal class DivineInjectUserFactory : IUserFactory
{
    public User Create()
    {
        // DON'T DO THIS - just an example
        var ordersService = DivineInjector.Current.Get<IOrdersService>();
        return new User(ordersService);
    }
}

However, this is pretty horrible and would lead to references to DivineInject smeared all over your code, which we don't want. Instead, DivineInject can actually generate this class for you (at runtime). This is done when you configure the rest of your singleton bindings:

DivineInjector.Current
    .Bind<IUserFactory>().AsGeneratedFactoryFor<User>();

Now if I have a class which needs to create a User object, I can depend on the IUserFactory dependency. For example:

internal class LoginService
{
    private readonly IUserFactory _userFactory;

    public LoginService(IUserFactory userFactory)
    {
        _userFactory = userFactory;
    }

    public User Login(string username, string password)
    {
        // todo authentication
        return _userFactory.Create();
    }
}

Each call to LoginService.Login will return me a newly created User object, with dependencies injected. This way I can create new scope objects, specific to my domain; the lifetime of these objects is clearly managed by my code, with no complex DI framework configuration to master.


Of course, the really interesting thing with having an object like this is that it might need some state. For example, my User class might need some kind of user id. How can we pass state into these objects? Doing this will make my User class a rich domain object.