Inject Services in ASP.NET Pages

When a Page Depends on One or More External Components, Code Injection Is a Good Thing

CoreCoder

LANGUAGES: C#

ASP.NET VERSIONS: 3.5

 

Inject Services in ASP.NET Pages

When a Page Depends on One or More External Components, Code Injection Is a Good Thing

 

By Dino Esposito

 

In software (and specifically in Web software), the term injection has an ominous overtone. You immediately think of SQL injection or perhaps script injection. There is, however, a form of injection in software that is absolutely benign and helpful. It is often referred to as dependency injection (DI).

 

Admittedly, the term dependency injection is high-sounding, maybe even a bit bombastic. But it sounds cool, doesn t it? When you say I use a lot of dependency injection you sound esoteric; when you say I write event handlers you sound pragmatic, at best. But under the hood in both cases you re applying the same object-oriented principle: the Dependency Inversion Principle (DIP).

 

In this article I ll first introduce DIP and provide a few sample programming scenarios where you use plenty of it. Next, I ll move on to consider a popular pattern that springs from the principle: dependency injection. I ll also clarify some of the confusion surrounding the terms, and finish by showing a practical example of how to leverage DI in ASP.NET pages.

 

The Principle of Inversion

In the theory of object-oriented design (OOD), DIP states that in the design of a class you should isolate dependencies and design the class in a way that makes it independent from any low-level module. For example, the Task class may depend on your implementation of a Logger class, and a Membership class may depend on a validation module that checks credentials.

 

