39

I meet one problem that i can't solve now. I have the following:

UnityHelper.DefaultContainer.RegisterInstance(typeof(IMyInterface), "test", instance);

where UnityHelper.DefaultContainer is my helper for getting unity container with loaded configuration.

here I registered instance as an instance of IMyInterface.

So anywhere( some time after using) I want to remove this mapping. Remove it at all. How I can do it?

I have tried:

UnityHelper.DefaultContainer.Teardown(instance)

but is was unsuccessful and the following code returns instance anyway:

UnityHelper.DefaultContainer.ResolveAll<IMyInterface>()
Sagar Zala
  • 4,854
  • 9
  • 34
  • 62
bug0r
  • 613
  • 1
  • 8
  • 19
  • Interesting. Why do you need this by the way? – Yauheni Sivukha Apr 24 '10 at 17:25
  • I use mocked instances in tests and want to clear environment for next test. Currently instances from previous test is in container and appear when I call ResolveAll(). – bug0r Apr 24 '10 at 17:38
  • In the commmon scenario developer can change implementation on the fly. – bug0r Apr 24 '10 at 17:39
  • 3
    Usually I create separate container for each test. This avoids such problems... Regarding changing on the fly - This will cause trouble with concurency - be carefull. I think that implementation can be changen by registering another instance whith the same name (but i not sure). – Yauheni Sivukha Apr 24 '10 at 18:28
  • yes about registering, but it will not remove it from "list of all" it is possible to create a special empty implementation to emulate delete, but I don't like this way. Creating separate container is good but container is created in code I want to test. – bug0r Apr 24 '10 at 20:17

6 Answers6

29

I had the same problem and just removed the registrations of the ContainerControlledLifetimeManager from my Container:

foreach (var registration in container.Registrations
    .Where(p => p.RegisteredType == typeof(object)
                && p.Name == name
                && p.LifetimeManager.Type == typeof(ContainerControlledLifetimeManager)))
{
    registration.LifetimeManager.RemoveValue();
}
Glaerferyn
  • 161
  • 7
Johannes Wanzek
  • 2,825
  • 2
  • 29
  • 47
12

This is an old question, but some answers are misleading, so I will provide my own. You can´t do that with Unity. End of the story. Calling RemoveValue on registrations lifetime managers does not achieve unregistration (more information about lifetime managers), and that method is not intended to unregister anything. So the final behaviour is unexpected and not convenient. Of course, RemoveValue makes even less sense if you register an implementation or a factory method, although the question is about unregistering instances. Consider the next piece of code

    public interface SomeInterface
    {
        int Foo { get; set; }
    }

    public class SomeImplementation: SomeInterface
    {
        public int Foo { get; set; }
    }

    static void Main(string[] args)
    {
        UnityContainer iocContainer = new UnityContainer();
        string registerName = "instance";
        //before any registration
        Resolve<SomeInterface>(iocContainer, registerName);

        iocContainer.RegisterInstance<SomeInterface>(registerName, new SomeImplementation());

        //after registration
        Resolve<SomeInterface>(iocContainer, registerName);

        ClearValue<SomeInterface>(iocContainer, registerName);

        //after clear value
        Resolve<SomeInterface>(iocContainer, registerName);


    }

    private static void Resolve<T>(UnityContainer iocContainer,string name)
    {
        if (iocContainer.IsRegistered<T>(name))
            iocContainer.Resolve<T>(name);

        iocContainer.ResolveAll<T>();
    }
    private static void ClearValue<T>(UnityContainer iocContainer, string name)
    {
        foreach (var registration in iocContainer.Registrations.Where(p => p.RegisteredType == typeof(T)
            && p.Name==name))
        {
            registration.LifetimeManager.RemoveValue();
        }
    }

If you debug it, you will see that after the call to ClearValue, the container still says it is registered, but if you try to resolve that instance it will throw an exception. What is even worse, calls to ResolveAll<T> will fail too.

To Sum up, no matter if you do ClearValue, wrap around your register instance with another IoC or a custom class, or provide your own LifeTimeManager, ResolveAll<T> and IsRegistered<T> won´t behave as expected, and the registration will still be there. So don't try it because it won´t work and it will cause problems down the road.

Monticola Explorator
  • 1,188
  • 13
  • 20
  • 1
    I'd like to add that I have made "unregistering" the instance that way (above) and I had ResolutionFailedException thrown while trying to ResolveAll or Resolve single instance with given name. Exception message was "Resolution of the dependency failed,occurred while: while resolving.\nException is: InvalidOperationException - Value of ContainerControlledLifetimeManager can only be set once". – Jacob Oct 03 '18 at 12:55
11

I think that is what you are looking for.

var lifetimeManager = new TransientLifetimeManager();
UnityHelper.DefaultContainer.RegisterInstance(typeof(IMyInterface), "test", instance, lifetimeManager);
lifetimeManager.RemoveValue();
er-v
  • 4,405
  • 3
  • 30
  • 37
  • 1
    No. it is not. Exception raises when second time resolving run. – bug0r Apr 27 '10 at 15:41
  • yes, it should. Something about that interface can not be constructed. That is becouse lifetimeManager.RemoveValue() - removes registration from Unity. The same exception come if you don't register type at all. I thought than this what you wanted. Isn't it? – er-v Apr 27 '10 at 15:49
  • Resolution of the dependency failed, type = "IMyInterface", name = "test". Exception message is: The current build operation (build key Build Key[IMyInterface, test]) failed: The current type, IMyInterface, is an interface and cannot be constructed. Are you missing a type mapping? (Strategy type BuildPlanStrategy, index 3) when resolving – bug0r Apr 27 '10 at 15:50
  • All resolves should go before lifetimeManager.RemoveValue() call – er-v Apr 27 '10 at 15:52
  • Ok, but what behaviour do you expect for unregistered type? – er-v Apr 27 '10 at 15:53
  • You should check registration with IsRegistered method before Resolving. – er-v Apr 27 '10 at 15:58
  • the order was: RegisterInstance(...., lifetimeManager); .... ResolveAll() -> exception ..... lifetimeManager.RemoveValue(); – bug0r Apr 27 '10 at 16:03
  • looks like removeValue() and even lifetimemanager.Dispose() does not remove mapping from registeredNames to resolving type. Other words removing values I leave name mapping exist inside container, that cause exception when resolving. Before for TransientLifetimeManager and after for ContainerControlledLifetimeManager. – bug0r Apr 27 '10 at 16:10
8

Here is how I handled unregistering instances from a unity container

I needed to implement Add/Remove functionality like this:

public interface IObjectBuilder
{
    void AddInstance<T>(T instance);
    void RemoveInstance<T>(T instance);
}

I created a custom lifetime manager to do the implementation

public class ExplicitLifetimeManager :
    LifetimeManager
{
    object Value;

    public override object GetValue()
    {
        return Value;
    }

    public override void SetValue(object newValue)
    {
        Value = newValue;
    }

    public override void RemoveValue()
    {
        Value = null;
    }
}

Here is the final implementation:

    Dictionary<object, ExplicitLifetimeManager> Instances = new Dictionary<object, ExplicitLifetimeManager>();

    public void AddInstance<T>(T instance)
    {
        ExplicitLifetimeManager e = new ExplicitLifetimeManager();
        Instances[instance] = e;
        Container.RegisterInstance(instance, e);
    }

    public void RemoveInstance<T>(T instance)
    {
        Instances[instance].RemoveValue();
        Instances.Remove(instance);
    }

calling removevalue on the custom lifetime manager causes the instance to be unregistered

Brad
  • 705
  • 7
  • 17
2

I have the same challenge and after experimenting I solved it by using the standard ContainerControlledLifetimeManager and calling RemoveValue when I want to remove the container instance. Note that if you are not using interfaces and your object has constructor which the container can find and use it will recreate the instance after you have destroyed it with lifetimeManager.RemoveValue().

[TestClass]
public class UnityContainerTest
{
    [TestMethod]
    public void RemoveFromContainer()
    {
        UnityContainer container = new UnityContainer();
        MyUnityMember member = new MyUnityMember(5);

        LifetimeManager lifetimeManager = new ContainerControlledLifetimeManager();
        container.RegisterInstance(member, lifetimeManager);

        var resolved = container.Resolve<MyUnityMember>();
        Assert.IsNotNull(resolved);

        lifetimeManager.RemoveValue();

        try
        {
            resolved = container.Resolve<MyUnityMember>();
            Assert.Fail(resolved + " is still in the container");
        }
        catch (ResolutionFailedException)
        {
        }
    }

    public class MyUnityMember
    {
        public MyUnityMember(int x)
        {
            I = x;
        }

        public int I { get; private set; }
    }
}
Velimir
  • 684
  • 7
  • 7
1

I had a similar requirement whereby I wanted to temporarily store objects in the unity container and found this was not possible (or at least easily possible). If your objective is to have a temporary storage place easily available to unity, then create a temporary storage service.

public class TemporaryStorageService : ITemporaryStorageService
{
    public void Deposit<T>(Object o, string key)
    {
        System.Windows.Application.Current.Properties[key] = o;
    }

    public T Withdraw<T>(string key)
    {   T o = (T)System.Windows.Application.Current.Properties[key];
        System.Windows.Application.Current.Properties.Remove(key);
        return o;
    }
}

Register your service with Unity. Then when you wish to store an object you call the Deposit Method and when you wish to remove the object you call the Withdraw method. A fuller explanation can be found here

Allan
  • 449
  • 5
  • 11