Storing a Reference to the Container
Typically, if you do not use constructor, property, or method call injection to resolve and populate all of your application dependencies during initialization, you will need to retain a reference to the container if you wish to access it directly to resolve objects. However, there are some other situations in which you may want to be able to reference the container after initialization. The following are some scenarios in which you may consider storing a reference to the container for use in your code:
- If you are using ASP.NET Web Forms or building a Web service. You must be able to resolve objects for each page or service request, and it is quite expensive in terms of resources and does not make sense to create the container and load the Enterprise Library configuration information or your own custom registrations every time. In this case, you will usually store the populated container in the ASP.NET Application dictionary or within your service implementation and use it to resolve instances as required for each request.
- If you are creating a console application or a component (rather than an application with a user interface or a Web service). If you are using Unity as your container, you can create the container and load the Enterprise Library container extension in your startup code and then use it to resolve the dependencies of other classes on demand using the Resolve method. Any dependencies defined in these classes will be populated automatically. You can hold it in a global variable throughout the life of the application. Note that disposing the container is not recommended.
- If you want to store registrations for your own objects within the container. You may choose to use a separate container for this, though you can just as easily make use of the default container that holds the Enterprise Library configuration registrations.
- If you want to be able to resolve instances of objects on demand rather that always having them resolved when a class is instantiated. For example, if an object is only required in certain cases (perhaps based on the run-time environment or some other factor), it may be useful to be able to call the methods that resolve instances from the container at run time instead of using constructor, property, or method call injection to create them when the class is initialized.
The following table will help you to understand when and where you should hold a reference to the container in forms-based and rich client applications built using technologies such as Windows Forms, Windows Presentation Foundation, and Silverlight.
Task |
When |
Where |
---|---|---|
Create and configure container. |
At application startup. |
Main routine, startup events, application definition file, or as appropriate for the technology. |
Obtain objects from the container. |
At application startup, and later if required. |
Where appropriate in the code. |
Store a reference to the container. |
At application startup. |
Global application state. |
Dispose the container. |
When the application shuts down. |
Where appropriate in the code or automatically when the application ends. |
The following table will help you to understand when and where you should hold a reference to the container in request-based applications built using technologies such as ASP.NET Web applications and Web services.
Task |
When |
Where |
---|---|---|
Create and configure container. |
At application startup. |
HTTP Module (ASP.NET and ASMX), InstanceContext extension (WCF). |
Obtain objects from the container. |
During each HTTP request. |
In the request start event or load event. Objects are disposed when the request ends. |
Store a reference to the container. |
At application startup. |
Global application state or service context. |
Dispose the container. |
When the application shuts down. |
Where appropriate in the code. |
Resolving an Entire Object Graph at Application Startup
The following schematic will help you to better understand how you can inject Enterprise Library objects, windows, forms, and custom classes you create into your application when it starts. The schematic shows the two main types of process: one for window or form-based application types such as Windows Forms and WPF; and one for request-based processes such as ASP.NET applications, ASMX Web services, and WCF Web services.
Both processes start by creating the container and loading the Enterprise Library configuration. For window or form-based application types, and for applications that maintain overall state such as console applications, you can resolve the main window, form, or class through the container. As long as the container can resolve all dependencies you define in the classes of your application, it will inject the resulting concrete instances into the relevant parameters and properties of these classes.
Note
This requires the container to include mappings for abstract classes and interfaces for your custom components (it cannot resolve these types without a mapping to a concrete type). In addition, if the container you are using cannot resolve concrete types that are not registered, you must add these registrations to the container in your startup code. Unity can resolve unregistered concrete types.
For request-based application types, you must capture each request and resolve the class that handles the request through the container to create the dependent types and populate the relevant dependencies. In other words, you build up the request instance through the container to resolve method and property dependencies because the instance is already created by the infrastructure. In ASP.NET, you can create an HTTP module that automates this process. In other types of request-based applications, you must resolve the class that creates the response yourself through the container.
Resolving and Injecting Objects on Demand
If you choose not to populate all of your application dependencies at application startup, you can use the container to resolve any of the Enterprise Library objects you want to use. You can also use it to resolve any of your own classes or other objects that have a public constructor (in other words, objects that you can create using the new operator) and for which there is a suitable registration in the container. When using the default Unity container, you can resolve concrete types without registering a mapping for that type in the container.
The following schematic shows an overview of the ways that you can use the container to generate instances of objects on demand. When you resolve an object through the container, it can resolve any dependencies within the object (such as constructor and method parameters and property values), and populate these with the resolved types. This means that you can, for example, have Enterprise Library objects such as a LogWriter or CacheManager automatically injected into your classes.
If you resolve the default instance of a type that is not registered when using Unity, the container will attempt to generate and return an instance of that type. However, the only time that this is really useful is when the object you are generating contains dependency attributes that the container will use to inject dependent objects into the requested object. In addition, if you are using an alternative dependency injection container, you may not be able to resolve types that are not registered.
Note
The Resolve and GetInstance methods are essentially entry points that allow a client to request an instance of a specific object. When the container starts handling that request, any and all dependencies are also resolved and injected. For each object that is resolved, the container selects a constructor and determines which parameters are needed to invoke it. For any of these parameters that need to be resolved, the container again selects a constructor and determines its parameters, continuing this process until no new objects need to be resolved. In some cases, depending on how they are registered in the container, the container might create a new instance or return a reference to an existing instance when it resolves each type.
More Information
For details of the ways in which you can implement the initialization process and store a reference to the container in different types of applications, see the following topics:
- Windows Forms and WPF Applications
- ASP.NET Web Forms Applications
- WCF and ASP.NET Web Service Applications
For information about creating instances of objects, see Creating and Referencing Enterprise Library Objects and Creating Application Block Objects.
For details of the three main scenarios for creating or injecting instances of objects, see the following topics:
- Injecting Resolved Types into Other Classes
- Resolving Instances of Types Using Unity
- Creating Application Block Objects Directly
For information about using the deprecated static facades in Enterprise Library, see the online documentation for Enterprise Library 4.1, available on the MSDN Web Site.
For information about the design of the dependency injection mechanism and container model, see The Dependency Injection Model.