DIC

DIC stands for Dependency Injection Container. Dependency Injection (DI) is a mean to realize an inversion of control, a common design pattern. But, as promised, lets use simple terms.

A real world example

As an autonomous work- or craftsman, how to acquire contracts? Would you burgle arbitrary houses in order to remodel, say, the occupant’s kitchen the way you would like it to be? Rather not! Most likely you will be contacted by occupants who want their kitchen to be remodeled or you may ask them whether they want it to be remodeled. Anyway, they will tell you how they want it to be remodeled. The only thing you have to know is how the customer’s remodeling is done by means of tools to be used as well as craftsmanship.

The principle

The customer is always right! As a service provider you will have to kindly ask her or him what she or he would like to be done. Only the particular customer can really tell you what she or he wants to be done (first-hand or reference information). Your key question is

“May I kindly ask you to provide me with your means (in terms of knowledge) I depend on in order to do my work?”

Understanding the virtual concept

For an easier understanding − for now − let’s disregard the “injection”. Instead, let’s add the concept of a container holding dependencies. This container is the only instance (in terms of a reference) that knows about the insights of the dependencies. So it’s recommended to use the dependency container as a dictionary that white-lists valid dependencies. From outside the container, you cannot change dependencies, but only request the same.

A graphical representation

The following images depict the sequence of a dependency request. First an authenticated request to a registered dependency.

Request a registered dependency

Request a registered dependency

If the requester is not authenticated or the dependency isn’t registered, nothing is returned.

Unauthenticated dependency request

Unauthenticated dependency request

Applied to our real world example, that means that there is no omnipotent craftsman who actively alters unasked customers’ facilities but the customers let the craftsman do the work they want him to do. So control is not with the one who does (the craftsman or provider) but with the one who lets him do (the customer or consumer). At least in the real world example, this may not appear as being an inversion of control, but in software it is as there typically powerful functions work on “defenseless” data.

As the container is a single reference to dependencies, it realizes a dictionary or registry implemented as a singleton that cannot be instantiated.

So what about “injection”?

Having learned that it’s just a detail that makes up an injection. If a class (our craftsman) is implicitly provided with its dependencies (typically by means of its construct), these dependencies are referred to as being “injected” into the class.

Dependencies

After having mentioned this concept a couple of times, it may not be transparent what dependencies might be. Generally spoken dependencies are any kind of resources a requester might depend on.

Examples
  • Language modules
  • Configuration settings
  • White-lists
  • Data descriptions
  • Database connections
  • Session objects

Container variants

Dictionary

The container might be implemented as a read-only dictionary that white-lists valid dependencies.

Registry

An extended variant is to offer a registration interface in order to register dependencies to the central registry.

Advantages

Security

The inversion of control inhibits undesired results and thus behavior as a requester cannot alter the container’s internal logic. This is especially true when being used in typical web application environments where the container is a plain back-end implementation unreachable by the front-end (by different run-time environments and encapsulation).

Clarity, trust and maintainability

The container’s nature as a singleton makes it the only source of truth for dependencies, so a dependency is either always wrong or always right regardless of the requester. Maintaining or changing a dependency effects all its requesters at once.

Possible disadvantages

Design effort

When designing your own DI container, working out a maintainable and effective design may be expensive.

Implementation effort

Implementing your own DI container of course bears the respective effort.

No golden hammer

Using a DIC will mainly increase the maintainability of your code in terms of refraining you from bypassing your design, but it won’t necessarily refrain others (like an attacker) from doing so (e.g. by injecting SQL etc.).

Pseudo code example

Following a code snipset using a pseudo code to demonstrate an implementation approach.

Pseudo code

// Singleton (final) and static class Dependency Injection Container (DIC)
final static class DIC
{
    // The construct defines and initializes the properties
    construct()
    {
	// A public property that allows passing the application context
	public strCurrentApplication = NULL;
 
	// Private properties holding white-lists and configuration switches
	private arrRegisteredApplications = [ “app1”, “app2”, “app3”, … ];
	private boolUseI18nModule = FALSE;
	private objDatabaseConnection = NULL;
	…
    }
 
    // Always check if set application is white-listed
    CheckIfRegisteredApplication()
    {
        if ( !in_array( self::strCurrentApplication, self::arrRegisteredApplications ) )
        {
            throw Exception( “Unregistered application!” );
        }
 
        // If application is white-listed, load its configuration
        LoadApplicationConfiguration( self::strCurrentApplication )
    }
 
    // Load application configuration
    // Application configuration parameters may be defined statically or
    // loaded from external configurations (files or DB)
    LoadApplicationConfiguration()
    {
        // Set (or override default values of)
        // configuration switches and object references
        self::boolUseI18nModule = 
        self::objDatabaseConnection = 
        ...
    }
 
    // Finally, an interface returning a reference to the database connection
    ConnectDatabase()
    {
        if ( CheckIfRegisteredApplication )
        {
            return self::objDatabaseConnection;
        }
 
        catch Exception;
    }
}
 
// Usage example of the previously defined DIC to get a reference
// to the database connection of app1
 
// Set valid application context
DIC::strCurrentApplication = “app1”;
objDatabaseConnection = DIC::ConnectDatabase();
// objDatabaseConnection now contains a DB connection of app1
// without having seen its credentials (as the DIC is the only source of trust)

By using this structure, you can put any dependency into your container and easily request the same.

Most of this explanation is also available as a presentation.

Leave a comment

0 Comments.

Leave a Reply

( Ctrl + Enter )