Sunday 11 November 2012

ASP.NET MVC 4.0. Controller out of scope of persistence implementations

These MVC small entries are focused on showing how to develope a n-layer-based application by following same important design patterns: Inversion of control pattern, Data Transfer Object pattern and Data Access Object pattern.

In this example, Unity 2.0 will be our Inversion of Control container.

In order to show the complete n-layer decoupled architecture, our first persistence implementation will be based on static developer information. The goal of this first approach is to show how the persistence layer can be decoupled from the Controller and therefore from the Presentation layer. In addition, business layer is comprised of business services which use the persistence implementation via Dependecy injection pattern implementation. This last concept is provided by the unity Container.

Our recipe has the following ingredients:

·         Inversion of control and Dependency Injection, provided by Unity 2.0 container.

·         Data transfer objet pattern, provided by an assembly which is made up of DTO objects.

·         Data Access Object pattern provided by an assembly containing the Interface required for persistence contract definition and an single file-based implementation of a specific persistence operation.

·         Model View Controller pattern implemented by the ASP.NET MVC piece of this architecture.

The steps we are going to follow are outlined below:

1) Firstly, I create a new assembly comprised of DTO objects to decouple Presentation layer from persistence layer.

2) The second step is to create an assembly providing the DAO classes and a basic and non-real persistence operation which just delivers specific and static developer information.

3) The third step creates the sevices assembly.

4) Finally, I focus my effort in creating a new ASP.NET MVC empty project. This project implements the MVC pattern directly, and the IoC and Dependency Injection via Unity 2.0.

I assume that creating Dll Library projects is not a problem and indeed it is well-known.

Creating a DTO object representing the decoupled model of this example is the first stage of this example.

The most important part of this assembly is the DTODeveloper class that represents the Developer entity without persistent-linked mechanisms.

namespace ModelBasedonPatterns

{

    [Serializable]

    public class DTODeveloper

    {

        public string Name { get; set; }

        public string IdentityCard { get; set; }

        public int Age { get; set; }

       

    }

}

 

The following assembly contains a Developer basic class that represents an Entity coupled with the persistence implementation.

 

It is important to see our basic and non realistic persistence implementation. In this case, in order to show the goal of this entry clearly, the only persistence method implemented is the one that obtain static information of a specific developer.

The DAO pattern implementation is implemented as below is shown:

namespace DaoBasedonPatterns

{

    public interface IDAOBase

    {

        object GetEntity();

    }

}

 

namespace DaoBasedonPatterns

{

    public class DAODeveloper :IDAOBase

    {

        #region IDAOBase Members

 

        public object GetEntity()

        {

            Developer developer = new Developer();

            developer.Age = 12;

            developer.Name = "Fernando";

            developer.IdentityCard = "11-1111";

            return developer;

        }

 

        #endregion

    }

}

 

 

