Skip to content

Instantly share code, notes, and snippets.

@alexfoxgill
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexfoxgill/f4d122781e75b4b5dac2 to your computer and use it in GitHub Desktop.
Save alexfoxgill/f4d122781e75b4b5dac2 to your computer and use it in GitHub Desktop.
Runtime context dependent proxy switcher proposal for Simple Injector
container.RegisterRuntimeProxy<ITestGuard>(context =>
new TestGuardSwitcher(() =>
context.Ancestors().Any(x => x.ImplementationType == typeof(TestController))
? new NullTestGuard()
: new OtherTestGuard());
class TestGuardSwitcher : ITestGuard
{
public TestGuardSwitcher(Func<ITestGuard> switcher)
{
// ...etc...
}
}
// or to use the container possibly return a Type from the function
container.RegisterRuntimeProxy<ITestGuard, TestGuardSwitcher>(
context =>
context.Ancestors().Any(x => x.ImplementationType == typeof(TestController))
? typeof(NullTestGuard)
: typeof(OtherTestGuard));
// then the Func<ITestGuard> in TestGuardSwitcher is injected as () => container.GetInstance(runtimeFunc(context))
@dotnetjunkie
Copy link

There is another problem with this code, that I didn't spot while writing my comment on stackoverflow.

To be able to work, the Ancestors() method should be able at runtime to determine the current list of ancestors of the TestGuardSwitcher. This list can change at runtime, because TestGuardSwitcher can be a singleton, while injected into many different object graphs. So this list of Ancestors is not available while building the object graph.

But to be able to determine the list of ancestors, Simple Injector actually has to know which object graph you are currently executing. But it has no way of knowing this. It is information it might be aware of while building the object graph, but executing methods on that graph is done at a later moment in time. To be able to pull this off, you would have to tell Simple Injector the execution is done in some sort of scope. Something like this:

using (container.BeginLifetimeScope())
{
    container.GetInstance<HomeController>().Index();
}

Under the covers, Simple Injector could store that list of Ancestors in an active scope, to be able to retrieve it for you. But what if the user does this:

using (container.BeginLifetimeScope())
{
    container.GetInstance<HomeController>().Index();
    container.GetInstance<TestController>().Index();
}

How does Simple Injector know that during the execution of TestController.Index the ancestors of the TestController should be active. It is possible for Simple Injector (and for you as user) to intercept the resolving of root types and flag this as the current type. But what about this?

using (container.BeginLifetimeScope())
{
    var home = container.GetInstance<HomeController>();
    var test = container.GetInstance<HomeController>();
    test.Index();
    home.Index();
}

I'm not saying it is impossible to do, but it is rather complicated to get such thing implemented correctly in the library and this will most likely have performance penalties. There is a design rule in Simple Injector that says that the library should be fast by default; there should be no surprises when it comes to performance during the main flow in the application.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment