Registering Existing Object Instances
This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.
|The latest Unity Application Block information can be found at the Unity Application Block site.|
The Unity container exposes overloads of the following two methods that allow you to work with instances of existing objects:
- RegisterInstance. This method generates a registration within the container for an existing object. Optionally, you can specify a name for the mapping and specify how the container manages the lifetime of the object.
- BuildUp. This method takes an existing object and applies the dependency mechanism process to it on demand. Optionally, you can specify a name in the overloads of this method for extensions to use.
The RegisterInstance method provides a similar dependency feature to the RegisterType method (when used with the ContainerControlledLifetimeManager) in that it creates a registration that always returns a reference to the same instance of the specified object, as long as that object is in scope. The RegisterType method with a ContainerControlledLifetimeManager automatically generates this single instance the first time your code calls it, and the RegisterInstance method accepts an existing instance for which it will return references.
|You can use the RegisterInstance method to register simple types and more complex or custom types. For example, you can register String values such as database connection strings with the container and have them injected into your code as required.|
If you register a type more than once using the RegisterInstance method (in other words, if you register more than one instance of the same type), only the last one you register remains in the container and is returned when you execute the Resolve or ResolveAll method.
The RegisterInstance method overloads accept an additional parameter—the object instance to register—compared to the RegisterType method overloads, but the use of the registration type and an optional name are identical. The following example shows how you can use the RegisterInstance method to register existing instances of objects that implement the IMyService interface. This example uses both the generic and the non-generic overloads of the container methods.
DataService myDataService = new DataService(); EmailService myEmailService = new EmailService(); LoggingService myLoggingService = new LoggingService(); // Create container and register existing object instance IUnityContainer myContainer = new UnityContainer(); myContainer.RegisterInstance<IMyService>(myDataService); myContainer.RegisterInstance<IMyService>("Email", myEmailService); myContainer.RegisterInstance(typeof(IMyService), "Logging", myLoggingService); // Retrieve an instance of each type IMyService theDataService = myContainer.Resolve<IMyService>(); IMyService theEmailService = myContainer.Resolve<IMyService>("Email"); IMyService theLoggingService = (IMyService)myContainer.Resolve(typeof(IMyService), "Logging");
|By default, the RegisterInstance method registers existing object instances with a container-controlled lifetime and holds on to a strong reference to the object for the life of the container. You can change this behavior if you want by using a different lifetime manager to control the creation, lifetime, and disposal of the object. For more information, see Using Lifetime Managers. For information about how to create custom lifetime managers, see Creating Lifetime Managers.|
Guidelines When Using the RegisterInstance Method
The following are some general guidelines and issues to be aware of when using the RegisterInstance method:
- When you register an existing object, you can decide whether the container should take over lifetime management of the object. You do this by specifying the appropriate lifetime manager type:
- If you specify the ContainerControlledLifetimeManager type, or if you do not specify a lifetime type, the object continues to exist for the lifetime of the container. When the container is disposed, it calls the Dispose method of the object and allows it to be garbage collected. Therefore, you must ensure that your code does not maintain reference to the object.
- If you specify the ExternallyControlledLifetimeManager type, the object continues to exist only as long as you maintain a reference to it in your code. The container maintains only a weak reference to the object, allowing it to be disposed when no other code is holding a reference to it.
- If you specify the PerThreadLifetimeManager type, the object continues to exist for the lifetime of the current thread. The thread object is reclaimed by garbage collection when the thread is disposed, but note that the object is not disposed in the sense that the Dispose method is not invoked.
- When you use the RegisterInstance method to register an existing object, attribute-driven and constructor injection do not take place on that object because it has already been created outside of the influence of the Unity container. You can call the BuildUp method of the container and pass it the existing object to apply property (setter) and method call injection. However, constructor injection never takes place because the constructor does not execute.
- In general, you should never need to specify the same registered type in calls to the RegisterType and RegisterInstance methods. In other words, if you register a mapping for IMyObject using the RegisterType method, you should avoid using IMyObject as the registration type parameter of the RegisterInstance method. You are likely to get unexpected behavior because type mapping occurs before instances are resolved. The following example shows an invalid registration.
- When using the PerThreadLifetimeManager, it is recommended that you use RegisterType and do not use RegisterInstance to register an object. When you register an instance with the PerThreadLifetimeManager, the instance is registered only for the executing thread. Calls to Resolve on other threads result in per-thread singletons for container-built instances. If you request a type registered with the PerThreadLifetimeManager in any thread other than the thread it was registered for, the lifetime container for that object finds that there is no registered instance for that thread and, therefore, permits the container to build a new instance for that thread. The result is that for threads other than the one registering the instance, the behavior is the same as if you registered the lifetime container with RegisterType.
|Some objects, such as unmanaged components and other applications, may hold on to references to an object that you pass to the RegisterInstance method. In this case, you should use the ExternallyControlledLifetimeManager. However, you should always design your code so that disposable objects ever have only one "owner."|
By using the BuildUp method, you can apply the dependency injection process to an existing object on demand. The BuildUp method overloads accept the registration identifier as an interface or an object type, a reference to the existing object to process, and, optionally, a name for the object that container extensions can use.
The following example shows how you can use the BuildUp method to apply dependency injection to existing object instances named myDataService and myLoggingService, which implement the interface IMyService. This example uses both the generic and the non-generic overloads of the container methods.
IMyService myDataService = new DataService(); IMyService myLoggingService = new LoggingService(); IMyService builtupDataService = myContainer.BuildUp<IMyService>( myDataService); IMyService builtupLoggingService = (IMyService)myContainer.BuildUp(typeof(IMyService), myLoggingService);
If you have created or added extensions to the Unity container, these extensions can access and use a name that you specify when you execute the BuildUp method. This allows the extensions to change their behavior depending on the value you specify. For example, they may use the name to control how dependencies are resolved or to control features such as event wiring or interception. The actual behavior depends on the individual extension.
The following code shows how you can execute the BuildUp method and provide a name. It uses both the generic and the non-generic overloads of the container methods.
IMyService myDataService = new DataService(); IMyService myLoggingService = new LoggingService(); IMyService builtupDataService = myContainer.BuildUp<IMyService>(myDataService, "Data"); IMyService builtupLoggingService = (IMyService)myContainer.BuildUp(typeof(IMyService), myLoggingService, "Logging");