As you can see , the implementation is very easy. The class DAODeveloper implementing the elemental persistence operation. This class implements the DAOBase interface providing the common operations to each DAO-related classes associated to a specific entity. In this case, DAODeveloper is associated to the Developer entity representing the information of a developer in the system (in this case, there is not real persistence operations, but in the following examples will see how providing several persistence implementations in order to show that they do not neither affect nor provoke changes in the Controller layer.

The services will use this DAO classes to invoke the persistence operation needed to execute the business logic.

 

The service implemented is the following:

namespace ServicesBasedonPatterns

{

    public class DeveloperService :IDeveloperService

    {

 

        #region IService Members

 

        public int ObtainServiceVersion()

        {

 

            return 1;

        }

 

        #endregion

 

        #region IDeveloperService Members

 

       

        public DTODeveloper GetDeveloper()

        {

            Developer dev= (Developer)this.DAOImpl.GetEntity();

           

            return (DTODeveloper)EntityToDto(dev);

 

 

 

        }

 

        #endregion

        #region Dependency Injection DAO

       

        public IDAOBase DAOImpl { set; get; }

 

 

        #endregion

 

 

        #region IService Members

 

 

        public object EntityToDto(object entity)

        {

            Developer dev = (Developer)entity;

            DTODeveloper dtoDev = new DTODeveloper();

            dtoDev.Age = dev.Age;

            dtoDev.IdentityCard = dev.IdentityCard;

            dtoDev.Name = dev.Name;

            return dtoDev;

       

        }

 

        #endregion

    }

}

 

The developer service implements the following interface.

 

namespace ServicesBasedonPatterns

{

    public interface IDeveloperService :IService

    {

        DTODeveloper GetDeveloper();

 

    }

}

 

namespace ServicesBasedonPatterns

{

    public interface IService

    {

        int ObtainServiceVersion();

        object EntityToDto(object entity);

    }

   

}

 

The business logic is very simple and yet you can see how the service use the DAO classes to decouple persistence operations from the Presentation layer.

The property

public IDAOBase DAOImpl { set; get; }

 

permits the service to abstract the persistence operations from the business logic definition. The property is injected via Unity Framework in the following way.

  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">

    <namespace name="DaoBasedonPatterns" />

    <namespace name="ServicesBasedonPatterns" />

    <assembly name="ServicesBasedonPatterns" />

    <assembly name="DaoBasedonPatterns" />

 

    <container>

      <!-- DAO implementation-->

      <register type="IDAOBase" name ="developerDAO"  mapTo="DAODeveloper"/>

 

      <!-- Developer service -->

      <register type="IDeveloperService" name="developerService" mapTo="DeveloperService">

        <property dependencyName="developerDAO" name="DAOImpl" dependencyType="IDAOBase"/>

      </register>

 

    </container>

  </unity>

 

This chuck of configuration tags is included in the Web.config file of the ASP.NET MVC project. When the Controller needs to get a instance of the service the container hands over the instance and injects the DAO developer instance to the properly DAOImpl.  The controller uses for this a Factory provider class. This static class instantiates the container and then gets the proper instance requested by the Controller.

Now, it is time to create the ASP.NET MVC 4.0 project from scratch.

The first step is to create a new ASP.NET MVC 4.0 empty project.

In this case, I see as a good practice to create a Test project as well in order to test the Controller. As an architected I am, I guess Unit tests must be defined to enrich the quality of the development lifecycle of the projects.

 

 

 

You must add the  Model assemby reference to use the DTODeveloper type.

 

 


 

 

Now, it is time to create a new Controller. In this case, following the default routing definition of MVC framework, I create the HomeController and add a new action called showDeveloper.

 

 

I select the empty controller because the rest of the options do not decouple the model from the Controller layer.

Then I create a view associated with the method showDeveloper of the HomeController controller.

 

The view has the following aspect:

 

@model ModelBasedonPatterns.DTODeveloper

<html>

<head></head>

<body>

@{

      

    ViewBag.Title = "ShowDeveloper";

}

 

 

<h2>ShowDeveloper</h2>

<p> @Model.Age </p>

<p> @Model.IdentityCard</p>

<p> @Model.Name</p>

</html>

</body>

 

 

 

As you can see, it is only display the developer’s information.

Here you can inspect the Controller implementation.

namespace MVCPatterns.Controllers

{

    public class HomeController : Controller

    {

        //

        // GET: /Home/

 

        public ActionResult Index()

        {

            return View();

        }

 

        // GET: /Home/ShowDeveloper/

        public ActionResult ShowDeveloper()

        {

            IDeveloperService dev =(IDeveloperService) FactoryProvider.getInstance(typeof(IDeveloperService), "developerService");

           

            DTODeveloper d = dev.GetDeveloper();

          

            ViewBag.DTODeveloper = d;

 

 

            return View(d);

 

        }

 

    }

}

 

As you can see, the implementation of the showDeveloper method firstly request a instance of the DeveloperService via the Factory Provider, and then obtain the “persisted” information of the Developer. In this case, be aware that the Developer entity class defined in the DAO assembly is not an entity of the MVC model. Instead, the model is made up of the DTODeveloper type which has not persistence information or mechanisms.

The view associated to this controller just shows the Developer information as follow:

The Factory provider is implemented as follow.

namespace MVCPatterns.Tools

{

    public static class FactoryProvider

    {

        private static IUnityContainer container;

        public static Object getInstance(Type type, string name)

        {

            if (container == null)

            {

                container = new UnityContainer();

              

 

               

                container.LoadConfiguration((UnityConfigurationSection)ConfigurationManager.GetSection("unity"));

 

                Object obj = container.Resolve(type, name);

                return obj;

            }

            else

            {

                Object obj = (Object)container.Resolve(type, name);

                return obj;

 

            }

 

        }

    }

}

 

As you can see, Unity container is instantiated and the configuration definition specified within the Web.config file is loaded. When from the controller the developer service is required, the unity container proceed to return the instance of the DeveloperService injecting the DAO implementation properly.

To sum up, you can see that the Controller layer is decoupled from the business implementation and persistence mechanisms.

To execute the example, I use the option “View in browser” from the MVCPattern project. Then I type in the explorer the following url in order to execute the showDeveloper functionality.

http://localhost:port/Home/ShowDeveloper

The result is the following:

In order to define a simple unit test for the method showDeveloper a option could be the following below:

namespace MVCPatterns.Tests

{

    [TestClass]

    public class DeveloperControllerTest

    {

        [TestMethod]

        public void testShowDeveloper()

        {

            try

            {

                // get the controller

                HomeController homeController = new HomeController();

                // execute the showDeveloper Method

                ViewResult viewResult = (ViewResult)homeController.ShowDeveloper();

                //Get the model

                DTODeveloper dtoDeveloper = (DTODeveloper)viewResult.Model;

                // validate the name of the developer

                Assert.AreEqual("Fernando", dtoDeveloper.Name);

 

            }

            catch (AssertFailedException e)

            {

                // failed the test

                Assert.Fail("the developer name has changed");

 

            }

           

           

        }

    }

Once you execute the test with the Visual Studio environment, you obtain the following result: