Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Structuremap - Override registration

Is it possible to register an interface in a registry, then "re-register" it to override the first registration?

I.E.:

For<ISomeInterface>().Use<SomeClass>();
For<ISomeInterface>().Use<SomeClassExtension>();

What I want here on runtime is that my object factory returns SomeClassExtension when I ask for ISomeInterface.

Thanks in advance!

like image 234
Samuel Poirier Avatar asked Oct 06 '22 15:10

Samuel Poirier


2 Answers

Good news, I found out that yes. It all depends on the order that the registry rules are added to the object factory container. So if you are using multiple registry classes as I was doing, you need to find a way to give a priority to add them to the container.

In other words, instead of using the .LookForRegistries() which gets all the Registry classes in the wrong order, try to find all the Registry files, set them in the order you want and add them manually to the object factory container:

    ObjectFactory.Container.Configure(x => x.AddRegistry(registry));

That way, you have full control on what rules you want.

Hope it helps :)

like image 189
Samuel Poirier Avatar answered Oct 10 '22 02:10

Samuel Poirier


I just wanted to add my solution to the problem when I needed to override some parts of a registry in my SpecFlow test.

I did find this thread pretty early in my search, but it didn´t really help me find the solution, so I hope it will help you.

My problem was that the "DataContext" in "StoreRegistry" (used by the application) use the "HybridHttpOrThreadLocalScoped" and I needed it to be "Transient" in my tests.

The code looked like this:
[Binding]
public class MySpecFlowContext
{    
...
    [BeforeFeature]
    private static void InitializeObjectFactories()
    {
        ObjectFactory.Initialize(x =>
        {
            x.AddRegistry<StoreRegistry>();
            x.AddRegistry<CommonRegistry>();
        });
    }   
}

To override the scope setting you will need to explicitly set it in the registration. And the override needs to be below what is overridden

The working code looks like this:
[Binding]
public class MySpecFlowContext
{    
...
    [BeforeFeature]
    private static void InitializeObjectFactories()
    {
        ObjectFactory.Initialize(x =>
        {
            x.AddRegistry<StoreRegistry>();
            x.AddRegistry<CommonRegistry>();
            x.AddRegistry<RegistryOverrideForTest>();
        });
    }    

    class RegistryOverrideForTest : Registry
    {
        public RegistryOverrideForTest()
        {
             //NOTE: type of scope is needed when overriding the registered classes/interfaces, when leaving it empty the scope will be what was registered originally, f ex "HybridHttpOrThreadLocalScoped" in my case. 
            For<DataContext>()
                .Transient()
                .Use<DataContext>()
                .Ctor<string>("connection").Is(ConnectionBuilder.GetConnectionString());
        }
    }
}
like image 25
JimiSweden Avatar answered Oct 10 '22 01:10

JimiSweden