Click here to Skip to main content
Click here to Skip to main content

Plug & Play (DI) using Spring.net Framework

, 16 Mar 2014
Rate this:
Please Sign up or sign in to vote.
Plug & play using Spring.net Framework, We will also see how we can wire our application using Spring.Net Configuration

Introduction

In this article, we will be looking at some of the issues we face when we create direct dependence on other class & how these issues can be resolved using spring.net. We will also look at how we can wire all our class / layers together by using spring.net configuration. The sample code for this article is written using Visual Studio 2013 but it doesn't have any dependence on Visual Studio version. You will have to select appropriate spring.net version if you are configuring spring.net DLLs manually.

I would like to get feedback on this article. Please feel free to share your comments or you can also email me at shettyashwin@outlook.com. If you like this article, please don't forget to rate it.

Direct Dependence

To demonstrate direct dependence, I have created a sample application. This sample application is a console app. Console application is something which is going to interact with the external world. Console application takes in customer ID. Remaining logic is managed by 3 layers below it. These three layers are Façade layer, Business layer & Data Layer.

internal class Program
    {
        public static void Main()
        {
            Console.WriteLine("Enter customer id & press enter");
            int customerId = Convert.ToInt32(Console.ReadLine().ToString());
            DoWork doWork = new DoWork();
            doWork.DoProcessingWork(customerId);
            Console.ReadLine();
        }
    } 

Façade Layer will be used to orchestrate validation process & then to add customer id on successful execution of validation via Business layer.

 public class DoWork 
    {
        public DoWork()
        {} 

        public virtual void DoProcessingWork(int customerId)
        {
            CustomerProcessor _processor = new CustomerProcessor();
            if (!IsCustomerValidate(customerId))
            {
                Console.WriteLine("Adding new customer ID");
                _processor.Add(customerId);
            }
            else
            {
                Console.WriteLine("Customer Id should be greater than 10");
            }
        }
 
        public virtual bool IsCustomerValidate(int customerId)
        {
            CustomerValidate _CustomerValidate = new CustomerValidate();
            return _CustomerValidate.ValidateCustomer(customerId);
        }
    } 

Business layer will interact with data layer for validating the customer Id & then to add it.

 public class CustomerProcessor
    {
        public void Add(int customerId)
        {
            Customer _customer = new Customer();
            if(customerId < 1) throw new Exception("Customer Id can't be less 1");
            _customer.Add(customerId);
        }
    } 

  public class CustomerValidate
    {
        public virtual bool ValidateCustomer(int customerId)
        {
            Search _search = new Search();
            return _search.IsCustomerIdRegistered(customerId);
        }
    }  

Since I have created this application for demo purposes, I will not be creating database. I have hardcoded customer Id for validation & when customer id is added via data layer, it will write a message back to console. Writing directly on console wouldn’t be the ideal solution, but we can ignore it for now.

