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: