This is a fairly straight forward decorator pattern scenario, with the complication that the decorated type has a constructor parameter that is dependent on the type into which it is being injected.
I have an interface like this:
interface IThing
{
void Do();
}
And an implementation like this:
class RealThing : IThing
{
public RealThing(string configuration)
{
... implementation ...
}
public void Do()
{
... implementation ...
}
}
And a decorator like this:
class DecoratingThing : IThing
{
IThing _innerThing;
public DecoratingThing(IThing thing)
{
_innerThing = thing;
}
public void Do()
{
_innerThing.Do();
}
}
Finally, I have some types that require an IThing
, called Depender1
, Depender2
etc..
class DependerX()
{
public DependerX(IThing thing)
{
... implementation ...
}
}
I want to configure an IOC container to resolve instances of DependerX
such that they are injected with RealThing
decorated with a DecoratingThing
. Important: Each DependerX
type requires a different value of configuration
to be passed to the constructor of its RealThing
, say "ConfigX" in each case. e.g. The work done by the IoC container might be:
new Depender1(new DecoratingThing(new RealThing("Config1")));
new Depender2(new DecoratingThing(new RealThing("Config2")));
... and so on.
In Unity, this seems quite clunky to configure as I have to mix in the decorator with the decorated:
container.RegisterType<IThing, DecoratingThing>("ConfigX",
new InjectionFactory(container => new DecoratingThing(new RealThing("ConfigX"));
container.RegisterType<DependerX>(
new InjectionConstructor(new ResolvedParameter<IThing>("ConfigX");
And repeat, violating DRY nicely, for each DependerX
.
What I'd like to do is remove the need to embed the construction of RealThing
in the construction of DecoratingThing
in each named registration of IThing
- and declare the decoration just once. This is so, for example, that if the decoration needs to change in future, it's easier to reconfigure. The best I came up with is this helper method for registration:
void RegisterDepender<TDepender>(IUnityContainer container, string config)
{
container.RegisterType<TDepender>(new InjectionConstructor(
new ResolvedParameter<IThing>(config)));
container.RegisterType<IThing, DecoratingThing>(config,
new InjectionFactory(c => new DecoratingThing(new RealThing(config))));
}
This removes repetition at least, but I still have to embed the construction of the RealThing
inside the DecoratingThing
- this means I can't vary their lifetimes independently for example. I can't register IThing
again to do this because I've used up my registration of that interface for the name. If I want to do that I have to introduce another set of named instances like so:
void RegisterDepender<TDepender>(IUnityContainer container, string config)
{
string realConfig = "Real" + config;
container.RegisterType<TDepender>(new InjectionConstructor(
new ResolvedParameter<IThing>(config)));
container.RegisterType<IThing, DecoratingThing>(config,
new InjectionFactory(c => new DecoratingThing(
container.Resolve<IThing>(realConfig))));
container.RegisterType<IThing, RealThing>(realConfig,
new ContainerControlledLifetimeManager(),
new InjectionConstructor(config));
}
Is this really the best option? It feels complex and potentially hard for those that will come after to grok. Do other IoC containers have a compelling way to cover this scenario? Since the pattern for how injection works is repeated for each DependerX, is there a way to only use a named instance at the top (DependerX
) level?
Any other comments?
Dependency Injection (DI) Dependency Injection is defined as a design pattern that allows removing hard-coded dependencies from an application. There is one major point to remember: “Inversion of control is principal and Dependency Injection is implementation”.
Dependency injection in . NET is a built-in part of the framework, along with configuration, logging, and the options pattern. A dependency is an object that another object depends on. Examine the following MessageWriter class with a Write method that other classes depend on: C# Copy.
Dependency injection is a pattern to allow your application to inject objects on the fly to classes that need them, without forcing those classes to be responsible for those objects. It allows your code to be more loosely coupled, and Entity Framework Core plugs in to this same system of services.
A class that lets you specify a factory method the container will use to create the object.
The class design itself seems reasonable. Here's a convention-based container configuration that basically does this:
public class MyConventions : UnityContainerExtension
{
protected override void Initialize()
{
var dependers = from t in typeof(IThing).Assembly.GetExportedTypes()
where t.Name.StartsWith("Depender")
select t;
foreach (var t in dependers)
{
var number = t.Name.TrimStart("Depender".ToArray());
var realName = "Real" + number;
var decoName = "Deco" + number;
var config = "Config" + number;
this.Container.RegisterType<IThing, RealThing>(realName,
new InjectionConstructor(config));
this.Container.RegisterType<IThing, DecoratingThing>(decoName,
new InjectionConstructor(
new ResolvedParameter<IThing>(realName)));
this.Container.RegisterType(t,
new InjectionConstructor(
new ResolvedParameter<IThing>(decoName)));
}
}
}
This configuration will automatically add all classes that match the above predicate, so once you've set it up, you can just add more classes (like Depender4
or Depender5
) without revisiting the container configuration at all.
The above configuration satisfies these unit tests:
[Fact]
public void ContainerCorrectlyResolvesDepender1()
{
var container = new UnityContainer().AddNewExtension<MyConventions>();
var actual = container.Resolve<Depender1>();
var deco = Assert.IsAssignableFrom<DecoratingThing>(actual.Thing);
var thing = Assert.IsAssignableFrom<RealThing>(deco.Thing);
Assert.Equal("Config1", thing.Configuration);
}
[Fact]
public void ContainerCorrectlyResolvesDepender2()
{
var container = new UnityContainer().AddNewExtension<MyConventions>();
var actual = container.Resolve<Depender2>();
var deco = Assert.IsAssignableFrom<DecoratingThing>(actual.Thing);
var thing = Assert.IsAssignableFrom<RealThing>(deco.Thing);
Assert.Equal("Config2", thing.Configuration);
}
[Fact]
public void ContainerCorrectlyResolvesDepender3()
{
var container = new UnityContainer().AddNewExtension<MyConventions>();
var actual = container.Resolve<Depender3>();
var deco = Assert.IsAssignableFrom<DecoratingThing>(actual.Thing);
var thing = Assert.IsAssignableFrom<RealThing>(deco.Thing);
Assert.Equal("Config3", thing.Configuration);
}
Have you ever thought about basing your decorators on the Unity Interception functionality? Then it would be really easy to say "intercept the calls to IThing
using this Interceptor" just once.
container.AddNewExtension<Interception>();
container.RegisterType<IThing>(new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<DecoratingThingBehavior>());
and then it would be "inject this IThing
into this and that Depender
"
container.RegisterType<Depender1>(new InjectionConstructor(new ResolvedParameter<IThing>("myNameForThing")));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With