public class Search 
    {
        public bool IsCustomerIdRegistered(int customerId)
        {
            if (customerId < 10)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    } 
 public class Customer 
    {
        public void Add(int customerId)
        {
            Console.WriteLine("Added new Customer Id :" + customerId.ToString());
        }
    } 

Below sequence diagram will give some idea about the layer & how process flows.

Problem Areas

  1. Console Application, Façade Layer & Business Layer are directly creating instance for their reference
  2. All the classes / layers are tightly bound to each other. For mapping it to different class / layer, we will have to make code changes
  3. Writing unit test case would be problematic since we will not be able to mock any of the layers directly.
  4. Applying Customized logic for different customers would be difficult. This will involve lots of ifs & buts in the code which will reduce maintainability.

What is Spring.Net

Spring.net is an open source application framework for building enterprise .NET application. It has been evolved from Java version of Spring framework. It allows you to remove incidental complexity when using the base class libraries makes best practices. You can get more details on Spring.net from here.

For demonstration purposes, in this article we will be using Spring.Core which supports Dependency Injection.

DI Solution using Spring.Net

To solve the problems mentioned above, we have to use Dependence injection. For dependence injection, I will be using Spring.Net framework. By using Spring framework, we will be creating application context. All the classes which we require for processing the data would be preconfigured & object instance shall be created using Application context. We will proceed step by step to achieve this. But first, we need to get the required spring reference together.

To get spring.net reference DLL, I have used NuGet. Nuget manager does setup all the required reference in Console Application. Other layer will not require spring DLL reference since we will be wiring them all together using app.configuration file in Console Application.

In app.config, we will have to mention section, context & object collection details. This is how we configure section details in app.config.

<configSections>
   <sectionGroup name="spring">
     <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
     <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
   </sectionGroup>
</configSections> 

Now we can go ahead and create a separate section in app.config. As mentioned above, I have created spring section in console application app.config.

 <spring>
    <context>
      <resource uri="config://spring/objects"/>
    </context>
    <objects xmls="http://www.SpringFramework.net">
      <object name="BusinessDoWork" 
      type="SpringSample.BusinessLayer.CustomerValidate, 
      SpringSample.BusinessLayer" singleton="false">
        <property name="Search" ref="DataLayerSearch"/>
      </object>
      <object name="BusinessCustomerProcessor" 
      type="SpringSample.BusinessLayer.CustomerProcessor, 
      SpringSample.BusinessLayer" singleton="false">
        <property name="Customer" ref="DataLayerCustomer"/>
      </object>
      <object name="FacadeCustomer" 
      type="SpringSample.FacadeLayer.DoWork, SpringSample.FacadeLayer" 
      singleton="false">
        <constructor-arg ref="BusinessDoWork"/>
        <constructor-arg ref="BusinessCustomerProcessor"/>
      </object>
      <object name="FacadeCustomerValidate" 
      type="SpringSample.FacadeLayer.DoWork, SpringSample.FacadeLayer" 
      singleton="false">
        <constructor-arg ref="BusinessDoWork"/>
      </object>
      <object name="DataLayerSearch" 
      type="SpringSample.DataLayer.Search, SpringSample.DataLayer" 
      singleton="false"/>
      <object name="DataLayerCustomer" 
      type="SpringSample.DataLayer.Customer, SpringSample.DataLayer" 
      singleton="false"/>
    </objects>
  </spring> 

Inside spring section, you can see two sub sections (Context & objects). Context defines the location from where objects need to be loaded / mapped. Spring.net can also load object from external source such as XML file. Hence we will have to specify configured location from where objects & its relation can be loaded. Objects sub section define the instance & its mapping. I will explain this section in detail once we visit the changes we have made.

Other important change we will have to do as a part of dependence injection is to define contract & then implement it in classes we have created. In the current sample, I have created contract using interface but you can also achieve this using abstract class if you have common logic to share upon. These contracts are created in separate project so that logic & contract stay in separate assembly.

public interface ICustomerProcessor
    {
        ICustomer Customer { get; set; }
        void Add(int customerId);
    } 

public interface ICustomerValidate
    {
        ISearch Search { get; set; }
        bool ValidateCustomer(int customerId);
    }

 public interface ICustomer
    {
        void Add(int customerId);
    } 

 public interface ISearch
    {
        bool IsCustomerIdRegistered(int customerId);
    }

public interface IDoWork
    {
        void DoProcessingWork(int customerId);
        bool IsCustomerValidate(int customerId);
    }  

Just to show variety of injections, I have created additional properties in ICustomerProcessor (Customer) & ICustomerValidate (Search). In Business layer, we will be using property injection & Façade layer we will injecting objects using constructor. Data Layer won’t change much, only change you see is the inheritance of ISearch & ICustomer interface.

 public class Customer : ICustomer
    {
        public void Add(int customerId)
        {
            Console.WriteLine("Added new Customer Id :" + customerId.ToString());
        }
    }

 public class Search : ISearch
    {
        public bool IsCustomerIdRegistered(int customerId)
        {
            if (customerId < 10)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

This is how we configure data layer in spring.net configuration in app.config:

 <object name="DataLayerSearch" 
    type="SpringSample.DataLayer.Search, 
    SpringSample.DataLayer" singleton="false"/>
      <object name="DataLayerCustomer" type="SpringSample.DataLayer.Customer, SpringSample.DataLayer" singleton="false"/> 

Also in Business Layer, we will inherit the interface we have to created for business layer (ICustomerProcessor & ICustomerValidate) & change the logic for object creation. Hereafter, we will not create any object but we will be referring to the object injected into properties. Also note that we will remove reference to Data Layer project. from Business Layer Project. Since we will only write our code against the interface signature, we need to add reference to contract project.

 public class CustomerProcessor : ICustomerProcessor
    {
        public ICustomer Customer { get; set; }

        public void Add(int customerId)
        {
            if(customerId < 1) throw new Exception("Customer Id can't be less 1");
            Customer.Add(customerId);
        }
    }

 public class CustomerValidate : ICustomerValidate
    {
        public ISearch Search { get; set; }

        public virtual bool ValidateCustomer(int customerId)
        {
            return this.Search.IsCustomerIdRegistered(customerId);
        }
    }

Spring Configuration for the same would look like this. I have added property tag which refers to object store created for Data Layer. When object for Business Layer is created, Spring.net will inject the data layer object based upon the reference.

<object name="BusinessDoWork" type="SpringSample.BusinessLayer.CustomerValidate, SpringSample.BusinessLayer" singleton="false">
    <property name="Search" ref="DataLayerSearch"/>
</object>
<object name="BusinessCustomerProcessor" 
type="SpringSample.BusinessLayer.CustomerProcessor, 
SpringSample.BusinessLayer" singleton="false">
    <property name="Customer" 
    ref="DataLayerCustomer"/>
</object> 

Same changes need to be done with Façade layer. Newly created interface will be inherited & object creation logic will be removed. In Façade layer object will be injected using Constructor. Similar to Business layer project, we will remove reference for Business Layer & Data Layer and add reference to Contract project in Façade Layer.

 public class DoWork : IDoWork
    {
        protected ICustomerValidate _CustomerValidate;
        protected ICustomerProcessor _processor;
        public DoWork(ICustomerValidate customerValidate, ICustomerProcessor processor)
        {
            _CustomerValidate = customerValidate;
            _processor = processor;
        }

        public DoWork(ICustomerValidate customerValidate)
        {
            _CustomerValidate = customerValidate;
        }

        public virtual void DoProcessingWork(int customerId)
        {
            if (!IsCustomerValidate(customerId))
            {
                Console.WriteLine("Adding new customer ID");
                _processor.Add(customerId);
            }
            else
            {
                Console.WriteLine("Customer Id should be greater than 10");
            }
        }

        public virtual bool IsCustomerValidate(int customerId)
        {
            return _CustomerValidate.ValidateCustomer(customerId);
        }
    }

This is how we configure Façade layer in spring configuration in app.config. For injecting object via constructor, I have added constructor-arg tag. This tag informs spring.net to inject dependence object with key name mentioned in ref attribute.

<object name="FacadeCustomer" type="SpringSample.FacadeLayer.DoWork, SpringSample.FacadeLayer" singleton="false">
        <constructor-arg ref="BusinessDoWork"/>
        <constructor-arg ref="BusinessCustomerProcessor"/>
</object>

In Spring.net, we can choose either or constructor for creating object. This can only be achieved based upon the parameter you configure for object creation. I have created a separate constructor in Façade layer for validation. If logic demands to get only validation result, then this can be achieved using single parameter constructor. Configuration for the same in app.config will look like this:

<object name="FacadeCustomerValidate" type="SpringSample.FacadeLayer.DoWork, SpringSample.FacadeLayer" singleton="false">
        <constructor-arg ref="BusinessDoWork"/>
</object> 

By referring all the objects via constructor / property, we have removed direct dependence. Objects are now been injected. None of the classes create their own object but they refer them via constructor or properties. Entire flow is been glued by configuration file. Since this class / layers are not directly linked, they can be twisted as per our requirement. Only part remaining now is to link façade layer with UI. This is how we achieve it.

internal class Program
    {
        public static void Main()
        {
            IApplicationContext appContext = ContextRegistry.GetContext();
            Console.WriteLine("Enter customer id & press enter");
            int customerId = Convert.ToInt32(Console.ReadLine().ToString());

            IDoWork doWork = appContext["FacadeCustomerValidate"] as IDoWork;
            doWork.IsCustomerValidate(customerId);

            doWork = appContext["FacadeCustomer"] as IDoWork;
            doWork.DoProcessingWork(customerId);

            Console.ReadLine();
        }
    } 

By using ContextRegistry, we get ApplicationContext. All the objects instance we need for processing user input we get it via ApplicationContext. We need to pass the KeyName we have configured it in App.Config.

For writing test case using MOQ, you can refer to my other article TDD using MOQ.

Points of Interest

In this article, we did see how we can remove direct dependence & wire all layers together using spring.net configuration. Hopefully, this might have given some idea how we can decouple class / layer. Decoupling of class / layer becomes important when we foresee lot of customization. This strategy also becomes helpful when we need to write 100% testable code.

References

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Ashwin. Shetty
Architect STC
India India
I have 11 years of experience in Microsoft Technology. My complete profile is available at http://www.linkedin.com/in/ashwinshetty
Follow on   Twitter   LinkedIn

Comments and Discussions

 
QuestionSource code file missing PinmemberTridip Bhattacharjee17-Mar-14 21:26 
AnswerRe: Source code file missing PinmemberAshwin. Shetty17-Mar-14 22:34 
NewsRe: Source code file missing PinmemberAshwin. Shetty17-Mar-14 23:50 
Question[My vote of 2] suggestion Pinmemberbryce16-Mar-14 19:55 
AnswerRe: [My vote of 2] suggestion PinmemberAshwin. Shetty16-Mar-14 20:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 16 Mar 2014
Article Copyright 2014 by Ashwin. Shetty
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid