Introduction to Munq IOC Container for ASP.NET

This is the first in a series of articles about using the Munq DI IOC Container and IOC containers in general.

Introduction

This is the first in a series of articles about using the Munq DI IOC Container and IOC containers in general.

Inversion of Control (IOC) is a pattern which decouples the use of an interface from the concrete implementation of that interface. By eliminating this coupling:

the code can be tested by using special test implementations of the interface.

fewer DLLs need to be deployed on each tier of a multi-tiered deployment.

project compilation may be sped up as there are fewer project dependencies.

alternate implementations of the interface can be configured for use without requiring changes to the main application code. This could mean changing from MSSQL to Oracle with a simple configuration file change.

An IOC Container is a pattern which allows the application to an instance of the interface without knowing the specific concrete class that will be used.

Munq DI IOC Container is the smallest, fastest IOC container that I know of. It is faster than any of the big players, Unity, Windsor Castle, Ninject, StructureMap, etc. See the graph below. Additionally, it has been designed for the web developer, with lifetime management that includes Request, Session, and Cached lifetime managers.

This article will provide you with a detailed understanding of the Munq IOC Container with:

a performance graph to grab your attention

API documentation

Additional articles will demonstrate the usage of the Munq DI IOC Container with real world examples including using Munq with ASP.NET MVC, a tour of the Munq code, and things to watch out for when using IOC Containers.

After downloading the code, I discovered a number of improvements which both simplified the code and significantly improved the performance. After several discussions, Kzu made me a contributor and several of my ideas and code were incorporated into the codebase.

Unfortunately, Kzu’s target for Funq was the mobile development space, while I am more involved in ASP.NET Webform and MVC application development. I didn’t need some of the features of Funq such as Container Hierarchies and Initializers, and I did need lifetime management to include web oriented styles including Request, Session, and Cached lifetime management. Thus Munq was conceived.

The goals for this development were:

Speed. High volume websites need to minimize the amount of work each page request needs to execute. Even 1/10th of a second can make a difference of a user’s perception of the site.

Simplicity. Munq does one thing, but does it well. It resolves requests for instances of Types by executing Factories that have been previously registered in the container.

Provide Web Lifetime Management. Windows applications can get by with a container that has the option of creating a new instance each request, or re-use the same instance. In the web application world, objects can have lifetimes that only span the current Request, the user’s Session, or be Cached reduce database load and access delays.

Creating the IOC Container

The container is usually created when the application first starts. In a web application, the container would typically be created in the Application_Start and stored in a field of the derived Application class or a static variable.

Container container = new Container();

Registering Type Factories

Registering the Type Factories associates a type to be resolved with a function that will return an instance of that type. This method is called when the container is asked to return an instance of the type.

Munq has four ways of registering type factory functions. These functions can be anything which has the correct signature and are not limited to delegates of the form

c=>new MyType()

but could be

c => CreateAndInitialzeMyType(c.Resolve<IOne>(), c.Resolve<ITwo>)

The first is using the type-safe generic Register methods. There are versions for both named and un-named registrations. Both take as a parameter, a delegate which takes a Container as its single parameter and returns an instance of the type.

The second is a set of methods which allows the factory method to be registered by passing the type of be resolved, and a delegate which takes a Container as its single parameter and returns an Object. There are versions for named and un-named registrations. These methods would typically be used if the registration information was read from an external store such as a database, XML file, or the web.config file.

The fourth is a set of methods which allows the factory method to be registered by passing the type of be resolved, and an object to be returned when the type is resolved. There are versions for named and un-named registrations. These methods would typically be used if the registration information was read from an external store such as a database, XML file, or the web.config file.

Getting an Instance from the Container

Once an interface and function have been registered in the container, the application can retrieve an instance by asking the container to resolve the interface to the concrete implementation that was registered. Munq has two forms of the Resolve method, a type-safe version using Generics, and a version that takes a Type as a parameter and returns an Object. Both versions have named and un-named overloads.

Lazy Resolution

There are situations where you may not wish to create the instance immediately. This may be because the instance uses a scarce resource or due to logic that may not require instantiation. For these cases, you can use the LazyResolve methods which returns a function that, when executed, performs the resolution and returns the instance.

Like the Resolve methods, the LazyResolve has two forms, a type-safe version using Generics, and a version that takes a Type as a parameter. Both versions have named and un-named overloads.

What is this IRegistration Thing?

You may have noticed that the Registration methods all return an object that implements the IRegistration interface. This interface allows the user to retrieve the internally generated ID for the registration and to specify the LifetimeManager to be used by the instance when it is resolved.

For example, if you need an IShoppingCart object to be stored in the users session, you would tell the registration to use the SessionLifetime manager:

Notice that this has been implemented in a fluent interface manner to allow changing of method calls. While there is currently only one method on this interface, any future methods will follow this pattern.

Specifying the Default Lifetime Manager

When the Container is first created, the default behaviour is to return a new instance for each Resolve method call. As shown above, this can be modified on a registration by registration basis. Additionally, you can specify which lifetime manager is to be used for any registration. For example, to always return the same instance for each call to Resolve, use the ContainerLifetime manager as shown below:

Available Lifetime Managers

Lifetime Managers allow you to modify the behaviour of the container as to how it resolves instances, and what is the lifetime of the instance. Munq has a set of Lifetime Managers designed for web applications. These are described below.

Warning: if you used the RegisterInstance method, then the same instance will be returned regardless of which lifetime manager is used.

AlwaysNewLifetime

This lifetime manager’s behaviour is to always return a new instance when the Resolve method is called by executing the factory method. This is the default behaviour.

ContainerLifetime

This lifetime manager’s behaviour is to always return the same instance when the Resolve method is called by executing the factory method.

SessionLifetime

This lifetime manager’s behaviour is to always return an attempt to retrieve the instance from Session when the Resolve method is called. If the instance does not exist in Session, a new instance is created by executing the factory method, and storing it in the Session.

RequestLifetime

This lifetime manager’s behaviour is to always return an attempt to retrieve the instance from Request.Items when the Resolve method is called. If the instance does not exist in Request.Items, a new instance is created by executing the factory method, and storing it in the Request.Items.

CachedLifetime

This lifetime manager’s behaviour is to always return an attempt to retrieve the instance from Cache when the Resolve method is called. If the instance does not exist in Cache, a new instance is created by executing the factory method, and storing it in the Cache.

Conclusion

I have given you a brief overview of the Munq DI IOC and its API. I will be following this with additional articles with examples of using Munq and dissecting the Munq code.

Share

About the Author

Matthew works on improving the performance and experience of the Code Project site for users, clients, and administrators.

Matthew has more years of software develeopment, QA and architecture experience under his belt than he likes to admit. He graduated from the University of Waterloo with a B.Sc. in Electrical Engineering. He started out developing micro-processor based hardware and software including compilers and operating systems.
His current focus is on .NET web development including jQuery, Webforms, MVC, AJAX, and patterns and practices for creating better websites.
He is the author of the Munq IOC, the fastest ASP.NET focused IOC Container.
His non-programming passions include golf, pool, curling, reading and building stuff for the house.

Thanks for reminding me that I haven't done a code release in a while. Since this article there have been a number of added features and minor bug fixes.
You can get the latest source at http://munq.codeplex.com/releases/view/77994[^]