I've got a Credentials
class that should be provided through dependency injection as an instance to all constructors which need it. Currently I've solved this problem by registering a single instance of the class to my DI container, with a singleton lifecycle. This ensures, per DI invocation, that all objects receive the same credentials. This works, but is a little awkward because the properties of the Credentials
singleton will change between each explicit DI invocation. This means each recipient constructor must immediately "grab and save" credentials properties from the Credentials
instance before they change.
What would make this better is if I could get the DI container to create a new Credentials
instance, per-graph or per-invocation, that is based on a prototype object (yes, GOF "Prototype" pattern). I am using Simple Injector, so my first solution looks like this:
public static Credentials creds; //Implements ICloneable
//....
var prototypeTransientLifestyle = Lifestyle.CreateCustom(
name: "Prototype Transient",
// instanceCreator is of type Func<object>
lifestyleApplierFactory: instanceCreator =>
{
return () => creds.Clone();
});
I think this works but, even so, it has two weaknesses. First, it can only be applied to my Credentials
class. I'd like it to be generically reusable. Second, it creates potentially many clones within a single, explicit DI invocation. I'd like it to have "per-graph" lifecycle so that it creates the clone just once and re-uses it for the remainder of that DI invocation.
Any ideas of how to proceed?
Incidentally, I know that "per-graph" lifecycle suffers from problems associated with lazy evaluation. I don't have any lazy evaluation, so it is not a concern.
I think I have a partial solution to my problem. To achieve the prototype cloning in a generic fashion, I can do this:
container.Register<Credentials>(() => (Credentials)creds.Clone());
Now I'd still like to have the "per graph" behavior. Further reading suggests I need to use a Simple Injector Scope
. Apparently this requires that I have a central location where my DI container is invoked, so that I can explicitly create the scope. My code is indeed well-suited for that, but I'm still wondering if there is another way to achieve "per graph" which does not require explicitly creating a scope.
As noted in the documentation, Simple Injector has no notion of a "per graph" lifestyle. Instead, the Scoped lifestyle provides behavior which is usually close enough.
Apparently this requires that I have a central location where my DI container is invoked, so that I can explicitly create the scope.
That is correct. This central location is called the Composition Root and every application will have it.
I'm still wondering if there is another way to achieve "per graph" which does not require explicitly creating a scope.
The Simple Injector GitHub repository contains a code example that demonstrates the Per Graph lifestyle, but my advise is to stick with the built-in construct, namely the ScopedLifestyle
.