Sunteți pe pagina 1din 20

9/2/13

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

Understanding Dependency Injection and Those Pesky Containers


We seem to be an industry enamored with buzz words. Even though XmlHttpRequest has been around since the mid-90s, mainstream programmers didnt give it a second thought until someone attached the term AJAX to it. The same is true for the never-ending quest to put as many different words as we can in front of drivendevelopment. Another term that hit the scene in recent years is dependency injection. Bringing form to concepts that had been around for a while, dependency injection (also known as DI) didnt kick into full force until Martin Fowler wrote his famous article in 2004. The development community grabbed onto the term and ran with it as the next big thing we should all be doing, which is great - except for the fact that DI seemed to be only a small part of what the community as a whole was doing. DI is an approach to providing one type with instances of the other types on which it may depend, all while keeping the types decoupled from one-another through the use of interfaces. Though defined in Wikipedia as an approach to testing computer programs, its more than just testing. That said, testing is an extremely good and important reason to use DI, because with it, you can write decoupled components, making it an integral part of good software testing. DI is a form of Inversion of Control and is sometimes confused as being the exact same thing. (Inversion of Control is a software principle whereas control of a class initialization and execution is delegated to another class, sometimes a container or a manager.) DI is a slight subset of Inversion of Control. Before digging into how implementations of DI work and how to use the DI Container, you need to understand the concept of coupled and decoupled software; the former being bad and the latter being the good that becomes even better with DI.

By: Miguel Castro


Migue l is an archite ct with IDe sign who spe cialize s in archite cture consulting and building .NET solutions. He is a Microsoft MVP and INETA spe ak e r and has be e n a software de ve lope r for ove r 22 ye ars. W ith a Microsoft back ground that goe s all the way back to VB 1.0 (and Q uick Basic in fact), Migue l jum pe d on .NET as soon as the first public Be ta was re le ase d and has provide d .NET solutions for clie nts around the country in a varie ty of industrie s. He conside rs him se lf to be a .NET De ve lope r and Archite ct and has e qual love for both VB and C #, and no tole rance for language bigotry. He s spok e n at num e rous use r groups around the country as we ll as de ve lope r confe re nce s. He s the author of the C ode Bre e ze code -ge ne rator, which am ong things can be found on his W e b site : www.ste e lblue solutions.com Migue l curre ntly live s in Lincoln Park , NJ with his wife Ele na and his daughte r Victoria. subscriptions@infote k cg.com

Software Coupling
When writing software, its always a good idea to separate the concerns of the types involved. Separation of concerns means that each type has either only one, or a very small set of responsibilities. Of course, if you translate your software to the line of business for which its built, it immediately becomes apparent that a business process involves many steps and therefore many types. Most of the time, there is a need for one type to work hand-in-hand with another and perhaps become a sub-part of another. In other words, one class may depend on another. In fact, the parent type would very likely contain an instance of the type on which it depends, usually passed in through a constructor or a property. The problem is that this creates a coupling between the two types. Not only can the parent type not exist (or compile) without the dependent type, it can be stuck with the way that type wants to do things. Ill show you what I mean with an example of what not-to-do, and then Ill show you techniques for solving the problem. A Coupled Example Lets take a look at a great example of a business process that can be subdivided easily: e-commerce. Among other things, three of the functions that are involved in a check-out process are:
www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true

DI in .NET 1.1
Normally, I would consider this a dead product, but recently I had a team of South American developers approach me after a conference talk and mention that they have an old system written in .NET 1.1. They still

1/20

9/2/13

functions that are involved in a check-out process are: payment processing customer update notification

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

After an order is placed, a customers credit card must be charged, after which the customer record needs to be updated with the order he/she placed and the product purchased. Lastly, the customer should receive an email with their receipt and order summary. An additional less critical process can be logging, which can take place at every step for internal auditing purposes. Lets start with a type that will contain the data involved in the example. This type is called OrderInfo and can be seen in Listing 1. To act upon this data, theres a type called Commerce with a method called ProcessOrder, which performs all the aforementioned subprocesses. In the interest of separating the concerns, I have created types called BillingProcessor, Customer, Notifier, and Logger. Each of them might be used from another class in another situation, but its also a good idea not to put everything in the Commerce type to encapsulate the check-out process. The four classes are shown in Listing 2. Notice that in the interest of simplicity, their methods have no real functionality. If they did, it would be complex and involve several resources, such as a database, the file system, or additional APIs like an email sender and a payment gateway. Also note that each of the methods of the four classes act upon different pieces of the OrderInfo type. The Commerce type incorporates each of the other four types by receiving an instance of each in its constructor. Think of this as an orchestrator or manager class. You can see this one in Listing 3. Assuming that you have an instance of OrderInfo with the necessary data, using the Commerce type can involve something like this: C o m m e r c ec o m m e r c e=n e wC o m m e r c e ( N e wB i l l i n g P r o c e s s o r ( ) , N e wC u s t o m e r ( ) , N e wN o t i f i e r ( ) , N e wL o g g e r ( ) ) ; c o m m e r c e . P r o c e s s O r d e r ( o r d e r I n f o ) ; The problem here is two-fold. First, the Commerce type is completely and utterly coupled to the other four types. Not only can it not work without them, but its totally locked into the implementation that each provides. What if the system youre writing changes payment gateways in the future? If your application were written like the example snippet above, you would have to rewrite the entire BillingProcessor class, only to rewrite it again later. Of course you can have two different classes, but that would mean changing the code in the Commerce class in order to alter which new or different types gets received. The second problem is that the Commerce class is difficult to test. Eventually you will have to test the production functionality of the four classes that house the sub-processes, but what if you want to test the ProcessOrder method of the Commerce class to see how it handles the combination of the four processes without having to deal with the resource access that those processes might undertake? Writing a unit test for this method means having to bring in all four of the other types and whatever resource access was written into them.

.NET 1.1. They still support and enhance this system but for corporate policy reasons, cannot upgrade it beyond 1.1. Interested in introducing DI to it, they asked me what their options are. To the best of my knowledge, none of the DI containers mentioned in this article support .NET 1.1 because of their use of generics and/or lambda expressions. The makeshift container I wrote for this article can be easily modified to favor typeof statements over generics. Though nowhere as feature-rich as any of the other containers, it can certainly fulfill the basic DI requirements of .NET 1.1 applications.

DI and Unit Testing


Although some may argue that DI is all about unit testing, its actually about writing decoupled software. Thats what I wanted the focus of this article to be and thats why I didnt get deeply into the practice of unit testing or TDD. Using a DI container to assist you in developing components which depend on interfaces rather than classes allows you to test those components with test implementations of their dependencies, dependencies which can otherwise involve more complex resources, such as databases. Its not the DI container that assists you in testing; its the practices on which you are forced to focus when involving a
2/20

"

coupled = bad

"

www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true

9/2/13

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

This is coupled behavior, and remember coupled = bad. But I didnt spend all that time writing code only to tell you not to do it this way. Im going to make adjustments to the code above in order to decouple my components and make everything more extensible and testable. A Decoupled Example The first step to decoupling application components is to abstract out the implementation from the definition in the four process classes. This way, you can provide a production implementation and test implementation later. So the first thing to do is refactor the definition of the classes out to four interfaces, as shown in Listing 4. Then youll modify the four process classes to implement their appropriate interface. In the interest of space, only the BillingProcessor class is included in this code snippet, but this same pattern applies to the other three process classes. P u b l i cc l a s sB i l l i n g P r o c e s s o r:I B i l l i n g P r o c e s s o r { V o i dI B i l l i n g P r o c e s s o r . P r o c e s s P a y m e n t ( S t r i n gc u s t o m e r , S t r i n gc r e d i t C a r d , D o u b l ep r i c e ) { / /P e r f o r mb i l l i n gg a t e w a yp r o c e s s i n g } } You can now write as many different billing processors as you want, each providing a different implementation of the interface. The key now is to modify the Commerce class so that it receives injections by way of the interfaces and not the concrete types as before. The rewrite of the Commerce class is in Listing 5. Ive provided the entire class again so you can see that the only thing that has changed is the type of the constructor arguments and the class fields. The method calls in the ProcessOrder method are exactly the same. The Commerce class makes these method calls and leaves their actual function to whatever the implementation classes are that were sent through the constructor. The Commerce types dependencies were injected through the constructor without being coupled to the Commerce type. The only coupling that took place is through the interfaces and they act as plumbing. This is good coupling. This light coupling is DI in its simplest form. The components have been decoupled from one another and through the use of interfaces, the application can grow and change in the future and components can be swapped if and when necessary. In fact, in the context of Visual Studio projects, the Commerce class can sit in one assembly (possibly the main application), the process classes in another (or even four different ones), and both sides share a third assembly containing the interfaces. If you were to write a unit test against the Commerce class ProcessOrder method, you would no longer need the production instances of the four process classes, and certainly not even a reference to the assembly in which they live. You can write test versions that implement the interfaces in a totally different way, perhaps doing nothing at all except providing a dummy return value when one is expected. In fact, ideally, you wouldnt need to write test implementations at all but can use a mocking framework to create them on-the-fly within the unit test itself. The one thing that hasnt changed with this refactoring is the fact that whatever called the Commerce class still needs to instantiate the four process classes in order to inject them into the instance of Commerce. This is where a DI container will come in handy.

focus when involving a DI container that does so. Testing is an important and involved topic and I felt it would digress from the core intent of this article.

MEF 2
I believe MEF to be a first-class citizen in the world of DI and that belief is solidified further with MEF 2. In addition to providing better debugging capability for composition errors (a headache for many MEF users), MEF 2 adds some great registration features with a new RegistrationBuilder class. The class exposes an awesome fluent API that lets you export types using various techniques without the need to use attribute decorations. Among these are direct replacements for the existing attributes as well as some very cool new techniques, such as exporting types that contain a certain property. MEF 2 Preview is currently in its fifth iteration and can be obtained from http://mef.codeplex.com/releases/view/79090. You can also find a good Code-Project article at http://www.codeproject.com/Articles/366583/MEF2-Preview-BeginnersGuide thats worth checking out.

Dependency Injection Containers


www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true 3/20

9/2/13

Dependency Injection Containers

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

DI containers are about two things, R&R. No, not rest and relaxation. Im talking about registration and resolving. These are the acts of storing a list of types and later retrieving instances of them at will. containers are about two things, " DIR&R (registration and resolving)

"

The DI container is the tool that turns DI into architectural patterns that lets you satisfy a types dependencies easily and automatically. It is a repository that typically associates interfaces with concrete types. How a DI Container Works DI containers all work in a very similar fashion. At the beginning of an applications execution-cycle, you need to register associations of concrete types to the interfaces that they implement. What makes containers different from one another is the way registration functionality is exposed. Later, when an instance of an interface implementation is requested, the container can offer an instance of the appropriate concrete type, called resolving. What makes the process of the instance assignment special is that it happens recursively, as many times as necessary. At the start of an app, you might register 20 types with 20 interfaces. When you request a type from the container by specifying an interface, not only do you get an instance of the associated type, but the container offers a bit more. The container looks at either the constructor arguments or the public properties and determines whether they are interface types. If they are interface types, it attempts to resolve them as w ell and set the argument or property value to the instance it resolved. The container then repeats the process for each of the resolved types as well. By the time it returns the type you requested, it has all its dependencies with it, and their dependencies, and so on down the line. Because essentially all containers work this way, theres no better way to fully understand what goes on behind the scene than to see the code of a very simple DI container. Any container you use later, no matter how complex it may seem, is essentially a variation of what Ill show you here. Because you need to store associations of interfaces to concrete types, start by writing a simple class to represent this association: P u b l i cc l a s sC o n t a i n e r I t e m { P u b l i cT y p eA b s t r a c t i o n T y p e{g e t ;s e t ;} P u b l i cT y p eC o n c r e t e T y p e{g e t ;s e t ;} } Now its a matter of writing a class that will serve as the container and expose an API for adding instances of ContainerItem types. Listing 6 shows the container class. As you can see, all the code does is expose a method called Register, which will let you store an association of an interface to a concrete type. Each association is stored in the container list, _Registrations. Now you just need to expose another method that will let you ask for whatever type is associated to a given interface. Call this method CreateType. P u b l i cTC r e a t e T y p e < T > ( )w h e r eT:c l a s s { O b j e c ti n s t a n c e=n u l l ; T y p et y p e=t y p e o f ( T ) ;
www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true 4/20

9/2/13

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

C o n t a i n e r I t e mc o n t a i n e r I t e m= _ R e g i s t r a t i o n s . W h e r e ( i t e m= > i t e m . A b s t r a c t i o n T y p e . E q u a l s ( t y p e ) ) . F i r s t O r D e f a u l t ( ) ; I f( c o n t a i n e r I t e m! =n u l l ) I n s t a n c e=A c t i v a t o r . C r e a t e I n s t a n c e ( C o n t a i n e r I t e m . C o n c r e t e T y p e ) ; R e t u r ni n s t a n c e ; } This simple version of the CreateType method looks for an item in the registration list where the AbstractionType property is equal to the type requested in the generic argument. If it finds an entry, it takes the ConcreteType property and creates an instance of it to return. Where a DI container provides its real value is in the recursive walk it takes through the properties and/or constructor arguments of the types it resolves, in order to further resolve its dependencies. Modify the CreateType method to do just that. You also need to return an instance of the requested type if it isnt an interface. This way, the CreateType method can be used to instantiate a type that might not have been registered earlier, but still walk through it to resolve its dependencies. Listing 7 shows the modified CreateType method. It doesnt take a lot of code to take the type that is found in the list, go through the arguments of its constructor and if they are of an interface type, attempt to resolve them. You continue to do the same for those types, and so on until the type initially requested is returned. In order to use this simple container, modify the e-commerce code snippet I wrote back in the A Coupled Example section. The Commerce class will remain exactly the same, as will the interfaces and the four processes. Only the client must change. C o n t a i n e rc o n t a i n e r=n e wC o n t a i n e r ( ) ; c o n t a i n e r . R e g i s t e r < I B i l l i n g P r o c e s s o r , B i l l i n g P r o c e s s o r > ( ) ; c o n t a i n e r . R e g i s t e r < I C u s t o m e r ,C u s t o m e r > ( ) ; c o n t a i n e r . R e g i s t e r < I N o t i f i e r ,N o t i f i e r > ( ) ; c o n t a i n e r . R e g i s t e r < I L o g g e r ,L o g g e r > ( ) ; O r d e r I n f oo r d e r I n f o=n e wO r d e r I n f o ( ) { C u s t o m e r N a m e=" M i g u e lC a s t r o " , E m a i l=" m i g u e l @ d o t n e t d u d e . c o m " , P r o d u c t=" L a p t o p " , P r i c e=1 2 0 0 , C r e d i t C a r d=" 1 2 3 4 5 6 7 8 9 0 " } ; C o m m e r c ec o m m e r c e= c o n t a i n e r . C r e a t e T y p e < C o m m e r c e > ( ) ;

c o m m e r c e . P r o c e s s O r d e r ( o r d e r I n f o ) ; Keep in mind that in a real application, the registrations occur at startup and container is saved in a way that it can be accessed from anywhere. If any of the registered types were to also have interfacebased constructor arguments, they would be resolved also, provided those interfaces were registered in the container. Any container you decide to use works in a very similar fashion to what Ive just demonstrated. There are many DI containers for you to choose from, according to your needs.
www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true

A Quick Tour Though Some Popular DI Containers

5/20

9/2/13

A Quick Tour Though Some Popular DI Containers

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

Although this article is not a tutorial on all the available DI containers out there, its worth talking briefly about a few of them and showing some simple examples. Unity is Microsofts answer to the call for DI containers. It works very similar fashion to the make-shift container you looked at in article. In fact, the only difference youll note is the name of container type and the names of the methods used to register resolve. Heres the same container-usage example I used earlier, using Microsoft Unity instead: U n i t y C o n t a i n e rc o n t a i n e r=n e wU n i t y C o n t a i n e r ( ) ; c o n t a i n e r . R e g i s t e r T y p e < I B i l l i n g P r o c e s s o r , B i l l i n g P r o c e s s o r > ( ) ; c o n t a i n e r . R e g i s t e r T y p e < I C u s t o m e r ,C u s t o m e r > ( ) ; c o n t a i n e r . R e g i s t e r T y p e < I N o t i f i e r ,N o t i f i e r > ( ) ; c o n t a i n e r . R e g i s t e r T y p e < I L o g g e r ,L o g g e r > ( ) ; O r d e r I n f oo r d e r I n f o=n e wO r d e r I n f o ( ) { C u s t o m e r N a m e=" M i g u e lC a s t r o " , E m a i l=" m i g u e l @ d o t n e t d u d e . c o m " , P r o d u c t=" L a p t o p " , P r i c e=1 2 0 0 , C r e d i t C a r d=" 1 2 3 4 5 6 7 8 9 0 " } ; C o m m e r c ec o m m e r c e= c o n t a i n e r . R e s o l v e < C o m m e r c e > ( ) ; c o m m e r c e . P r o c e s s O r d e r ( o r d e r I n f o ) ; Other popular containers include Castle Windsor, MEF, NInject, StructureMap, and Spring.NET. Each offers slightly different features than the others, but they all offer a way to register types and to resolve them and their dependencies. To keep the article short, and because they are very similar, details of these other containers wont be covered here. The difference in usage scenarios is purely syntactical and there are plenty of resources available online to show you how to use them. I will demonstrate an example using one of them: Castle Windsor. Heres Castle Windsor. In the interest of space, Ill leave out the creation of the OrderInfo class: W i n d s o r C o n t a i n e rc o n t a i n e r=n e w W i n d s o r C o n t a i n e r ( ) ; c o n t a i n e r . R e g i s t e r ( C o m p o n e n t . F o r < C o m m e r c e > ( ) ) ; c o n t a i n e r . R e g i s t e r ( C o m p o n e n t . F o r < I B i l l i n g P r o c e s s o r > ( ) . I m p l e m e n t e d B y < B i l l i n g P r o c e s s o r > ( ) ) ; c o n t a i n e r . R e g i s t e r ( C o m p o n e n t . F o r < I C u s t o m e r > ( ) . I m p l e m e n t e d B y < C u s t o m e r > ( ) ) ; c o n t a i n e r . R e g i s t e r ( C o m p o n e n t . F o r < I N o t i f i e r > ( ) . I m p l e m e n t e d B y < N o t i f i e r > ( ) ) ; c o n t a i n e r . R e g i s t e r ( C o m p o n e n t . F o r < I L o g g e r > ( ) . I m p l e m e n t e d B y < L o g g e r > ( ) ) ; C o m m e r c ec o m m e r c e= c o n t a i n e r . R e s o l v e < C o m m e r c e > ( ) ; c o m m e r c e . P r o c e s s O r d e r ( o r d e r I n f o ) ; As you can see, the process is the same, although the API exposed by Castle Windsor is very different from that of Unity. Notice that when using this container, any class to be resolved needs first to be registered, including the Commerce class, and notice that this class in a this the and but

www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true

6/20

9/2/13

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

registered, including the Commerce class, and notice that this class is registered on its own and not associated to any interface. Lets look at one more by seeing what the syntax for NInject looks like: I K e r n e lc o n t a i n e r=n e wS t a n d a r d K e r n e l ( ) ; c o n t a i n e r . B i n d < I B i l l i n g P r o c e s s o r > ( ) . T o < B i l l i n g P r o c e s s o r > ( ) ; c o n t a i n e r . B i n d < I C u s t o m e r > ( ) . T o < C u s t o m e r > ( ) ; c o n t a i n e r . B i n d < I N o t i f i e r > ( ) . T o < N o t i f i e r > ( ) ; c o n t a i n e r . B i n d < I L o g g e r > ( ) . T o < L o g g e r > ( ) ; C o m m e r c ec o m m e r c e=c o n t a i n e r . G e t < C o m m e r c e > ( ) ; c o m m e r c e . P r o c e s s O r d e r ( o r d e r I n f o ) ; Microsoft provides another container called the Managed Extensibility Framework, or MEF. Although many will argue that MEF is not really a DI container, including Microsoft themselves, it does provide the ability to serve as one; and quite well. MEF provides the ability to develop plug-ins and extensible applications in a simple and consistent manner. It provides a container class that stores registrations as well as the ability to resolve types and dependencies: the essence of a DI container. What makes MEF very unique is its ability to discover types instead of forcing you to list registrations through code at application startup. MEF lets you decorate types to be registered and associate them with an interface in that decoration. It can then go out and discover said types by building a catalog, which it can do in a number of ways. Lets take a look at how types are registered in MEF: [ E x p o r t ( t y p e o f ( I B i l l i n g P r o c e s s o r ) ) ] [ P a r t C r e a t i o n P o l i c y ( C r e a t i o n P o l i c y . N o n S h a r e d ) ] p u b l i cc l a s sT e s t B i l l i n g P r o c e s s o r :I B i l l i n g P r o c e s s o r { v o i dI B i l l i n g P r o c e s s o r . P r o c e s s P a y m e n t ( s t r i n gc u s t o m e r ,s t r i n gc r e d i t C a r d , d o u b l ep r i c e ) { / /p e r f o r mb i l l i n gg a t e w a yp r o c e s s i n g } } A class dependencies, as in the case of the Commerce class, need to be marked in MEF. This can be done with either the ImportingConstructor attribute for constructor injection, or with the Import attribute for property injection. The MEF version of the Commerce class is in Listing 8. Note that the Commerce class is also exported. Later, when resolved through the container, MEF examines the attributes to satisfy its dependencies. In order to register the necessary types, you need to create a catalog of types. MEF provides several ways of cataloging types but the easiest is the assembly catalog. This allows you to point to an assembly and let MEF scan it for types that offer type-export decorations. You can also combine more than one catalog using an aggregate catalog. In this example, you create an aggregate catalog but only add one assembly catalog to it. A g g r e g a t e C a t a l o gc a t a l o g= n e wA g g r e g a t e C a t a l o g ( ) ; c a t a l o g . C a t a l o g s . A d d ( n e wA s s e m b l y C a t a l o g ( A s s e m b l y . G e t E x e c u t i n g A s s e m b l y ( ) ) ) ; C o n t a i n e r=n e wC o m p o s i t i o n C o n t a i n e r ( c a t a l o g ) ;
www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true

&

The CompositionContainer class is MEFs DI container. Here, I built a

7/20

9/2/13

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

The CompositionContainer class is MEFs DI container. Here, I built a catalog from the current assembly, which is where the Commerce class and the four process classes reside. Later, to resolve the Commerce class and its dependencies, I used the GetExportedValue method like this: C o m m e r c ec o m m e r c e= C o n t a i n e r . G e t E x p o r t e d V a l u e < C o m m e r c e > ( ) ; c o m m e r c e . P r o c e s s O r d e r ( o r d e r I n f o ) ; MEF is included with.NET Framework and its discovery mechanism gives it a nice quality over other containers. The trade-off is that your type registrations are scattered throughout all your classes in the way of attribute decorations. I personally do not consider this a negative thing. I like explicit code and MEFs attribute model allows me to always know if a class is being used by MEF or not. This is something I would not be able to tell if I were using a different DI container.

Practical Application of Dependency Injection and Containers


Now, for the fun part. All of this would just be cool code if you dont know how to apply it in your applications. Im going to show you how to implement a DI container into three types of applications: WPF, WebForms, and MVC. With a little effort, you can modify the WPF example to work in a Silverlight scenario as well as a Metro app scenario. The other two examples both apply to ASP.NET, but Ill provide you with both since WebForms and MVC differ quite a bit in the way they serve views. Ill use MEF as the container but the code I make available for download at the end of article also provides examples in Unity. Other containers would be a variation of one of the two examples. WPF WPF continues to be Microsofts premier development platform for its XAML stack. The other two are Silverlight and Metro apps. With certain exceptions here and there, as well some framework differences, development on all three platforms is very similar. Views consist of XAML markup working in conjunction with code-behind pages. A popular pattern that is often associated almost synonymously with WPF (all XAML-stack platforms, in fact) is Model-View-ViewModel, or MVVM. Ill demonstrate DI in a WPF application that implements the MVVM pattern. A WPF application has one main view when the application starts up, which hosts two other views within it and offers a button to toggle between the two. The two views are CustomerListView and CustomerView, and the hosting view is MainWindowView. Each of the three views has a corresponding view-model class under the same name but with a view-model suffix instead of View. A service class provides data models for both the CustomerListViewModel and CustomerViewModel classes. The class is called CustomerRepository and is responsible for obtaining information from a database. The CustomerRepository class implements an interface called ICustomerRepository and the viewmodels contain properties of the interface type, not the concrete class type. As you may be able to tell, Ive set the scene for class dependencies here. The MainWindowViewModel class has a dependency on the other two view-model classes; and each of those two have a dependency on an implementation of the ICustomerRepository interface. In order to satisfy all dependencies, all class instances need to be served up by a DI container. The first order of business is to set one up and register types and associations with it.
www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true

MEF uses discovery to find types and their associations to interfaces,

8/20

9/2/13

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

MEF uses discovery to find types and their associations to interfaces, so you have to decorate any class you want to export so that MEF will find it. Ill leave out most of the class implementation code for brevity, but Ill show the containment of the dependent types to explain afterward. Be sure to check the sidebar to see where you can download the entire solution of projects. The MainWindowViewModel class contains the two other viewmodels and toggles between them using a command and property. The class is shown in Listing 9. In this class, the dependencies are satisfied using property injection. As you can see, there are two properties of the types of the two other view-models and they are both decorated with the Import attribute. Later when this class is resolved, instances of those two view-models will be injected into these two properties. As you can probably guess, both of those view -models will also be exported so that MEF discovers and registers them. Because this class will be resolved and dependencies injected into them using properties, the class will need to be instantiated before its dependencies are injected, unlike a constructor injection technique. To properly initialize and use this view-model, I need to set the CurrentViewModel property to the value _CustomerListViewModel property. The problem is that I cant do this in the constructor because upon construction, the dependencies have not yet been injected. For this kind of situation, MEF gives us the IPartImportsSatisfiedNotification interface. When MEF resolves this view-model class, it checks for this interface and if it finds it implemented, it executes the OnImportsSatisfied method after it finishes injecting dependencies. The other two view-model classes will also be exported and contain the repository as a dependency. For variation of technique demonstration, Ive chosen to use constructor injection in these two cases. [ E x p o r t ] [ P a r t C r e a t i o n P o l i c y ( C r e a t i o n P o l i c y . N o n S h a r e d ) ] p u b l i cc l a s sC u s t o m e r L i s t V i e w M o d e l :v i e w m o d e l B a s e { [ I m p o r t i n g C o n s t r u c t o r ] p u b l i cC u s t o m e r L i s t V i e w M o d e l ( I C u s t o m e r R e p o s i t o r yc u s t o m e r R e p o s i t o r y ) { _ C u s t o m e r s M o d e l= c u s t o m e r R e p o s i t o r y . G e t A l l ( ) ; } } And [ E x p o r t ] [ P a r t C r e a t i o n P o l i c y ( C r e a t i o n P o l i c y . N o n S h a r e d ) ] p u b l i cc l a s sC u s t o m e r V i e w M o d e l:v i e w m o d e l B a s e { [ I m p o r t i n g C o n s t r u c t o r ] p u b l i cC u s t o m e r V i e w M o d e l ( I C u s t o m e r R e p o s i t o r yc u s t o m e r R e p o s i t o r y ) { _ C u s t o m e r M o d e l= c u s t o m e r R e p o s i t o r y . G e t B y I d ( 1 ) ; } } Marking the constructors with the ImportingConstructor attribute provides the constructor injection Im looking for. The last thing I need is to export the CustomerRepository class and to associate it to the ICustomerRepository interface.
www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true 9/20

9/2/13

ICustomerRepository interface.

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

[ E x p o r t ( t y p e o f ( I C u s t o m e r R e p o s i t o r y ) ) ] [ P a r t C r e a t i o n P o l i c y ( C r e a t i o n P o l i c y . N o n S h a r e d ) ] p u b l i cc l a s sC u s t o m e r R e s p o s i t o r y :I C u s t o m e r R e p o s i t o r y { p u b l i cC u s t o m e rG e t B y I d ( i n ti d )... p u b l i cL i s t < C u s t o m e r >G e t A l l ( )... p u b l i cv o i dU p d a t e ( C u s t o m e rc u s t o m e r )... } Remember, due to the recursive nature of the DI container typeresolving process, resolving the MainWindowViewModel class later will resolve its dependencies, the other view-models. Resolving those two classes will resolve their dependencies, the CustomerRepository class. Now that the classes are set up properly, the WPF application needs to discover them so the container can be assembled. The easiest place to do this is in the code-behind of the App.xaml file by overriding the OnStartup method. This will ensure that it happens at application startup. p u b l i cp a r t i a lc l a s sA p p:A p p l i c a t i o n { p u b l i cs t a t i cC o m p o s i t i o n C o n t a i n e rC o n t a i n e r ; p r o t e c t e do v e r r i d ev o i dO n S t a r t u p ( S t a r t u p E v e n t A r g se ) { A g g r e g a t e C a t a l o gc a t a l o g= n e wA g g r e g a t e C a t a l o g ( ) ; c a t a l o g . C a t a l o g s . A d d ( n e wA s s e m b l y C a t a l o g ( A s s e m b l y . G e t E x e c u t i n g A s s e m b l y ( ) ) ) ; C o n t a i n e r=n e wC o m p o s i t i o n C o n t a i n e r ( c a t a l o g ) ; b a s e . O n S t a r t u p ( e ) ; } } Im also storing the instance of the container in a static property so it can be accessed from anywhere in the application if needed. Because the MainWindowView window is set up to be the startup window, its code-behind class executes when the application starts up after the aforementioned OnStartup method executes. The viewmodel for this window needs to be set to the windows DataContext property. The other views will have theirs set through data templates and a standard view-model-to-Content property technique, but since this is the first one, it needs to be done manually. Rather than manually instantiating an instance of the MainWindowViewModel class, Im going to ask the container for it, and Ill do it in the MainWindowView class constructor. p u b l i cM a i n W i n d o w ( ) { I n i t i a l i z e C o m p o n e n t ( ) ; M a i n W i n d o w V i e w M o d e lv i e w m o d e l= A p p . C o n t a i n e r . G e t E x p o r t e d V a l u e < M a i n W i n d o w V i e w M o d e l > ( ) ; t h i s . D a t a C o n t e x t=v i e w m o d e l ; } This sets the DI wheels into motion. Nowhere else in this project will you be instantiating any view-model manually, or any type in which view-models are dependent. The application is constructed the way modern WPF, Silverlight, and Metro applications are written: using containment, view-switching, and with view-models mimicking the
www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true 10/20

9/2/13

containment, view-switching, and with view-models mimicking the containment relationship between views.

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

When you write unit tests to test the CustomerRepository , you use that actual class so that you can test the database functionality, but when you write unit tests to test the view-models, you dont necessarily need to access the database. Because the view-models depend on a type that implements the ICustomerRepository , you can provide view-models with either a test implementation or even better Id use a mocking framework. MVC ASP.NET MVC is a terrific framework that allows us to develop Web applications in keeping with good architectural and development principles, including separation of concerns, testability, and dependency injection. Like the view-models in the previous example, the controller classes youll use in the MVC example will depend on the same ICustomerRepository dependency. The CustomerRepository class and the ICustomerRepository interface remain exactly the same as in the WPF example, so I wont repeat it here. The HomeController class will have its dependency injected using constructor injection and can be seen in Listing 10. Notice that this class is exported with an identifier string that is the same name as the controller class but without the word Controller. Also note that the class is associated with the IController interface. This is the case with all other controllers that I write, and because there will be many classes associated with the same interface; the string identifier becomes important when the controllers get resolved later. When they architected ASP.NET MVC, they took the idea of decoupled types right into the design of the framework. When you write a controller class in ASP.NET MVC, a controller factory instantiates the class and executes the desired action. The controller factory can be unhooked and a replacement put in its place so you can intercept how controller classes are served up. Because this controller has dependencies that need to be injected into it, it needs to be instantiated through the container. You have a few choices in the way you implement DI in the MVC application, and the first choice is where to setup the container. You can do it in the Global.asax.cs class but what you really need to do in this file is to hook up a replacement to the default controller factory. You need to write a class called MefControllerFactory and hook it up in the application startup event of the Global.asax.cs class. p r o t e c t e dv o i dA p p l i c a t i o n _ S t a r t ( ) { A r e a R e g i s t r a t i o n . R e g i s t e r A l l A r e a s ( ) ; R e g i s t e r G l o b a l F i l t e r s ( G l o b a l F i l t e r s . F i l t e r s ) ; R e g i s t e r R o u t e s ( R o u t e T a b l e . R o u t e s ) ; C o n t r o l l e r B u i l d e r . C u r r e n t . S e t C o n t r o l l e r F a c t o r y ( n e wM e f C o n t r o l l e r F a c t o r y ( ) ) ; } The line I added to this already-existing event is the last one, where I set the controller factory to an instance of the replacement class. You will set up the container in the MefControllerFactory class. The controller factory is in Listing 11. I could have written a controller factory entirely from scratch by implementing the IController interface, but it was much easier to inherit from the default one and override the CreateController
www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true 11/20

9/2/13

inherit from the default one and override the CreateController method. The constructor contains the code that will discover all of my exported types and store the container in a class variable for later use. When a controller is requested during a browser query, this class will get hit for a controller and it will execute the CreateController method. The argument, controllerName, will receive the name of the controller as it appeared in the URL used to query the application, without the word Controller in it. Thiss why I exported the HomeController and identified it with the name, Home. The CreateController method queries the controller for a specific type that implements the IController interface using the identifier name. When the controller class gets resolved, the ICustomerRepository dependency will be injected into the constructor argument since I decorated the constructor with ImportingConstructor. From here, its available to any action that needs to use it. As in the WPF example, you can write unit tests to test the controller actions and use a mock object to satisfy the necessary dependencies.

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

I want to take advantage of an opportunity presented in this example to demonstrate a way you can extend MEF to provide something that was not built into it. The controller factory has another available method that can be overridden in order to obtain a controller class, called GetControllerInstance. This method does not receive a controller name in an argument but instead receives a Type. This type corresponds to the controller class that needs to be instantiated. This seems a whole lot easier because then I can simply export the controller, with no need to identify it with a name or associate it with the IController interface. The problem is that the MEF container does not come equipped with a method to resolve a type given an actual Type argument; so Ill extend it by writing an extension method. You can see my extension method in Listing 12. This extension method adds a method to the container called GetExportedValueByType. This method scans the registered types and looks for one that matches the Type argument sent into the method. Now you can resolve the controllers in the controller factory without the need for its name, and you can change the exportation of the controller classes to a simple [Export]. p r o t e c t e do v e r r i d eI C o n t r o l l e r G e t C o n t r o l l e r I n s t a n c e ( R e q u e s t C o n t e x tr e q u e s t C o n t e x t , T y p ec o n t r o l l e r T y p e ) { r e t u r n_ C o n t a i n e r . G e t E x p o r t e d V a l u e B y T y p e ( c o n t r o l l e r T y p e )a sI C o n t r o l l e r ; } Theres a new feature added to MVC 3 called the dependency resolver which offers yet another way of resolving controllers. In fact, it allows you to resolve many other things in ASP.NET MVC. The full code for this article includes examples of its usage, but for the purposes of brevity I will not discuss it here. WebForms The last example of DI usage I will demonstrate involves a technology that many think cannot be subject to DI and called it one of its shortcomings: ASP.NET WebForms. Unlike ASP.NET MVC, the WebForms architecture is one of a much coupled nature. ASPX pages are combined with code-behind class and at runtime, the two are combined and a virtual page class is created and executed. This is where the page life-cycle comes from and why we get several great events into which we can inject code. Sadly this also means that the code-behind class cannot be instantiated and served by an outside influence, since it needs to remain under ASP.NET management the entire time. However, like ASP.NET MVC, there is a mechanism in place that builds the classes for us and its into that you can tap. Pages in ASP.NET WebForms are served up using a class called
www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true 12/20

9/2/13

Pages in ASP.NET WebForms are served up using a class called PageHandlerFactory . This class is installed as an HTTP Handler Factory and is meant to return an instance of an HTTP Handler; in this case, a class that is derivative from System.Web.UI.Page. What you can do is override this process with your own handler factory that derives from the standard one. By overriding the method that returns the Page class, you can call upon the base so that you can obtain that page class without interfering with the process, then you can inject your dependencies. Construction injection is out of the question here because you cannot resolve the page class using a container, so you have to resort to property injection. MEF lets you do this easily by declaring the dependency properties and decorating them with the Import attribute. The dependency class in this case remains the CustomerRepository class and its configuration for MEF compliance remains the same as in the two previous examples. The ASPX pages code-behind class does

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

not need to get decorated with anything at the class level, since it will not be served through the container, only at the property level for the dependencies it may contain. p u b l i cp a r t i a lc l a s sC u s t o m e r s :S y s t e m . W e b . U I . P a g e { [ I m p o r t ] I C u s t o m e r R e p o s i t o r y_ C u s t o m e r R e p o s i t o r y ; p r o t e c t e dv o i dP a g e _ L o a d ( o b j e c ts e n d e r , E v e n t A r g se ) { g r d C u s t o m e r s . D a t a S o u r c e= _ C u s t o m e r R e p o s i t o r y . G e t A l l ( ) ; g r d C u s t o m e r s . D a t a B i n d ( ) ; } } Ill show you how to resolve that class dependencies in a few minutes, but first you have to configure the container in the WebForms application. As in the MVC example, you can go to the Application_Start event in the Global.asax.cs file to set up the container. p r o t e c t e dv o i dA p p l i c a t i o n _ S t a r t ( o b j e c ts e n d e r , E v e n t A r g se ) { A g g r e g a t e C a t a l o gc a t a l o g= n e wA g g r e g a t e C a t a l o g ( ) ; c a t a l o g . C a t a l o g s . A d d ( n e wA s s e m b l y C a t a l o g ( A s s e m b l y . G e t E x e c u t i n g A s s e m b l y ( ) ) ) ; C o m p o s i t i o n C o n t a i n e rc o n t a i n e r= n e wC o m p o s i t i o n C o n t a i n e r ( c a t a l o g ) ; A p p l i c a t i o n [ " C o n t a i n e r " ]=c o n t a i n e r ; } Also like the previous example, youll use the Application store to hang on to the container. Next, you have to create a class that will replace the PageHandlerFactory class. Ive created a class called MefPageHandlerFactory , which will override the GetHandler method and obtain the Page class by calling on the base. Listing 13 shows the factory class. After youve obtained the page class, youll use a feature that MEF provides. By calling the SatisfyImportsOnce method, youre telling MEF to run the class sent into the argument through the resolve process and attempt to resolve any properties it finds decorated with the Import attribute. When the page is returned at the end of the method, it will be equipped with instances of the proper classes in its dependency properties.

www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true

13/20

9/2/13

dependency properties.

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

The last thing you need to do is install the new handler factory in the web.config file by assigning it as the handler to be used for anything with an aspx extension. < s y s t e m . w e b > < h t t p H a n d l e r s > < a d dp a t h = " * . a s p x "v e r b = " * " t y p e = " D I . W e b F o r m s . M e f P a g e H a n d l e r F a c t o r y "/ > < / h t t p H a n d l e r s > < / s y s t e m . w e b > Unfortunately, unit-testing WebForms code-behind pages is next to impossible as the class cannot be instantiated on its own. This remains one of WebForms shortcomings. That being said, I think I need to say something in defense of WebForms. Business code should be written so it can be tested on its own, regardless of the client implementing it. ASP.NET MVC lets us unit test controller actions but that does not mean this should serve as the test for your business logic. Controller actions return a certain result based on input arguments and thats what should be tested by unit tests, not that the customer was saved properly. If you design applications to accommodate this, the lack of ability to test a WebForms code-behind class will seem a little less significant and WebForms may be able to retain some of the glory it once carried as a first class development platform for Web applications. I say this as an active developer in both the WebForms and MVC platforms.

Conclusion
As you can see, dependency injection solves several problem areas in development. It allows you to decouple code components from one another and it lets you stop worrying about instantiating classes to send into other classes. Solving these two problems also sets up your software for easy testability later. There are many elements of DI that I couldnt cover in this article. Among them is the resolving multiple implementations of an interface as well as defining which of several registered implementations gets resolved, which is possible through configuration files. Most containers provide both of these features, each in its own variety. I also couldnt cover every container out there. Besides MEF, Unity, NInject, and Castle Windsor, there are also StructureMap and Spring.NET. I apologize to the developers of the latter two for not providing coverage within this article but Ill go on record as saying that both StructureMap and Spring.NET are first-class citizens in the DI world and top-shelf products. The examples in this article should give you a great head-start on using dependency injection. The three scenarios should also serve as a good kick-off point for just about any application you are writing. Whether youre using a Microsoft container or a third-party one, using DI in your applications will ensure that youre writing decoupled, manageable, and testable components, and also very importantly, its really, really cool. Miguel Castro

www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true

Listing 1: OrderInfo class p u b l i cc l a s sO r d e r I n f o { p u b l i cs t r i n gC u s t o m e r N a m e{g e t ;s e t ;} p u b l i cs t r i n gE m a i l{g e t ;s e t ;} p u b l i cs t r i n gP r o d u c t{g e t ;s e t ;} p u b l i cd o u b l eP r i c e{g e t ;s e t ;}

14/20

9/2/13

p u b l i cd o u b l eP r i c e{g e t ;s e t ;} p u b l i cs t r i n gC r e d i t C a r d{g e t ;s e t ;}

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

Listing 2: The four process classes p u b l i cc l a s sB i l l i n g P r o c e s s o r { p u b l i cv o i dP r o c e s s P a y m e n t ( s t r i n gc u s t o m e r , s t r i n gc r e d i t C a r d ,d o u b l ep r i c e ) { / /p e r f o r mb i l l i n gg a t e w a yp r o c e s s i n g } } p u b l i cc l a s sC u s t o m e r { p u b l i cv o i dU p d a t e C u s t o m e r O r d e r ( s t r i n gc u s t o m e r , s t r i n gp r o d u c t ) { / /u p d a t ec u s t o m e rr e c o r dw i t hp u r c h a s e } } p u b l i cc l a s sN o t i f i e r { p u b l i cv o i dS e n d R e c e i p t ( O r d e r I n f oo r d e r I n f o ) { / /s e n de m a i lt oc u s t o m e rw i t hr e c e i p t } } p u b l i cc l a s sL o g g e r { p u b l i cv o i dL o g ( s t r i n gm e s s a g e ) { / /l o gm e s s a g et ol o gf i l e } }

Listing 3: Commerce class p u b l i cc l a s sC o m m e r c e { p u b l i cC o m m e r c e ( B i l l i n g P r o c e s s o rb i l l i n g P r o c e s s o r , C u s t o m e rc u s t o m e r , N o t i f i e rn o t i f i e r , L o g g e rl o g g e r ) { _ B i l l i n g P r o c e s s o r=b i l l i n g P r o c e s s o r ; _ C u s t o m e r=c u s t o m e r ; _ N o t i f i e r=n o t i f i e r ; _ L o g g e r=l o g g e r ; } B i l l i n g P r o c e s s o r_ B i l l i n g P r o c e s s o r ; C u s t o m e r_ C u s t o m e r ; N o t i f i e r_ N o t i f i e r ; L o g g e r_ L o g g e r ; p u b l i cv o i dP r o c e s s O r d e r ( O r d e r I n f oo r d e r I n f o ) { _ B i l l i n g P r o c e s s o r . P r o c e s s P a y m e n t ( o r d e r I n f o . C u s t o m e r N a m e , o r d e r I n f o . C r e d i t C a r d , o r d e r I n f o . P r i c e ) ; _ L o g g e r . L o g ( " B i l l i n gp r o c e s s e d " ) ; _ C u s t o m e r . U p d a t e C u s t o m e r O r d e r ( o r d e r I n f o . C u s t o m e r N a m e ,

www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true

15/20

9/2/13

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

o r d e r I n f o . C u s t o m e r N a m e , o r d e r I n f o . P r o d u c t ) ; _ L o g g e r . L o g ( " C u s t o m e ru p d a t e d " ) ; _ N o t i f i e r . S e n d R e c e i p t ( o r d e r I n f o ) ; _ L o g g e r . L o g ( " R e c e i p ts e n t " ) ; } }

Listing 4: Process classes refactored to interfaces p u b l i ci n t e r f a c eI B i l l i n g P r o c e s s o r { v o i dP r o c e s s P a y m e n t ( s t r i n gc u s t o m e r ,s t r i n gc r e d i t C a r d , d o u b l ep r i c e ) ; } p u b l i ci n t e r f a c eI C u s t o m e r { v o i dU p d a t e C u s t o m e r O r d e r ( s t r i n gc u s t o m e r , s t r i n gp r o d u c t ) ; } p u b l i ci n t e r f a c eI N o t i f i e r { v o i dS e n d R e c e i p t ( O r d e r I n f oo r d e r I n f o ) ; } p u b l i ci n t e r f a c eI L o g g e r { v o i dL o g ( s t r i n gm e s s a g e ) ; }

Listing 5: Commerce class rewrite using interfaces p u b l i cc l a s sC o m m e r c e { p u b l i cC o m m e r c e ( I B i l l i n g P r o c e s s o rb i l l i n g P r o c e s s o r , I C u s t o m e rc u s t o m e r , I N o t i f i e rn o t i f i e r , I L o g g e rl o g g e r ) { _ B i l l i n g P r o c e s s o r=b i l l i n g P r o c e s s o r ; _ C u s t o m e r=c u s t o m e r ; _ N o t i f i e r=n o t i f i e r ; _ L o g g e r=l o g g e r ; } I B i l l i n g P r o c e s s o r_ B i l l i n g P r o c e s s o r ; I C u s t o m e r_ C u s t o m e r ; I N o t i f i e r_ N o t i f i e r ; I L o g g e r_ L o g g e r ; p u b l i cv o i dP r o c e s s O r d e r ( O r d e r I n f oo r d e r I n f o ) { _ B i l l i n g P r o c e s s o r . P r o c e s s P a y m e n t ( o r d e r I n f o . C u s t o m e r N a m e ,o r d e r I n f o . C r e d i t C a r d , o r d e r I n f o . P r i c e ) ; _ L o g g e r . L o g ( " B i l l i n gp r o c e s s e d " ) ; _ C u s t o m e r . U p d a t e C u s t o m e r O r d e r ( o r d e r I n f o . C u s t o m e r N a m e , o r d e r I n f o . P r o d u c t ) ; _ L o g g e r . L o g ( " C u s t o m e ru p d a t e d " ) ; _ N o t i f i e r . S e n d R e c e i p t ( o r d e r I n f o ) ; _ L o g g e r . L o g ( " R e c e i p ts e n t " ) ; } }

Listing 6: My makeshift DI container p u b l i cc l a s sC o n t a i n e r {


www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true 16/20

9/2/13

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

p u b l i cC o n t a i n e r ( ) { _ R e g i s t r a t i o n s=n e wL i s t < C o n t a i n e r I t e m > ( ) ; } p u b l i cv o i dR e g i s t e r < T ,U > ( ) w h e r eU:c l a s s ,n e w ( ) { T y p ea b s t r a c t i o n T y p e=t y p e o f ( T ) ; T y p ec o n c r e t e T y p e=t y p e o f ( U ) ; i f( ! a b s t r a c t i o n T y p e . I s I n t e r f a c e ) t h r o wn e wA p p l i c a t i o n E x c e p t i o n ( " F i r s tg e n e r i ca r g u m e n tm u s tb ea n i n t e r f a c et y p e . " ) ; _ R e g i s t r a t i o n s . A d d ( n e wC o n t a i n e r I t e m ( ) { A b s t r a c t i o n T y p e=a b s t r a c t i o n T y p e , C o n c r e t e T y p e=c o n c r e t e T y p e } ) ; } L i s t < C o n t a i n e r I t e m >_ R e g i s t r a t i o n s ; }

Listing 7: Modified CreateType function and support code p u b l i cTC r e a t e T y p e < T > ( )w h e r eT:c l a s s { T y p et y p e=t y p e o f ( T ) ; r e t u r n( T ) G e t C o n c r e t e T y p e ( t y p e ) ; } o b j e c tG e t C o n c r e t e T y p e ( T y p et y p e T o R e s o l v e ) { C o n t a i n e r I t e mc o n t a i n e r I t e m= _ R e g i s t r a t i o n s . W h e r e ( i t e m= > i t e m . A b s t r a c t i o n T y p e . E q u a l s ( t y p e T o R e s o l v e ) ) . F i r s t O r D e f a u l t ( ) ; i f( c o n t a i n e r I t e m! =n u l l ) r e t u r nG e t T y p e I n s t a n c e ( c o n t a i n e r I t e m . C o n c r e t e T y p e ) ; e l s e r e t u r nG e t T y p e I n s t a n c e ( t y p e T o R e s o l v e ) ; } o b j e c tG e t T y p e I n s t a n c e ( T y p et y p e ) { o b j e c ti n s t a n c e=n u l l ; C o n s t r u c t o r I n f o [ ]c o n s t r u c t o r s=t y p e . G e t C o n s t r u c t o r s ( ) ; i f( c o n s t r u c t o r s . L e n g t h>0 ) { C o n s t r u c t o r I n f oc o n s t r u c t o r=c o n s t r u c t o r s [ 0 ] ; L i s t < o b j e c t >c o n s t r u c t o r A r g u m e n t s= n e wL i s t < o b j e c t > ( ) ; P a r a m e t e r I n f o [ ]p a r a m e t e r s= c o n s t r u c t o r . G e t P a r a m e t e r s ( ) ; f o r e a c h( P a r a m e t e r I n f op a r a m e t e ri np a r a m e t e r s ) { o b j e c tp a r a m e t e r I n s t a n c e=n u l l ; i f( p a r a m e t e r . P a r a m e t e r T y p e . I s I n t e r f a c e ) p a r a m e t e r I n s t a n c e=G e t C o n c r e t e T y p e ( p a r a m e t e r . P a r a m e t e r T y p e ) ; c o n s t r u c t o r A r g u m e n t s . A d d ( p a r a m e t e r I n s t a n c e ) ; }
www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true 17/20

9/2/13

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

i n s t a n c e=A c t i v a t o r . C r e a t e I n s t a n c e ( t y p e ,c o n s t r u c t o r A r g u m e n t s . T o A r r a y ( ) ) ; } r e t u r ni n s t a n c e ; }

Listing 8: MEF-aware Commerce class [ E x p o r t ] [ P a r t C r e a t i o n P o l i c y ( C r e a t i o n P o l i c y . N o n S h a r e d ) ] p u b l i cc l a s sC o m m e r c e { [ I m p o r t i n g C o n s t r u c t o r ] p u b l i cC o m m e r c e ( I B i l l i n g P r o c e s s o rb i l l i n g P r o c e s s o r , I C u s t o m e rc u s t o m e r ,I N o t i f i e rn o t i f i e r , I L o g g e rl o g g e r ) { _ B i l l i n g P r o c e s s o r=b i l l i n g P r o c e s s o r ; _ C u s t o m e r=c u s t o m e r ; _ N o t i f i e r=n o t i f i e r ; _ L o g g e r=l o g g e r ; } I B i l l i n g P r o c e s s o r_ B i l l i n g P r o c e s s o r ; O R p u b l i cC o m m e r c e ( ) { } [ I m p o r t ] I B i l l i n g P r o c e s s o r_ B i l l i n g P r o c e s s o r ; }

Listing 9: MainWindowViewModel class [ E x p o r t ] [ P a r t C r e a t i o n P o l i c y ( C r e a t i o n P o l i c y . N o n S h a r e d ) ] p u b l i cc l a s sM a i n W i n d o w V i e w M o d e l V i e w M o d e l B a s e ,I P a r t I m p o r t s S a t i s f i e d N o t i f i c a t i o n { [ I m p o r t ] C u s t o m e r L i s t V i e w M o d e l_ C u s t o m e r L i s t V i e w M o d e l ; [ I m p o r t ] C u s t o m e r V i e w M o d e l_ C u s t o m e r V i e w M o d e l ; V i e w M o d e l B a s e_ C u r r e n t V i e w M o d e l ; p u b l i cI C o m m a n dT o g g l e V i e w C o m m a n d{g e t ;p r i v a t es e t ;} p u b l i cV i e w M o d e l B a s eC u r r e n t V i e w M o d e l { g e t{r e t u r n_ C u r r e n t V i e w M o d e l ;} s e t { _ C u r r e n t V i e w M o d e l=v a l u e ; O n P r o p e r t y C h a n g e d ( " C u r r e n t V i e w M o d e l " ) ; } } p u b l i cv o i dO n I m p o r t s S a t i s f i e d ( ) { C u r r e n t V i e w M o d e l=_ C u s t o m e r L i s t V i e w M o d e l ;


www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true 18/20

9/2/13

C u r r e n t V i e w M o d e l=_ C u s t o m e r L i s t V i e w M o d e l ; }

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

Listing 10: MVC controller [ E x p o r t ( " H o m e " ,t y p e o f ( I C o n t r o l l e r ) ) ] [ P a r t C r e a t i o n P o l i c y ( C r e a t i o n P o l i c y . N o n S h a r e d ) ] p u b l i cc l a s sH o m e C o n t r o l l e r:C o n t r o l l e r { [ I m p o r t i n g C o n s t r u c t o r ] p u b l i cH o m e C o n t r o l l e r ( I C u s t o m e r R e p o s i t o r yc u s t o m e r R e p o s i t o r y ) { _ C u s t o m e r R e p o s i t o r y=c u s t o m e r R e p o s i t o r y ; } I C u s t o m e r R e p o s i t o r y_ C u s t o m e r R e p o s i t o r y ; p u b l i cA c t i o n R e s u l tC u s t o m e r s ( ) { I E n u m e r a b l e < C u s t o m e r >c u s t o m e r s= _ C u s t o m e r R e p o s i t o r y . G e t A l l ( ) ; r e t u r nV i e w ( c u s t o m e r s ) ; } }

Listing 11: MVC controller factory p u b l i cc l a s sM e f C o n t r o l l e r F a c t o r y:D e f a u l t C o n t r o l l e r F a c t o r y { p r i v a t eC o m p o s i t i o n C o n t a i n e r_ C o n t a i n e r ; p u b l i cM e f C o n t r o l l e r F a c t o r y ( ) { A g g r e g a t e C a t a l o gc a t a l o g=n e wA g g r e g a t e C a t a l o g ( ) ; c a t a l o g . C a t a l o g s . A d d ( n e wA s s e m b l y C a t a l o g ( A s s e m b l y . G e t E x e c u t i n g A s s e m b l y ( ) ) ) ; _ C o n t a i n e r=n e wC o m p o s i t i o n C o n t a i n e r ( c a t a l o g ) ; } p u b l i co v e r r i d eI C o n t r o l l e rC r e a t e C o n t r o l l e r ( R e q u e s t C o n t e x tr e q u e s t C o n t e x t ,s t r i n gc o n t r o l l e r N a m e ) { r e t u r n_ C o n t a i n e r . G e t E x p o r t e d V a l u e < I C o n t r o l l e r > ( c o n t r o l l e r N a m e ) ; } }

www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true

Listing 12: MEF extension method p u b l i cs t a t i co b j e c tG e t E x p o r t e d V a l u e B y T y p e ( t h i sC o m p o s i t i o n C o n t a i n e rc o n t a i n e r ,T y p et y p e ) { f o r e a c h( v a rP a r t D e fi nc o n t a i n e r . C a t a l o g . P a r t s ) { f o r e a c h( v a rE x p o r t D e fi nP a r t D e f . E x p o r t D e f i n i t i o n s ) { i f( E x p o r t D e f . C o n t r a c t N a m e= =t y p e . F u l l N a m e ) { v a rc o n t r a c t=A t t r i b u t e d M o d e l S e r v i c e s . G e t C o n t r a c t N a m e ( t y p e ) ; v a rd e f i n i t i o n= n e wC o n t r a c t B a s e d I m p o r t D e f i n i t i o n ( c o n t r a c t ,c o n t r a c t ,n u l l , I m p o r t C a r d i n a l i t y . E x a c t l y O n e , f a l s e ,f a l s e ,C r e a t i o n P o l i c y . A n y ) ;

19/20

9/2/13

CODE Magazine - Article: Understanding Dependency Injection and Those Pesky Containers

f a l s e ,f a l s e ,C r e a t i o n P o l i c y . A n y ) ; r e t u r nc o n t a i n e r . G e t E x p o r t s ( d e f i n i t i o n ) . F i r s t O r D e f a u l t ( ) . V a l u e ; } } } r e t u r nn u l l ; }

Listing 13: WebForms Page Handler Factory p u b l i cc l a s sM e f P a g e H a n d l e r F a c t o r y:P a g e H a n d l e r F a c t o r y { p u b l i co v e r r i d eI H t t p H a n d l e rG e t H a n d l e r ( H t t p C o n t e x tc o n t e x t , s t r i n gr e q u e s t T y p e , s t r i n gv i r t u a l P a t h , s t r i n gp a t h ) { P a g ep a g e=b a s e . G e t H a n d l e r ( c o n t e x t ,r e q u e s t T y p e ,v i r t u a l P a t h ,p a t h ) a sP a g e ; i f( p a g e= =n u l l ) r e t u r np a g e ; C o m p o s i t i o n C o n t a i n e rc o n t a i n e r= c o n t e x t . A p p l i c a t i o n [ " C o n t a i n e r " ] a sC o m p o s i t i o n C o n t a i n e r ; c o n t a i n e r . S a t i s f y I m p o r t s O n c e ( p a g e ) ; r e t u r np a g e ; } }

www.code-magazine.com/articleprint.aspx?quickid=1210031&printmode=true

20/20

S-ar putea să vă placă și