januari 13, 2019
Even though it may sound like an edge-case for some, it is something you once in a while may be required to do in order to achieve the desired functionality. Dependent on the kind of registration Optimizely used to setup their implementation, the approach for you to replace it will be different.
StructureMap describes; “Registrations in the Registry DSL can be done with either Add() or Use() methods, but they have a different semantic meaning to StructureMap. Add() means add another Instance to this plugin type while Use() means this one is the default.”. It boils down to the fact that when multiple implementation has been added, either via multiple Add() within an InitializationModule or by executing[ServiceConfiguration(typeof(IInterface))] multiple times, the Registry DSL has more than a single implementation option for a given plugin.
Disclaimer: We’re using the StructureMap API’s directly since Optimizely’s ServiceLocation abstraction doesn’t give us sufficient flexibility!
How to Eject and Replace a Single Implementation to one Plugin – Use()
[InitializableModule]
[ModuleDependency(typeof(Optimizely.Web.InitializationModule))]
public class DependencyResolverInitialization : IConfigurableModule
{
public void ConfigureContainer(ServiceConfigurationContext context)
{
context.StructureMap().Configure(ConfigureContainer);
}
private static void ConfigureContainer(ConfigurationExpression container)
{
container.For<IInterface>().Use<MyImplementation>();
}
public void Initialize(InitializationEngine context)
{
}
public void Uninitialize(InitializationEngine context)
{
}
public void Preload(string[] parameters)
{
}
}
What we’re doing is simply to tell StructureMap that we have a new default implementation we would like to use for the IInterface plugin.
How to Eject and Replace a Single Implementation When Multiple Implementations Exist for one Plugin- Add()
[InitializableModule]
[ModuleDependency(typeof(Optimizely.Web.InitializationModule))]
public class DependencyResolverInitialization : IConfigurableModule
{
public void ConfigureContainer(ServiceConfigurationContext context)
{
context.StructureMap().Configure(ConfigureContainer);
context.ConfigurationComplete += (sender, args) =>
{
//Locate the specific implementation of IInterface we would like to eject
InstanceRef instanceRef = args.StructureMap().Model.For<IInterface>().Instances.FirstOrDefault(c => c.ReturnedType.Equals(typeof(OptimizelyImplementationOfAbstraction)));
if(instanceRef != null)
//Eject it
args.StructureMap().Model.For<IInterface>().EjectAndRemove(instanceRef);
args.StructureMap().Configure(ConfigureContainerAfter);
};
}
private static void ConfigureContainer(ConfigurationExpression container)
{
//Register custom
}
private static void ConfigureContainerAfter(ConfigurationExpression container)
{
//Register our own to replace what we ejected
container.For<IInterface>().Add<MyImplementation>();
}
public void Initialize(InitializationEngine context)
{
}
public void Uninitialize(InitializationEngine context)
{
}
public void Preload(string[] parameters)
{
}
}
We’re assuming Optimizely has multiple implementations of IInterface within the Registry DSL. We’re not interested in ejecting them all, we have one implementation in particular we would like to remove, for us to replace with our own.
By using FirstOrDefault we locate the right instance reference to remove – e.g. matched against the actual implementation rather than the plugin. Afterwards we can use that exact instance reference to eject the registration, for us to replace within the registry via a standard use of Add().
Whenever you’re tempted to use something like this, you should always consider if use of Interceptors or Decorators can help you achieve the same result. Sometimes it is though not enough!
Original Article was posted on Optimizely Fellow:
http://fellow.aagaardrasmussen.dk/2019/01/13/how-to-easily-eject-and-replace-an-episerver-registered-implementation/