Ryan LanciauxNew Media Mercenary

Very Quick and Simple Dependency Injection with StructureMap

February 26, 2008 by ryan

There are a lot of resources on the web about dependency injection and using StructureMap, however, I wanted to write something that was an extremely simple example. This is basically the tip of the iceberg but hopefully it will help someone. 

We want to make our application very loosely coupled -- to achieve this 'loose coupling' we're going to have several projects in the solution. What this means if we need to change any part of this application later on (we wouldn't want to in this case since its a demo and all), we could do so without impacting everything else. Anyways, we're going to create three class libraries and a WinForms application.

Next we want to create our main inteface -- this will be under the DisplayMessage Project:

 

namespace DisplayMessage

{

    public interface IDisplayMessage

    {

        string message();

    }

}

The interface defines just one method that, when implemented, will return a string stating what class its coming from. Next, we want to create our two implementation classes (one under Implementation1, the other under Implementation2). Please keep in mind I'm not suggesting to have every class in it's own library -- it's just for the sake of example :)

Implementation1:

    public class MessageOne : IDisplayMessage

    {

        public string message()

        {

            return "This is a message from Implementation1";

        }

    }

 Implementation2:

    public class MessageTwo : IDisplayMessage

    {

        public string message()

        {

            return "This is a message from Implementation2";

        }

    }

Okay that was easy enough, now on to the Forms App.  We're first going to add a reference to StructureMap and the project DisplayMessage and create a file called StructureMap.config -- this config file is going to define all of our assemblies. We want to make sure we edit the properties of this file and set the Copy to Output Directory option to "Copy Always." StructureMap will use this file at runtime to get our object references. The config file looks like this: 

<?xml version="1.0" encoding="utf-8" ?>

<StructureMap>

  <Assembly Name="DisplayMessage" />

  <Assembly Name="Implementation1" />

  <Assembly Name="Implementation2" />

 

  <PluginFamily Type="DisplayMessage.IDisplayMessage"

                Assembly="DisplayMessage"

                DefaultKey="MessageOne">

    <Plugin Type="Implementation1.MessageOne"

            Assembly="Implementation1"         

            ConcreteKey="MessageOne" />

    <Plugin Type="Implementation2.MessageTwo"

                Assembly="Implementation2"

                ConcreteKey="MessageTwo" />   

  </PluginFamily>

</StructureMap>

Notice we define a PluginFamily for the IDisplayMessage interface and set the default implementation to be MessageOne (the DefaultKey of PluginFamily references the ConcreteKey of the Plugin). Other than that, this should be pretty straight-forward but if you have any confusion, please check out the StructureMap documentation. Only a couple more things to do before we can run this...

Ok, we're going to add 3 buttons to our form -- one for the default IDisplayMessage and one for each implementation.

 Now to add the code...

        //Default IDisplayMessage 

        private void btnDefault_Click(object sender, EventArgs e)

        {

            IDisplayMessage msg = StructureMap.ObjectFactory.GetInstance<IDisplayMessage>();

            System.Windows.Forms.MessageBox.Show(msg.message());

        }

 

        //Implementation1

        private void btnOne_Click(object sender, EventArgs e)

        {

            IDisplayMessage msg = StructureMap.ObjectFactory.GetNamedInstance<IDisplayMessage>("MessageOne");

            System.Windows.Forms.MessageBox.Show(msg.message());

        }

 

        //Implementation2

        private void btnTwo_Click(object sender, EventArgs e)

        {

            IDisplayMessage msg = StructureMap.ObjectFactory.GetNamedInstance<IDisplayMessage>("MessageTwo");

            System.Windows.Forms.MessageBox.Show(msg.message());

        } 

Lets parse this up a little bit...

  • IDisplayMessage msg = StructureMap.ObjectFactory.GetInstance<IDisplayMessage>();

    This statement gets the default IDisplayMessage object in the StructureMap.config file. Currently, it will get the same object as getting a named instance of "MessageOne"
  • IDisplayMessage msg = StructureMap.ObjectFactory.GetNamedInstance<IDisplayMessage>("MessageOne");

    This statement gets the object associated with the ConcreteKey "MessageOne"
  • IDisplayMessage msg = StructureMap.ObjectFactory.GetNamedInstance<IDisplayMessage>("MessageTwo");

    This statement gets the object associated with the ConcreteKey "MessageTwo"

Instead of simply hitting F5, we will need to build the application -- we want to copy the DLL files from Implementation1 and Implementation2 to the bin directory of the forms app and run the executable there.  For testing, however, we can add a reference to both projects (this completely defeats the purpose of dependency injection so be sure to remove the references later on) or adjust the output directory of the implementation class libraries to be the same as the Form application's bin directory. Running the application shows that everything is working as expected.

For more information please check out the following links:

kick it on DotNetKicks.com



Related posts

Comments

February 27. 2008 08:32

Justin Etheredge

Nice post, but you gotta work on the formatting of your code. It makes it impossible to read your samples.

Justin Etheredge

February 27. 2008 08:39

ryan

Thanks Justin -- I changed the theme, I had some weird things going on with BlogEngine.Net last night. Maybe this is better?

ryan

February 27. 2008 11:07

Justin Etheredge

Much much better.

Justin Etheredge

February 27. 2008 20:18

SimonTeW

A suggestion to avoid having to manually copy the DLLs from Implementations 1 & 2 to the forms app bin directory (I've previously run into exactly the same problem):

In each implementation project, set the build output path (on the Build tab of the project properties) to point to the directory you want the DLLs to end up in.

You'll need to do this twice for each implementation project, once for the Release configuration and once for the Debug configuration.

For example, assuming the implementation project and the forms project are in separate sub-directories of the StructureMapDemo directory, set the Release build output path for each implementation project to: ..\DemoMain\bin\Release (type it as written here - relative paths are allowed). Similarly, set the Debug build output path to ..\DemoMain\bin\Debug.

Now the implementation project DLLs will be saved to the correct directory automatically when you build the projects.

SimonTeW

February 28. 2008 08:06

Razan Paul

U kicked a good thing. It is helpful.


But one thing here in the country drop down list i have not found my country name(Bangladesh).

Please add my country(Bangladesh).

Razan Paul

April 9. 2008 11:43

Ed

Ryan,

If I place each of my implementations in a different project / library / assembly then am I to add IDisplayMessage to each project too? Otherwise I need to reference the DisplayMessage assembly, thus increasing coupling and defeating the purpose of using an IoC Container?

I'm not sure how best to proceed I don't want to reference the abstract types assembly from each concrete types assembly nor do I want to copy and paste the abstract type to each assembly. I have to go down one of these routes. Don't I?

Evidently I'm confused! Could you point me in the right direction?

Thank you.

Ed

September 12. 2008 11:53

Terry

Ed,

You're not as confused as you think. I don't know if you've found the answer to your question yet or not, but for the benefit of others who may follow...

If you simply copy the source code for the IDisplayMessage into each project, then they will become different interfaces and will not be interchangable. You should instead, as you hinted in your second paragraph, define all of your interfaces into an abstract types assembly, and reference that assembly from each of the other assemblies that need it.

Another thing that I commonly do in my abstract type assembly is provide a "Null" concrete class that can be used when no other instance is specified. This class implements the interface, but implements no more functionality than absolutely required for the class to function without errors.

For instance, if I have an ILogEvent interface, I provide a NullLogEvent concrete class that does nothing. Then if no other concrete class has been provided for a property of type ILogEvent, I return an instance of the NullLogEvent class rather than returning null. By doing this, I never have to check to see if the property value is null. Specifying a default concrete type in your DI engine largely covers this, but sometimes its nice to simply have an implementation that does nothing.

Terry

September 12. 2008 12:01

Ed

Yes Terry,

I did go down that route. I have a Contracts assembly, which has the interfaces for my services.

Thanks for your comments.

Ed

Ed

September 25. 2008 21:07

pingback

Pingback from programandoem.net

Programando em .NET » StructureMap - Uma Injeção de Dependências

programandoem.net

November 30. 2008 22:56

pingback

Pingback from codebetter.com

A Gentle Quickstart for StructureMap 2.5 - Jeremy D. Miller -- The Shade Tree Developer

codebetter.com

November 30. 2008 23:48

pingback

Pingback from feeds.feedburner.com

A Gentle Quickstart for StructureMap 2.5 - Jeremy D. Miller -- The Shade Tree Developer

feeds.feedburner.com

December 2. 2008 10:16

pingback

Pingback from taccato.com

A Gentle Quickstart for StructureMap 2.5 - taccato! trend tracker, cool hunting, new business ideas

taccato.com

July 13. 2009 15:35

pingback

Pingback from answerspluto.com

list of urls 4 « Answers Pluto

answerspluto.com

Comments are closed




© 2008 Ryan Lanciaux :: powered by BlogEngine.NET