These dependencies are part of the contract, so they cannot be avoided or skipped. However, as a good designer you should design the class in a way that makes an instance of the internal module just a parameter. Like many of you, I guess, I was scared at first by the name dependency injection , but I did know all too well the principle of creating functions and classes in a parametric way. It is the same old concept, just revamped and given a new, fancier name. Although in different forms, this principle has been around since the late 1980s; it was formalized as DIP by Robert Martin in the mid-1990s (see http://www.objectmentor.com/resources/articles/dip.pdf for more information).

 

Why is the term inversion being used to describe the principle? The term inversion refers to the fact that during the implementation you proceed in a top-down manner and are interested in reusing the biggest possible outermost container rather than a small piece of functionality. Suppose you have a Membership class with a ValidationChecker member. What would you like to reuse? The validation checker or the Membership class? Reusing the ValidationChecker class is straightforward it s already a reusable class. The challenge is in being able to reuse the outermost container. But the outermost container the Membership class depends on the validation checker. If you can break this dependency, you ll win.

 

DIP contrasts the vision according to which you build larger classes by aggregating smaller pieces of code in a bottom-up approach. With DIP, you go top-down both in design and implementation. This is the inversion.

 

The Dependency Injection Pattern

Dependency injection is merely a pattern that implements DIP. It consists of designing classes with well-known injection points where any required dependency can be passed in as an argument. A real-world example of DI are Windows shell extensions or perhaps ASP.NET HTTP modules. In both cases, you have some mainstream code that at some point expects to receive input from an external dependency, a registered shell extension, or a registered HTTP module. It looks around, loads the dependency, and interacts with that through a known interface.

 

Wait a moment. Doesn t this sound a lot like plug-ins? What s the difference, if any? Plugin and DI are two related patterns for making a piece of code independent from some low-level modules in a way that allows you to change the module at will (even on the fly) without affecting the behavior and functionality of the outermost container. I ll return to plug-ins in a moment.

 

Before going any further, I need to clarify how DI relates to Inversion of Control (IoC). Many consider DI and IoC synonymous and use the terms interchangeably; others differentiate.

 

My guess is that anybody who wants to intervene in the debate probably understands that there should be a general principle and a practical pattern. The problem is merely with naming. In many articles and books, I ve seen IoC presented as the principle and DI as the pattern. In those references there s no mention of DIP. It seems to me that, instead, IoC originates in the Java community as the pattern that applies DIP to classes. DI is a relatively newer term coined a few years ago by Martin Fowler (see http://martinfowler.com/articles/injection.html). According to Fowler, DI is a more precise term than IoC and expresses better what s going on. With DI being so similar to DIP, the confusion is warranted. And a key fact that often goes unnoticed is that the I in DI stands for injection; the I in DIP stands for inversion. In the end, given this description, I consider IoC and DI synonymous, but both patterns of DIP.

 

Plugin vs. DI/IoC

What s the difference between the Plugin pattern and the DI/IoC pattern? With DI/IoC you can spot dependencies right from the constructor of the class. If you use a Plugin pattern, instead, you must inspect the source code of the class to spot dependencies.

 

Some people argue that DI/IoC is preferable because it makes a solution easier to test. Honestly, I don t see the point. In both cases, you can provide a fake or a mock-up for testing purposes.

Another point that is often made in the debate is that a class designed with DI/IoC in mind is inherently more reusable across applications. A class that accepts all of its dependent components via, say, the constructor is easier to manage than a class that uses an internal factory to locate and instantiate all dependencies. With DI/IoC you have more self-contained solutions.

 

Finally, I d say that the Plugin+Factory pair works better when you have a list of potential components to load, but you don t know how many of them are actually registered. A DI/IoC works better when you know exactly how many components you re going to load.

 

That said, both Plugin and DI/IoC can be used where appropriate. The biggest, and indisputable, benefit associated with DI/IoC solutions is the availability of ad hoc frameworks. When you get to use one of these frameworks, as you ll see in a moment, you configure some mappings between interfaces and actual types, then instruct the framework to return the actual instance of a class that implements a given interface. Let s examine a practical case. Figure 1 lists some popular DI/IoC frameworks.

 

Framework

URL

Castle Windsor

http://www.castleproject.org/container/index.html

Spring.NET

http://www.springframework.net

StructureMap

http://structuremap.sourceforge.net/Default.htm

Unity (Enterprise Library 4.0)

http://codeplex.com/unity

Figure 1: Popular DI/IoC frameworks.

 

Injection in Action

Microsoft Unity comes with Microsoft s Enterprise Library 4.0; I ll be using that for the purposes of this article. All DI/IoC frameworks are built around a container object. Bound to some configuration information, the container resolves dependencies. The caller code instantiates the container and passes the desired interface as an argument. In response, the IoC/DI framework returns a concrete object that implements that interface.

 

A class designed for DI/IoC needs to have an injection point for its dependencies. Each dependency is represented with an interface. There are three ways to inject dependencies into a class: using the constructor, a setter property, or an interface.

 

More in detail, you can add a new constructor to the class and make it accept as many dependencies as required. As mentioned, each dependency is an interface. Here s an example:

 

public class Task

{

   private IDependency1 _dep1 = null;

   private IDependency2 _dep2 = null;

   // Inject the dependency via the ctor

   public Task(IDependency1 dep1, IDependency2 dep2)

   {

      this._dep1 = dep1;

      this._dep2 = dep2;

   }

   :

}

 

Alternatively, you can define a setter property (or method) on the class and pass dependencies through that. A third possibility is represented by a combination of methods and properties. In this case, the class implements the interface and supports injection through the members. All techniques are valid; the choice is up to you. Most of the time you would use a constructor or a setter.

 

Applying DI to ASP.NET Pages

To begin, add to your ASP.NET project a reference to Unity. Next, edit the web.config file as shown in Figure 2.

 

<configuration>

 <configSections>

   <section name="unity" type="Microsoft.Practices.Unity.

    Configuration.UnityConfigurationSection, &#xA;

    Microsoft.Practices.Unity.Configuration,

     Version=1.1.0.0, Culture=neutral, &#xA;

     PublicKeyToken=31bf3856ad364e35" />

 </configSections>

 <unity>

   <containers>

      <container>

         <types>

      <type type="Samples.IDataFinder, base"

      mapTo="Samples.NWindFinder, appNWind" />

         </types>

     </container>

   </containers>

 </unity>

</configuration>

Figure 2: Registering a DI/IoC mapping.

 

The <types> section lists the type that the DI/IoC container should look for:

 

<types>

 <type type="Samples.IDataFinder, base"

   mapTo="Samples.NWindFinder, appNWind" />

 :

</types>

 

The type attribute indicates the interface on which a class depends. The mapTo attribute indicates the actual type to instantiate whenever the container requests the specified type. For example, whenever the DI/IoC container requests a type IDataFinder from an assembly named base.dll, it actually returns an instance of NWindFinder from the assembly appNWind. Let s see what else is required in an ASP.NET application.

 

To smooth the propagation of DI/IoC capabilities throughout the pages of the site, I created a base page class and exposed a Resolve method, as shown in Figure 3.

 

public class MyBasePage : System.Web.UI.Page

{

 protected IUnityContainer container = null;

 public MyBasePage()

 {

   // Initialize the DI/IoC container

   container = new UnityContainer();

   // Instruct the container to read information

   // from web.config

   UnityConfigurationSection section;

   section = ConfigurationManager.GetSection("unity")

      as UnityConfigurationSection;

   section.Containers.Default.Configure(container);

 }

 public IDataFinder DataFinder { get; set; }

 public T Resolve<T>()

 {

   // Take type T and look in the configuration for

   // matching types

   return container.Resolve<T>();

 }

}

Figure 3: The DI/IoC container in action.

 

You typically create an assembly where you put the base page class and the interfaces on which the application depends, such as IDataFinder. Next, you derive from the common base page each page where you need DI/IoC capabilities (see Figure 4).

 

public partial class TestPage : Samples.MyBasePage

{

 protected void Page_Load(object sender, EventArgs e)

 {

   // Retrieve the data finder object to use

   this.DataFinder = this.Resolve<IDataFinder>();

   if (this.DataFinder == null)

       return;

   // Use the data finder

   object data = this.DataFinder.GetData();

   GridView1.DataSource = data;

   GridView1.DataBind();

 }

}

Figure 4: A page that uses DI/IoC.

 

From a design perspective, all you do is decide on which external services your page depends and define a property for each. Next, you resolve the dependency through the container and go. To change the dependency, you don t need to touch the code you simply edit the configuration file.

 

Conclusion

Dependency injection has perhaps a high-sounding name, but hides a very handy practice. With the help of DI/IoC containers, applying dependency injection is really easy and effective. You do some configuration work and the framework of choice does the rest. I haven t mentioned some of the additional (and really powerful) features that some containers include I ll save that for another article.

 

Source code accompanying this article is available for download.

 

Dino Esposito is an architect at IDesign and specializes mainly in ASP.NET, AJAX, and RIA solutions. Dino is the author of Microsoft .NET: Architecting Applications for the Enterprise (Microsoft Press, 2008). He also wrote Programming ASP.NET 3.5 Core Reference, also for Microsoft Press. Late-breaking news is available at http://weblogs.asp.net/despos.

 

Personal Anecdote

It was 1994 and I was working on my first important project. It was a standalone Windows 3.1 application doing some nice stuff with image-based documents. We had (too) many customers asking regularly for various forms of customization. In the end, it was good business for the company. Customers were first buying a good number of licenses, then paying for extra customization. But it was a nightmare for the development team as we had to maintain slightly different versions of the codebase.

 

One Sunday morning I was shaving in front of the mirror when I realized my razor was broken. I had to locate and set up a second razor. And it worked just fine. So in the end, for just my face, I could use two razors interchangeably. This inspired me to consider a couple of new options for the software. (Again, it was 1994 and the DIP was still to come.) Monday morning I shared the shaving experience with the rest of the team and we promptly arranged two equally valid options. In a nutshell, the problem was extending some menus with extra features, but in a way that we could maintain one codebase and sell specific pluggable extensions.

 

The first option we considered was defining a CreateMenu function (no classes and no OOP at the time for us) reading the standard menu from resources and extra items from a configuration file. The second option was passing the list of extra items to the CreateMenu function. Basically, the point was: where should the loading code go? We opted for what we considered the most packaged solution CreateMenu does it all. We opted for Plugin versus Dependency Injection. Today, the burden of the loading code is being taken care of by DI/IoC containers.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish