Skip to content

Well-architected application development with code

This post helps to understand the process of well-architected application development and architecting a software project from requirement to a fully functional decoupled layered architecture.

It will not be focusing on the theoretical part of business analysis such as user stories or use cases. Also, won’t be diverting the attention to creating a web application to avoid dealing with UI components like HTML, javascript, CSS, etc. This post will work on the core concepts of object-oriented programming. It explores on how to implement various design patterns and use various architectural principals in a project to make it decoupled and easier to understand code. This project will aim to create a well-formatted template with decoupled architecture that can be implemented in any new project to get up and running quickly.

Requirements – ABC Pet Shop

“ABC Pet Shop” is a pet shop chain located in Sydney and Melbourne. The pet shop requires a simple customer management system for their retail outlets with the following features in 1st phase.

Phase 1 – requirements:

  1. The application will require 5 fields, Full Name, Phone Number, Bill amount, Bill Date, and Customer Address.
  2. There are two types of customers that come to the pet shop. 1. Customer, 2. Visitor
    1.  A customer is a person who comes and buys things from a shop and is involved in a financial transaction. All the fields mentioned in 1 are mandatory for customers.
    2. A visitor is a person who comes to the pet shop for inquiry but doesn’t buy anything at that moment. Only a Full Name and Phone number are mandatory for a visitor.
    3. The system should be able to add types of customers if required in future
  3. The System should be able to:
    1. Add new validation rules seamlessly and these validation rules should be flexible and reusable to the system.
    2. The system should have the ability to display, add, update and delete customer data.
    3. Currently, the system should be using SQL server and ADO.net as data layer and in coming months be able to migrate to Entity Framework. Migration should be seamless without many changes across the system.
    4. The system should have the ability to cancel any modification done to the screen which means if we are editing a record and changing values, we should be able to revert to the old values.

This is the initial requirement for Phase-1 of the project. Now to proceed with these requirements, it is essential to understand some basic concepts of object-oriented principles (oop) to identify the classes.

What is an Entity?

“An entity is a thing with distinct and independent existence”. Entities are things that we see in the real world like nouns (eg. person, place, or things). In an object-oriented perspective, an entity object represents an object in the real-world problem domain. So in this post, the object or entities will be used as synonyms.

Well-architected application development steps

Step 1- Identify an Entity or Objects of your system?

Software is primarily developed to solve real-world problems and provide automation to real-world scenarios and people. A software code should replicate real-world entities to its objects, for instance, a supplier that supplies goods in the real world then the software code should have an entity called Supplier. To identify entities/objects we need to identify nouns from a functional specification or a user story. Nouns become entities, a verb becomes actions for entities and pronouns become the properties and behaviour for those entities.

In the requirement above there are the following nouns:

Sydney, Melbourne, Customer, Visitor, Pet Shop

There is a common practice used by architects to follow nouns, verbs, and pronouns but an architect must be careful on not to pick unwanted nouns and verbs that don’t relate to the system. In the above list of nouns, Sydney and Melbourne are cities and have no direct connection with other system requirements. The only useful nouns are Customer and Visitor which is where the requirement is asking to do actions like validate, Add, Update and delete.

What is Class?

In OOP a class is a blueprint (or template) for creating objects. Class acts as a template that defines the nature of a future object, which should contain the object’s name, actions, and properties.

Three-phase processes of OOP

OOP is a three-phase process namely: –

  • Template Creation: – Creating classes and writing logic in those classes.
  • Instantiate: – Create entities/objects of these classes and bring them to live in RAM / Computer.
  • Run: – Interact with these objects to achieve the software functionality.

A software architect / a software developer would encounter common/recurring design problems in all three of these phases and Design Patterns has solutions to these problems. The design patterns are divided into three categories that cover these phases: –

OOP Phase Design Pattern Category
Template / Class Creation Structural Design Pattern
Instantiation problems Creational design pattern
Runtime problems Behavioral design pattern

Create Customer Class with properties and actions (methods) in Visual Studio by adding a Class Library called “CustomerLibrary” in solution “ABCPetShop”.

Step 2 – Identify Relationship between two entities.

In the real world these entities have mainly two relationships “IS A” and “HAS A”. For example, the relationship between Father and Son is “IS A” relationship we can say “Father is a Son” but when we compare Father with a Car or Son with a Car then the relationship changes to “HAS A” relationship “Father has a Car” and “Son has a Car”.

In the requirement: “A visitor is a kind of Customer with fewer attributes” and so the Visitor class can inherit the properties from the Customer class. Inheritance is one of four basic concepts of OOP (Inheritance, Abstraction, Encapsulation, and Polymorphism)

One of the actions the Customer object has to do is to Validate, it has to make sure that all the attributes are filled for the customer and FullName and PhoneNumber is filled for the Visitor, therefore the validation methods should be different. That means we need to make sure the Validate method can be overridden (make is “Virtual”).

There is one more requirement that the system should be able to add a new type of customer in the future. This implies, the customer is not a Parent of a Visitor but is a type of customer so the parent is something else of types customer, visitor, and any other added customer type. Let’s call it a base class (CustomerBase) from which we can derive Customer, Visitor classes, and any other customer types.

CustomerBase is an incomplete class with properties and methods that can be derived by Customer and Visitor and use it as per their needs.

Step 3 – Designing the Application Architecture

In the process of well-architected application development, we have identified the entities (Domain classes). But the questions here are “what will these classes do?” and “How these classes will work for the system?”.

  1. Who is going to invoke these classes (define UI or Customer Context) to make them work?
  2. Once the work is finished by these entities who are going to store the work done by the classes (define Data Store or Persistent Context).

Presentation Layer defines User Interface (UI) to invoke the Business Layer that has entities/classes that represent real-world business objects (Domain) and Data Layer will store the entities.

Three Layer Architecture

Managing 3 layers (UI, domain, DAL) means “Change in one layer can have an impact on 3 places or more”. Therefore a decoupled architecture design is needed to avoid the conflict between these 3 layers.

Windows Forms Application for UI, class library for CusotmerLibrary (domain), and class library for DataAccess (DAL) is added in the project to make a 3 layer architecture:

Note: There is a term called Three Tier Architecture mostly being interchangeably used with Three Layer Architecture. There is the confusion that these two are the same but there is a vast difference between the two. Three-layered architecture has three logical layers separated but is hosted in the same physical machine, whereas in three-tier architecture all three logical layers are hosted in 3 different machines.

Step 4: Interface Design

(All the required names for the tools like text box, command buttons, etc are given accordingly)

Customer type separates the customer from the visitor and in the future, if additional types are added they will be listed accordingly and UI is referencing the Customer library (Domain Layer).

using System;
using System.Windows.Forms;
using CustomerLibrary;
namespace PetShop
{
    public partial class frmCustomer : Form
    {
        public frmCustomer()
        {
            InitializeComponent();
        }

        private void cmdAdd_Click(object sender, EventArgs e)
        {
            CustomerBase custbase = null;
            if (cboCustType.SelectedIndex==0)
            {
                custbase = new Visitor();
            }
            else
            {
                custbase = new Customer();
            }
            custbase.FullName = txtFullName.Text;
            custbase.Address = txtAddress.Text;
            custbase.PhoneNumber = txtPhoneNo.Text;
            custbase.BillDate = dtBillDate.Value;
            custbase.BillAmount = Convert.ToDecimal(txtBillAmount.Text);
        }
    }
}

The main problem in the above code:- What will happen if we add one more customer type?  the UI has to change every time a new customer type is added, this is a design problem that violates the SOLID design principles.

SOLID – is an acronym for the first five object-oriented design (OOD) principles by Robert C. Martin (Uncle Bob)

  • S – Single Responsibility Principle (SRP)
  • O – Open-closed Principle
  • L – Liskov Substitution Principle
  • I – Interface Segregation Principle
  • D – Dependency Inversion Principle

Single Responsibility Principle (SRP): This principle states that:

A class should have one and only one reason to change, meaning the class should have only one job. The synonym of SRP is Separation of concerns (SOC) which states that one class should do only its concerns and any unwanted tasks should be moved to some other class.

In the above code, the first principle of SOLID the SRP is violated, UI’s task is to fix the layout, receive inputs, and display outputs, however, it is tasked to create new Customer objects which is not its job.

The answer to this problem is to have an abstract (detached) class that separates the UI from performing unwanted tasks.

Step 5 – Decoupling the classes – Using Interfaces

To decouple UI with the customer classes the UI has to see the Customer Types in an abstract (detached) way rather than dealing with concrete classes. Abstraction – is one of the key concepts of object-oriented programming (OOP) whose main goal is to hide unnecessary details of the code only to show what is necessary.

The interface helps implement abstraction by creating pure definitions where UI will be pointing at not worrying about the implemented classes in the backend. An Interface class library (IcustomerLib) is added to achieve abstraction.

using System;

namespace ICustomerLIb
{
    public interface ICustomer
    {
        string FullName { get; set; }
        string PhoneNumber { get; set; }
        decimal BillAmount { get; set; }
        DateTime BillDate { get; set; }
         string Address { get; set; }
        void Validate();
        
    }
}

UI will reference to interface ICustomerLib and the CustomerBase class will implement the interface.

public class CustomerBase:ICustomer 
    {
        public string FullName { get; set; }
        public string PhoneNumber { get; set; }
        public decimal BillAmount { get; set; }
        public DateTime BillDate { get; set; }
        public string Address { get; set; }
        public virtual void Validate()
        {
            // Virtual function created so that it can be override by child class
            //let this be defined by child classes. 
        }

    } // .... No changes in any other code

IN UI code changes to use Interface Class: 

private void cmdAdd_Click(object sender, EventArgs e)
        {
            ICustomer iCust = null;
                        
            if (cboCustType.SelectedIndex==0)
            {
                iCust = new Visitor();                 
            }
            else
            {
                iCust = new Customer();                
            }
            iCust.FullName = txtFullName.Text;
            iCust.Address = txtAddress.Text;
            iCust.PhoneNumber = txtPhoneNo.Text;
            iCust.BillDate = dtBillDate.Value;
            iCust.BillAmount = Convert.ToDecimal(txtBillAmount.Text);
        }

Step 6 – Abstract classes  (Half Class – Not Full Class – Parent Class)

“CustomerBase” class is a base/parent class that defines all the properties but the methods are not fully defined and are open for modification by the child classes, which means the class is not complete and must not be used. To prevent creating an object of the “CustomerBase”, this class is made abstract. public abstract class CustomerBase:ICustomer UI is still not decoupled, it is creating the object of concrete classes and if these classes change modification in UI is needed. “O” of SOLID principle, states that designs should be “open for extension but closed for modification”, so more work is required to fix this for well-architected application development.

Step 7 – Use of Simple Factory Pattern (PIC pattern for decoupling)

The problem is “Classes should not create objects”. By shifting the task of creating the object from classes (the UI in this scenario) to a separate entity that will only be responsible for creating objects when required is the solution to the problem. The solution to this problem is addressed by Factory Design Pattern. A Factory whose job will be to create new objects by utilizing the PIC pattern (Polymorphism + Interfaces + Centralizing object Creation) is to be implemented. A class library called CustomerFactory with a Factory class containing Create method is created to return the type of customer object requested.

using System;
using ICustomerLib;
using CustomerLibrary;
namespace CustomerFactory
{
    public class Factory
    {
        public ICustomer Create(int CustomerType)
        {
            if (CustomerType==0)
            {
                return new Visitor();
            }
            else
            {
                return new Customer();
            }
        }
    }
}
Now the UI code looks much cleaner by only using the Factory object
private void cmdAdd_Click(object sender, EventArgs e)
        {
            ICustomer iCust = null;

            Factory oFactory = new Factory();
            oFactory = new Factory();
            iCust = oFactory.Create(cboCustType.SelectedIndex);

            iCust.FullName = txtFullName.Text;
            iCust.Address = txtAddress.Text;
            iCust.PhoneNumber = txtPhoneNo.Text;
            iCust.BillDate = dtBillDate.Value;
            iCust.BillAmount = Convert.ToDecimal(txtBillAmount.Text);
        }

The creation of entity objects or concrete objects is moved out of UI to Factory however there are more problems to fix:

  • Instead of creating Concrete objects in UI, the Factory is creating objects, so the problem is still not fixed but shifted to Factory, UI is now tightly coupled to the factory instead of the concrete classes. What if millions of users use UI at the same time? UI will create millions of factory objects which will be a disaster for system performance.
  • The factory is using IF, ELSE to decide which object to create, whenever a new entity is added to the system the factory has to change to address it.

Step 8 – Improve the performance of Factory Class

Problem:- Only one factory class is needed, which will instantiate all the concrete classes. “Singelton Pattern” has the solution to this problem.

Singleton Pattern:

Singelton Patterns falls into creational design patterns and is one of the most used patterns for situations in a project where only one instance of the object is to be created and shared between the clients. The steps to implement singleton pattern are:

  • Define the constructor as private – so that a new object can’t be created (or the whole class can be made Static to make it more strict)
  • Define methods static – to force just one instance to be created

Factory class implements Singelton Pattern with a private constructor and static method,  UI can directly call the method without the need to instantiate the Factory class.

namespace CustomerFactory
{
    //Simple Factory Pattern 
    // To improve perfomance we use singelton pattern so that it 
    // Can only be instantiated once

    public class Factory
    {
        private Factory()
        {
            //This is private constructor so that the object cannot be instantiated.

        }
        public static ICustomer Create(int CustomerType)
        {
            if (CustomerType==0)
            {
                return new Visitor();
            }
            else
            {
                return new Customer();
            }
        }

    }
}

Now in UI the code becomes more efficient and we have decoupled the UI layer from the concrete classes

  private void cmdAdd_Click(object sender, EventArgs e)
        {
            ICustomer iCust = null;
            Factory.Create(cboCustType.SelectedIndex);

            
            iCust.FullName = txtFullName.Text;
            iCust.Address = txtAddress.Text;
            iCust.PhoneNumber = txtPhoneNo.Text;
            iCust.BillDate = dtBillDate.Value;
            iCust.BillAmount = Convert.ToDecimal(txtBillAmount.Text);
        }

UI is now decoupled with the entity classes by using Factory pattern and Singelton pattern. There one more problem to fix,  removing “if then else” in Factory class, for that RIP design pattern has the solution.

Step 9 – RIP Pattern (Replace If with Polymorphism)

A best practice statement to keep in mind is “If there is polymorphism and if you see lots of IF conditions that mean polymorphism benefit is not exploited“. To remove it from the factory class we need to do three tasks. Task 1: Create a list of customers “ICustomer”.

 public static class Factory
    {
        private static List<ICustomer> customers = new List<ICustomer>();
        static Factory()
        {
            //This is private constructor so that the object cannot be instantiated.

            // load the type of customers here 
            customers.Add(new Visitor());
            customers.Add(new Customer());

        }
        public static ICustomer Create(int CustomerType)
        {
            return customers[CustomerType];
        }

    }
Task 2: Load customer types in the list of customers while loading the Factory class.

Task 3: Create a method that returns the type of customer by looking up the list by index. Due to polymorphism, the concrete customer classes get automatically typecast to a generic interface.

One constraint of the RIP pattern is that the concrete classes should have inheritance and polymorphism together.

There are various ways to achieve IOC principles like using Dependency Injection, Delegates, and so on. In this project, the control is inverted from UI to factory class that utilizes the IOC (Inversion of Control) principle to inject an object into the UI.

Step 10: Further improvement: Lazy loading the Factory

Currently, the Factory is loading the objects every time it is called or even if not needed. This can be improved to just-in-time loading, only load the objects when needed is the basic principle of the Lazy Loading design pattern (creational design pattern). For Lazy Loading:

First: Make the object collection types null and do not load them in the constructor.

Second: Create a method that loads when the object is null and if not just lookup in the available collection.
 public static class Factory
    {
        private static List<ICustomer> customers = null;
        static void LoadCustomers()
        {
            // load the type of customers here 
            customers = new List<ICustomer>();
            customers.Add(new Visitor());
            customers.Add(new Customer());
        }
        public static ICustomer Create(int CustomerType)
        {
            if (customers == null)
            {
                LoadCustomers();
            }
            return customers[CustomerType];
        }
    }

At this stage, the factory class looks good, but wait.  Now what? The factory is returning the same objects all the time “iCust= Factory.Create(0);” “That is what we wanted we don’t want many objects in memory” well that is true but that doesn’t mean, the same reference to the object to be returned by factory class to do different tasks, will have very serious issues. The factory class is created to generate new instances not to return the same objects.

Step 11: Prototype Pattern (Cloning the objects)

a collection of objects in Factory that gets instantiated whenever it is needed (lazy loading) but the problem of lazy loading is that the Factory returns the existing instances which will have significant issues for the application. The solution to this is to use cloning of objects to make them independent objects, by using the .Net ICloneable Interface.

To clone the objects:
  1. Define a “Clone” method in the “ICustomer” interface.
  2. Use the .Net inbuilt “MemberwiseClone” method – It is a protected method of the object which creates a shallow copy of the current object to the new object.
// Include a Clone  method in Customer base so all objects associated with it can be cloned
public class CustomerBase:ICustomer 
    {
        public string FullName { get; set; }
        public string PhoneNumber { get; set; }
        public decimal BillAmount { get; set; }
        public DateTime BillDate { get; set; }
        public string Address { get; set; }
        public virtual void Validate()
        {
            // Virtual function created so that it can be override by child class
            //let this be defined by child classes. 
        }
        public ICustomer Clone() 
        {
            // Introducing Memberwise clone in base class to be able to clone any customer objects created 
            return (ICustomer)this.MemberwiseClone();
        }
    }

// Implement Clone method in the interface 
public interface ICustomer
    {
        string FullName { get; set; }
        string PhoneNumber { get; set; }
        decimal BillAmount { get; set; }
        DateTime BillDate { get; set; }
         string Address { get; set; }
        void Validate();
        ICustomer Clone();        
    }
// Then return the clone customer object from factory
public static ICustomer Create(int CustomerType)
        {
            if (customers == null)
            {
                LoadCustomers();
            }
            return customers[CustomerType].Clone();
        }

So far implementing a decoupled, well-architected application development process is on track. Let’s have a thought on what can be improved in the architecture. Factory’s main duty is to act as a central location to create objects, what will happen if new entities like Order, Sales, Logger, etc appear. Can a single factory handle this? No not at the moment. How to make the Factory class a universal Factory that can instantiate any entities?

The solution to this is, using Dependency Injection (DI) and inverting the control from factory class to external entity and make Factory Generic.(To know about Inversion of Control and Dependency Injection Click here)

Step 12: Using Dependency Injection Design Pattern in Factory to make it Universal

Use Unity Application block to inject entities/objects in the Factory class from outside. Unity’s main task is to utilize Dependency Injection (DI) design pattern to inject objects. Unity has a concept of containers (or Collections). “RightType” and “ResolveType” methods help to add and get objects from the container collection respectively.

For implementing DI using Unity:
  1. Download Unity application block in Factory class using NUGET and use “using Microsoft.Practices.Unity” & “Microsoft.Practices.Unity.Configuration”. (Unity.NetCore (4.0.3) & Unity.Configuration (5.11.2) in this demo)
  2. Create App.config file to load the configuration of objects to be injected
  3. Load the objects in the Unity container using RegisterType or load them from the config file and resolve the object.
//// Configuration File to load the Unity Container ////

<configuration>
  <configSections>
    <section name="unity"
             type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, 
             Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <container>
      <register type="ICustomerLib.ICustomer, ICustomerLib"
                mapTo="CustomerLibrary.Visitor, CustomerLibrary" name="0" />
      <register type="ICustomerLib.ICustomer, ICustomerLib"
                mapTo="CustomerLibrary.Customer, CustomerLibrary" name="1" />
    </container>
  </unity>
  <startup>
    <supportedRuntime version="v5.0" sku=".NETFramework,Version=v5.0" />
  </startup>  
</configuration>

//// Factory Class Code ////


using ICustomerLib;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;

namespace CustomerFactory
{
    //Simple Factory Pattern 
    // To improve perfomance we use singelton pattern so that it 
    // Can only be instantiated once

    public static class Factory
    {

        static IUnityContainer oUnitCont = null;
        static Factory()
        {
            oUnitCont = new UnityContainer();

            // We can directly load the unity container here 
            //oUnitCont.RegisterType<ICustomer, Visitor> ("0"); //You can get the value from config 
            //oUnitCont.RegisterType<ICustomer, Customer>("1");

            if (ConfigurationManager.GetSection("unity") != null)
            {
                //Or We can load the entityes to be injected from the configuration file
                oUnitCont.LoadConfiguration();
            }
        }               
        public static ICustomer Create(int CustomerType)
        {            
            return oUnitCont.Resolve<ICustomer>(CustomerType.ToString());
        }   

    }
}

New customer types can be added to the config file and its corresponding object will be returned by the unity Container. Now, the Factory class is automatically creating new instances of Customer types once requested, but what about if there are “Supplier” or “Order” entities. To make sure Factory works for all entities, rather than tying it with a single type, it has to be a “GENERIC” class.

But first, let’s understand “Generics” and “Generic Collections”. These are two different terms that we need to be clear on before moving forward.

Generics

Generics means the general from, not specific. In C#, generic means not specific to a particular data type. C# allows defining generic classes, interfaces, abstract classes, fields, methods, static methods, properties, events, delegates, and operators using the type parameter and without specifically using data type. A generic type helps to decouple the logic from the data type and can be declared by specifying a type parameter. e.g. TypeName<T> where T is type parameter.

Generic classes are defined using a type parameter in angle brackets after the class name. The following defines a generic class.

Class DataStore
{
	public bool CompareData(int x, int y)
	{
		if (x==y)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}

// We can call the object and compare integer data type
DataStore obj = new DataStore();
bool b1 = obj.CompareData(1,2);
// what if I want to compare a string data Type
b1 = obj.CompareData("this", "that"); // throw an cxceptino

//So to decide what type of data to compare we can use generic 
// Generic Class
using System.Collection.Generic
class DataStore <DT>
{
    public DT Data { get; set; }  

    public bool CompareData(DT x, DT y)
	{
		if (x==y)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

}
// While calling we passed on string data type
DataStore<string> strStore = new DataStore<string>();
strStore.Data ="Hi Mr pasta!!";
strStore.Data = 1001; // it will throw compile time error

//While calling we passed on int data type 
DataStore<int> intStore = new DataStore<int>();
intStore.Data = 100;
//intStore.Data = "Hi Mr Pasta!!"; // it will throw compile-time error

// We can call the object and compare using predefined data type
DataStore<int> obj = new DataStore<int>();
bool b1 = obj.CompareData(1,1); // Returns true

// If I want to compare a string data Type we can inject string data type
DataStore<string> obj = new DataStore<string>();
bool b2 = obj.CompareData("this", "that"); //Returns false

Generics separates or decouple the logic from the data type which will improve usability and maintenance of the code.

Difference between Generic Collections (List), an Array, and ArrayList

Generic collections are the strongly typed collection that is aimed to bridge the gap between Array and Array List.

Problem with Array and ArrayList

Array:- Arrays are strongly typed (meaning that you can only put one type of object into it) and are limited to size (Fixed length).
//We can only declare certain type of array with fixed length
int[] Array = new Int[5]; //Declaration of size 5 array of type integer. 
for(int i = 0; i < Array.Length; i++)
{
   Array[i] = i + 5; //Add values to each array index
}

// The things that we cannot do with array
//must specify the size 
int[] iCount= new int[]; 

//number of elements must be equal to the specified size 
int[] iCount = new int[4] { 2, 4 };

//cannot use var with array initializer
var iCount = { 2, 4, 6, 8, 10}; 
To overcome the problems of an Arry they discovered an ArrayList.

ArrayList:- ArrayList is a non-generic collection of objects whose size can be increased as per the need basis and can be used to add unknown data where you don’t know the types or the size of the data. But, when the Arraylist doesn’t know the type of data it has to typecast the data, for that It has done the boxing and unboxing while processing (this will significantly decrease the performance than using an Array).

ArrayList arlist = new ArrayList(); 
// or 
var arlist = new ArrayList(); // recommended 
//Array list can hold any type of data and can expand as required.
arlist1.Add(1);
arlist1.Add("Bill");
arlist1.Add(" ");
arlist1.Add(true);
arlist1.Add(4.5);
arlist1.Add(null);

// While Accessing the Arraylist it has overhead of boxing and unboxing 
int firstElement = (int) arlist[0]; //returns 1
string secondElement = (string) arlist[1]; //returns "Bill"
//int secondElement = (int) arlist[1]; //Error: cannot cover string to int

Array list solved the problem of Array but performance decreased. So to get the benefit of the array (performance) and be able to increase the size (ArrayList) they discovered a Generic collection called (List).

List (Generic Collection): List is a strongly typed generic collection, so you need to specify a type parameter for the type of data it can store but data can increase on a need basis. It doesn’t incur the overhead of being converted to and from type objects.

// Here we have created list of integer that can expand dynamically
List<int> numbers = new List<int>();
numbers.Add(1); // adding elements using add() method
numbers.Add(2);
numbers.Add(5);
numbers.Add(7);

// Or you can directly add the numbers
List<int> numbers = new List<int>() { 1, 2, 5, 7 };
Console.WriteLine(numbers[0]); // prints 1
Console.WriteLine(numbers[1]); // prints 2
Console.WriteLine(numbers[2]); // prints 5
Console.WriteLine(numbers[3]); // prints 7

// using foreach LINQ method
numbers.ForEach(num => Console.WriteLine(num + ", "));//prints 1, 2, 5, 7, 

Step 13:- Making Generic Factory

Generics separates or decouples the logic from the data type, that’s what is needed in the Factory class.

using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;

namespace Factory
{
    //Simple Factory Pattern 
    // To improve perfomance we use singelton pattern 
    // Follow IOC principle using Dependency Injection via Unity 
    // Make this class Generic so that the logic is decoupled from the data type.

    public static class Factory<INJECTTYPE>
    {
        static IUnityContainer oUnitCont = null;
        static Factory()
        {            
            if (ConfigurationManager.GetSection("unity") != null)
            {
                //Or We can load the entities to be injected from the configuration file
                oUnitCont.LoadConfiguration();
            }
        }               
        public static INJECTTYPE Create(string Type) // will return whatever type is injected
        {            
            return oUnitCont.Resolve<INJECTTYPE>(Type.ToString()); //resolves to any type injected
        }       

    }
}

//Call From the UI -- we can simply pass ICustomer to get Customer objects 
// If in future if we pass supplier or any other class it will return the same type of objects. 
  ICustomer iCust = null;
  iCust = Factory<ICustomer>.Create(cboCustType.SelectedIndex.ToString()).Clone();;

The Factory is generic, much more cleaner, and independent to produce new instances of objects. UI is only talking to Factory and interface (not to Business Layer) and so the process of well-architected application development is moving smoothly. Note:- The ICustomerLib project is renamed to Interface to make it easier to understand.  Let’s look at other requirements to proceed further.

Requirement to Validate

As per the customer requirement, validate action has to be performed by the Customer and Visitor accordingly. Customers must provide all the information but visitors can provide FullName and the Phone Number only. Currently, two separate Validate methods for Customer and Visitor are created, what if another type of customer appears? It’s not a good practice to keep on writing new validate for every new type of Customer. Plus, the requirement is saying “the system should be able to validate any type of customer dynamically” which means validation logic should change when the type of customer changes. It seems Customer Class needs improvement here:

  • It is not following SRP (Single Responsibility Principle) – The class is not doing one task but multiple
  • It is not doing SOC (Separation of Concerns) – Class is not separated to Validation logic, an unnecessary concern.
  • It is not implementing IOC – which means moving logic away from the entity class to some other class.

To fix this Customer Entity must be decoupled from Validation logic and have to make sure these two concrete classes communicate to each other via Interface. Interface for Customer called (ICustomer) is already present, Validation Interface and a Validation logic is required here. To achieve this decoupling we can implement Strategy Design Pattern.

Step 14- Implement Strategy Pattern

A strategy pattern is a behavioral design pattern that enables selecting an algorithm (or a Strategy) at runtime. Strategy lets the logic vary independently from the clients that use it.

IValidation interface is created and a Separate class library called ValidationLogic is created for the validation logic classes.

// Validation Interface that has a Validation class and is Generic Interface where we can inject Type
namespace Interfaces
{
    public interface IValidation<InjectType>
    {
        void Validate(InjectType obj);
    }
}

using System;
using Interfaces;

//Validation Logic Project to hold all the validation related logic
namespace ValidationLogic
{
    //Validation logic for customer entity
    public class CustomerValidation : IValidation<ICustomer>
    {
        public void Validate(ICustomer obj)
        {
            if (obj.FullName.Length == 0)
            {
                throw new Exception("Customer Full Name is required");
            }
            if (obj.PhoneNumber.Length == 0)
            {
                throw new Exception("Customer Phone Number is required");
            }
            if (obj.BillAmount == 0)
            {
                throw new Exception("Bill Amount is required");
            }
            if (obj.BillDate >= DateTime.Now)
            {
                throw new Exception("Bill Date is not correct");
            }
            if (obj.Address.Length == 0)
            {
                throw new Exception("Address is required");
            }
        }
    }
    //Validation logic for Visitor Entity
    public class VisitorValidation : IValidation<ICustomer>
    {
        public void Validate(ICustomer obj)
        {
            if (obj.FullName.Length == 0)
            {
                throw new Exception("Visitor Full Name is required");
            }
            if (obj.PhoneNumber.Length == 0)
            {
                throw new Exception("Visitor Phone Number is required");
            }
        }
    }

}

Validations are moved away from Customer Entity to a separate entity and injected Validation in Customer Base constructor.

namespace CustomerLibrary
{
    public class CustomerBase : ICustomer
    {
        //Create object of Interface validation
        private IValidation<ICustomer> _validation = null;

        //Inject the Validation strategy in the Customer object
        //when the customer object is created it requies what type of validation strategy is required
        public CustomerBase(IValidation<ICustomer> objVal)
        {
            _validation = objVal;
        }

        public string FullName { get; set; }
        public string PhoneNumber { get; set; }
        public decimal BillAmount { get; set; }
        public DateTime BillDate { get; set; }
        public string Address { get; set; }
        public virtual void Validate()
        {
            // Virtual function created so that it can be override by child class
            //let this be defined by child classes. 
            // Clalling the validatoin method and passing the current customer object to be validated
            _validation.Validate(this);
        }
        public ICustomer Clone()
        {
            // Introducing Memberwise clone in base class to be able to clone any customer objects created 
            return (ICustomer)this.MemberwiseClone();
        }

    }
    public class Customer : CustomerBase
    {
        //In the individual child class creating the constructor to call the Validation 
        //this is injecting Validation strategy here
        public Customer(IValidation<ICustomer> objVal):base(objVal)
        {

        }        

    }

    public class Visitor : CustomerBase
    {
        //this is injecting Validation strategy here
        public Visitor(IValidation<ICustomer> objVal):base(objVal)
        {

        }       
    }
}

Since the customerbase constructor needs a validation strategy, the Unity container in the factory needs to change. Note: Changed the Unity Key to “Customer” and “Visitor” instead of just using 0 or 1 and made necessary changes in the APP.config and the UI.

 public static class Factory<INJECTTYPE>
    {
        static IUnityContainer oUnitCont = null;
       
        public static INJECTTYPE Create(string Type) // will return whatever type is injected
        {
            if (oUnitCont==null)
            {
                if (ConfigurationManager.GetSection("unity") != null)
                {
                    oUnitCont = new UnityContainer();
                    //Here we are registering different customer types and injecting the validation methods accordingly

                    oUnitCont.RegisterType<ICustomer, Visitor>("Visitor", new InjectionConstructor(new VisitorValidation()));
                    oUnitCont.RegisterType<ICustomer, Customer>("Customer", new InjectionConstructor(new CustomerValidation()));


                    //Or We can load the entities to be injected from the configuration file
                    // oUnitCont.LoadConfiguration();
                }
            }
            return oUnitCont.Resolve<INJECTTYPE>(Type.ToString()); //resolves to any type injected

        }

    }

App.config small change
<register type="ICustomerLib.ICustomer, ICustomerLib"
                mapTo="CustomerLibrary.Visitor, CustomerLibrary" name="Visitor" />
      <register type="ICustomerLib.ICustomer, ICustomerLib"
                mapTo="CustomerLibrary.Customer, CustomerLibrary" name="Customer" />

UI small Change

 ICustomer iCust = null;

                if (cboCustType.SelectedIndex==0)
                {
                    iCust = Factory<ICustomer>.Create("Visitor").Clone();
                }
                else 
                {
                    iCust = Factory<ICustomer>.Create("Customer").Clone();
                }

The validation logic is decoupled from the Customer class using Strategy Pattern.

Next up,  implementing the Data Access layer using ADO.NET and Entity Framework with a goal to decouple model from database (RDBMS – relational database management system).

Step 15- Implement Decoupled Data Access layer

Start by adding a new class library for all the Interfaces related to the Data Access Layers called InterfacesDAL

using System;
using System.Collections.Generic;

namespace InterfacesDAL
{
    //Design Pattern to be used here 
    //Repository Pattern
    // we are making this interface a generic interface to accept any type of class 
    // Since we are using generic type interface theis pattern will be called generic Repository Pattern
    public interface IDal<InjectType>
    {
        
        void Add(InjectType obj); // Inmemory add
        void Update(InjectType obj); // Inmemory update
        List<InjectType> Search();
        void Save(); // Physical commit
    }
}

A generic interface is designed that can be used by all the model classes to perform CRUD operations. Basically, the IDAL will serve all the entity classes and decouple them from the data layer logic. For the data access logic, a class library called DataAccessLibrary is added that will implement IDal.

Business logic won’t care what will happen behind IDAL

A generic base class called AbstractDal is added implementing IDal with virtual functions which can be inherited and changed by the child classes.

using InterfacesDAL;

namespace DataAccessLibrary
{
    public abstract class AbstractDal<InjectType> : IDal<InjectType>
    {
        //since connection string will be used by child classes so we are making it protected
        protected string ConnectionString = "";
        // we will pass the connection string to the Constructor of this AbstractDal class
        public AbstractDal(string _connString)
        {
            ConnectionString = _connString;
        }
        // make sure the list is available in the child classes
        protected List <InjectType> lstObj = new List<InjectType>();
        public virtual void Add(InjectType obj)
        {
            lstObj.Add(obj);
        }

        public virtual void Save()
        {
            throw new NotImplementedException();
        }

        public virtual List<InjectType> Search()
        {
            throw new NotImplementedException();
        }

        public virtual void Update(InjectType obj)
        {
            lstObj.Add(obj);
        }
    }
}

Repository Pattern & Template Pattern with ADO.NET

A separate class library for ADO.Net logic called ADONetLibrary is added which implements IDal . ADO.NET normally Opens a Connection, Executes a Command, and closes the connection and it normally will have a fixed template and for this type of repetitive tasks, we can implement a Template Design Pattern.

ADO.Net Template:- Normally has fixed template and can be reusable by different DAL classes

Template Design Pattern

In Template Design Pattern, normally the sequence of tasks is fixed but the individual sequences in the template abstract class can be overridden by the child classes. A TemplateADO class is created to act as a template, that consists of methods that can be overridden by the child classes.

using System;
using DataAccessLibrary;
using InterfacesDAL;
using System.Data;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;

namespace ADONetLibrary
{
    public abstract class TemplateADO<InjectType>:AbstractDal<InjectType>
    {
        //Declaring connection and command objects
        protected SqlConnection objConn = null;
        protected SqlCommand objCommand = null;

        //Pass Inject the connection string as required by the base class
        public TemplateADO(string _connStr):base(_connStr)
        {

        }
        private void OpenConn()
        {
            objConn = new SqlConnection(ConnectionString);
            objConn.Open();
            objCommand = new SqlCommand();
            objCommand.Connection = objConn;
        }
        private void CloseConn()
        {
            objConn.Close();
        }
        
        //This will be overridden by the child class as per their sql execution queries.
        // they can attach a search, insert or update queries. 
        protected abstract void ExecuteCommand(InjectType obj);
        protected abstract List<InjectType> ExecuteCommand();
        

        public void Execute(InjectType obj)
        {
            ///Follow the fixed ADO.net template 
            OpenConn();
            ExecuteCommand(obj);
            CloseConn();
        }

        // override the save function from the ABstractDal
        public override void Save()
        {
            foreach (InjectType obj in lstObj)
            {
                Execute(obj);
            }
        }

    }
}

Template class opens the connection, executes the command, and closes the connection, and Save can be overridden by child classes as per their execution logic. This is now a universal template that can be inherited by the Data Access model classes.

A CustomerDAL class is created that inherits the Template Class to execute customer-related data layer logic. A Database called PetShop and a database table name tblcustomer with autoincrement ID (PK) is created to proceed ahead.

using Interfaces; // We need business objects here to get them inserted in database
namespace ADONetLibrary
{
    public class CustomerDAL : TemplateADO<ICustomer>
    {
        public CustomerDAL(string _connStr):base( _connStr) // connection string to be passed to the template and base class
        {

        }
        //We can now override the ExecuteCommand to use Customer specific execute query
        protected override void ExecuteCommand(ICustomer obj)
        {
            // A simple insert statement to insert into tblCustomer
            objCommand.CommandText = "Insert into tblCustomer(" +
                                      "FullName," +
                                      "BillAmount," +
                                      "BillDate," +
                                      "PhoneNumber," +
                                      "Address)" +
                                      " values('" +
                                      obj.FullName + "','" +
                                      obj.BillAmount + "','" +
                                      obj.BillDate + "','" +
                                      obj.Address + "')";
        }
    }
}
To instantiate the Customer Data Access class, the Factory has to be used. So, the Factory should reference Customer DAL and ADONetLibrary.
using InterfacesDAL;
using ADONetLibrary;
namespace Factory
{
    //Design pattern :- Simple Factory Pattern 
    // To improve perfomance we use singelton pattern 
    // Follow IOC principle using Dependency Injection via Unity 
    // Make this class Generic so that the logic is decoupled from the data type.

    public static class Factory<INJECTTYPE>
    {
        static IUnityContainer oUnitCont = null;
       
        public static INJECTTYPE Create(string Type) // will return whatever type is injected
        {
            if (oUnitCont==null)
            {
                if (ConfigurationManager.GetSection("unity") != null)
                {
                    oUnitCont = new UnityContainer();
                    //Here we are registering different customer types and injecting the validation methods accordingly
                    //Or We can load the entities to be injected from the configuration file
                    // oUnitCont.LoadConfiguration();

                    oUnitCont.RegisterType<ICustomer, Visitor>("Visitor", new InjectionConstructor(new VisitorValidation()));
                    oUnitCont.RegisterType<ICustomer, Customer>("Customer", new InjectionConstructor(new CustomerValidation()));
                    /// Registering a new DAL object in Factory

 //Injecting the _connStr in the constructor as main base class Abstract Dal needs connection string to be injected in constructor.                   
                    string _connStr = GetConnectionString();
                    oUnitCont.RegisterType<IDal<ICustomer>, CustomerDAL>("ADODal", new InjectionConstructor(_connStr));                    
                }
            }
            return oUnitCont.Resolve<INJECTTYPE>(Type.ToString()); //resolves to any type injected
        }
        //for now we are just passing the connection string here manually 
        // we will have to change this to more elegant way later. 
        static private string GetConnectionString()
        {
            // To avoid storing the connection string in your code,
            // you can retrieve it from a configuration file.
            return "Data Source=localhost;Initial Catalog=PetShopDB;"
                + "Integrated Security=true;";
        }
    }
}
Let’s proceed to add the Search feature where that loads the objects from the database and returns a list to the UI to process it.
// In Template.ADO

 public List<InjectType> Execute() // returning the list 
        {
            ///Follow the fixed ADO.net template 
            List<InjectType> lst = null;
            OpenConn();
            lst =  ExecuteCommand();
            CloseConn();
            return lst;
        }


// In Customer DAL class

protected override List<ICustomer> ExecuteCommand()
        {
            List<ICustomer> lstCust = null;
            objCommand.CommandText = "Select * from tblCustomer";
            SqlDataReader dr = null;
            dr = objCommand.ExecuteReader();
            while (dr.Read())
            {
                // Now we need the Factory's help here to create the customer so that we can fill the information here. 

            }

            return lstCust;

        }

Wait for a second, there is a little problem here, after reading data from the database list of concrete classes (customer or visitor) should be returned, for that, concrete classes have to be instantiated by the Factory as well.

But, Factory is already is referencing the CustomerDal to create its objects, and to reference back to the factory from this project will cause a “Circular Reference Problem” (circular dependency – If two classes try to reference each other). How to fix this?

To fix this issue, different factories for Data Layer and Business layer are required. The Business layer factory and Data layer factory work independently to create objects for the Business layer and Data layer.

/// Data Access Factory

using Microsoft.Practices.Unity;
using System.Configuration;
using InterfacesDAL;
using ADONetLibrary;
using Interfaces;

namespace FactoryDAL
{
    public static class FactoryDAL<INJECTTYPE>
    {
        static IUnityContainer oUnitCont = null;

        public static INJECTTYPE Create(string Type) // will return whatever type is injected
        {
            if (oUnitCont == null)
            {
                if (ConfigurationManager.GetSection("unity") != null)
                {
                    oUnitCont = new UnityContainer();
                    
                    //Injecting the _connStr in the constructor as main base class Abstract Dal needs connection string to be injected in constructor.
                    string _connStr = GetConnectionString();
                    oUnitCont.RegisterType<IDal<ICustomer>, CustomerDAL>("ADODal", new InjectionConstructor(_connStr));

                }
            }
            return oUnitCont.Resolve<INJECTTYPE>(Type.ToString()); //resolves to any type injected

        }

        //for now we are just passing the connection string here manually 
        // we will have to change this to more elegant way later. 
        static private string GetConnectionString()
        {
            // To avoid storing the connection string in your code,
            // you can retrieve it from a configuration file.
            return "Data Source=localhost;Initial Catalog=PetShopDB;"
                + "Integrated Security=true;";
        }

    }
}


// Our business layer factory comes back to its previous state.
using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;
using Interfaces;
using CustomerLibrary;
using ValidationLogic;

namespace Factory
{
    //Design pattern :- Simple Factory Pattern 
    // To improve perfomance we use singelton pattern 
    // Follow IOC principle using Dependency Injection via Unity 
    // Make this class Generic so that the logic is decoupled from the data type.

    public static class Factory<INJECTTYPE>
    {
        static IUnityContainer oUnitCont = null;
       
        public static INJECTTYPE Create(string Type) // will return whatever type is injected
        {
            if (oUnitCont==null)
            {
                if (ConfigurationManager.GetSection("unity") != null)
                {
                    oUnitCont = new UnityContainer();
                    //Here we are registering different customer types and injecting the validation methods accordingly
                    //Or We can load the entities to be injected from the configuration file
                    // oUnitCont.LoadConfiguration();

                    oUnitCont.RegisterType<ICustomer, Visitor>("Visitor", new InjectionConstructor(new VisitorValidation()));
                    oUnitCont.RegisterType<ICustomer, Customer>("Customer", new InjectionConstructor(new CustomerValidation()));                                          

                    
                }
            }
            return oUnitCont.Resolve<INJECTTYPE>(Type.ToString()); //resolves to any type injected

        }
        
    }
}

Customer UI can now access the data access layer via Interfaces DAL to execute commands or receive a list of customers from the database.

using System;
using System.Windows.Forms;
using Interfaces;
using Factory;
using FactoryDAL;
using InterfacesDAL;
using System.Collections.Generic;
namespace PetShop
{
    public partial class frmCustomer : Form
    {
        private ICustomer iCust = null;
        public frmCustomer()
        {
            InitializeComponent();
        }

        private void cmdAdd_Click(object sender, EventArgs e)
        {
            try
            {
                FillCustomer();
                // Creating Idal object of type Icustomer from 
                // Factory that returns IDal object of type ICustomer by requesting ADODal from Create method
                IDal<ICustomer> dal = FactoryDAL<IDal<ICustomer>>.Create("ADODal");
                dal.Add(iCust); // This is in memory addition 
                dal.Save(); // this is physical commit. 
                LoadGrid();
                MessageBox.Show("Success!!");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }             
        }

        private void FillCustomer()
        {
                iCust.FullName = txtFullName.Text;
                iCust.Address = txtAddress.Text;
                iCust.PhoneNumber = txtPhoneNo.Text;
                iCust.BillDate = dtBillDate.Value;
                if (txtBillAmount.Text.Length>0)
                {
                    iCust.BillAmount = Convert.ToDecimal(txtBillAmount.Text);
                }
        }

        private void cboCustType_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Here we can pass the Visitor or customer from App.config and avoid using if. 
            if (cboCustType.SelectedIndex == 0)
            {
                iCust = Factory<ICustomer>.Create("Visitor").Clone();
            }
            else
            {
                iCust = Factory<ICustomer>.Create("Customer").Clone();
            }         

        }

        private void LoadGrid()
        {
            IDal<ICustomer> dal = FactoryDAL<IDal<ICustomer>>.Create("ADODal");
            List<ICustomer> lstCusts = dal.Search();
            dgCustomerList.DataSource = lstCusts;
        }

        private void frmCustomer_Load(object sender, EventArgs e)
        {
            LoadGrid();
        }
    }

}


Using template and repository pattern for ADO.net the UI can successfully insert and retrieve data, this now can be further extended to use repository pattern for Entity Framework (EF).

Repository Pattern using ADO.Net – Explanation

The main goal of the repository pattern is decoupling the model from the data access layer. To implement the repository pattern in Data Access Layer, the interface is defined, then an AbstractDAL of the generic type is created so that it can be inherited by all data entities. Then for ADO.net repository, an ADO template that holds the sequential tasks such as opening the connection, Execute the command, and closing the connection is created. Finally, the actual entity-related data access class was created to execute the queries related to the entity.

Repository Pattern Using Entity Framework

A dropdown is added in Winfrom (ddChooseDAL)  that will have two selections one for ADO.net and another one for EF to be able to select which repository to use making it a plug and play system (decoupled architecture).

What actually is the Entity Framework?

Entity Framework is an open-source object-relational mapping (ORM) framework for ADO.net. EF uses ADO.net and is just the wrapper for ADO.Net to simplify the use of ADO.net API. ADO.Net has routine jobs like opening a connection to the database, Executing queries, create a dataset or DataReader to fetch the data from the database, and closing the connection. Instead of focusing on all these tasks, EF has enabled automating all these database-related activities and just focus on the domain objects. Using ORM, the entity framework enables to map the database tables with domain objects without the need for the data-access code.

One pitfall while working with EF is that Interface cannot be used to map the objects, concrete classes itself has to be used. Such a pity, it makes code ugly by not being able to use the interface. 

EF – ORM needs concrete class

Need to change all Customer Interfaces to CustomerBase to be able to utilize EF.

EF – ORM needs a Key

All objects must have a unique key to be able to map the object to the database table. Create integer type ID property in Customer Class and the Customer Interface and mark this property to be [key] by data annotation [key] attribute (add NuGet package (System.componentmodel.annotations) to use data annotations.

Entity Framework Library

A separate class library for Entity framework is created and install in the NuGet package “Microsoft Entity Framework Core. SqlServer” (cause EF core doesn’t have Modelbuilder.Entity.ToTable()). This class library will reference the InterfaceDAL, Interfaces, and also Customer Library (why? will explain this later). A generic EFDalAbstract class is created that inherits from DbContext (EF class) and implements the generic interface IDAL

using InterfacesDAL;
using Microsoft.EntityFrameworkCore;

namespace EFDALLibrary
{
    public abstract class EFDalAbstract<INJECTTYPE> : DbContext, IDal<INJECTTYPE>
        where INJECTTYPE:class /// it is telling the that the type we are injecting is a class
    {
        public void Add(INJECTTYPE obj)
        {
            /// Using the Entitytframework Set<>.Add that can be used to save the entity of type INJECTTYPE.          
            /// This only places the objects in memory ready for commit
            Set<INJECTTYPE>().Add(obj);
        }

        public void Save()
        {
            SaveChanges(); // This is for the physical committ to the database. 
        }

        public List<INJECTTYPE> Search()
        {
            //Return the collection of Injected Type objects via Entity Framework
            return Set<INJECTTYPE>().AsQueryable<INJECTTYPE>().ToList<INJECTTYPE>();
        }

        public void Update(INJECTTYPE obj)
        {
            throw new NotImplementedException();
        }
    }
}

Adaptor Design Pattern

Adaptor Design Pattern is a structural Pattern that allows objects with incompatible interfaces to collaborate. This is also known as the wrapper (an alternative naming shared with the decorator pattern) that is often used to make existing classes work with others without modifying their Source code.

In this project, set().Add, SaveChanges() from entity framework (DBContext) is used to save and  Set().AsQueryable() is used to query the list of objects from the database. But in ADO.Net, ExecuteNonQuery() for save and Executereader() for getting a list from the database has to be executed. To avoid these differences while interacting with the data layer, the interface called IDal (a wrapper) is used, that doesn’t care what is happening in the background but gives the consistent methods called Save() and Search(), Here, Adaptor Design Pattern is utilized by using inheritance to make incompatible method names compatible.

Let’s Continue with the EF

Create an EFCustomerDAL for EF to perform object relation mapping (ORM). The customer model is mapped to tblCustomer.

using Interfaces;
using Microsoft.EntityFrameworkCore;

namespace EFDALLibrary
{
    public class EFCustomerDAL:EFDalAbstract<ICustomer>
    {
        // Here we will do Object relation mapping
        // We are using EF code first approach for this demo.
        // to write mapping code we will be using OnModelCreating
        protected override void OnModelCreating(ModelBuilder modelBldr)
        {
            // Mapping code
            //Currently we cannot use interface while mapping so we have to use our Customer Abstract class
            modelBldr.Entity<CustomerBase>().ToTable("tblCustomer");
        }        
    }
}

Pass the DbContextOptions with the connection string to connect to the database in the EFDal Abstract class constructor.

public abstract class EFDalAbstract<INJECTTYPE> : DbContext, IDal<INJECTTYPE>
        where INJECTTYPE:class /// it is telling the that the type we are injecting is a class
    {
        public EFDalAbstract()
            :base(GetSQLOptions("name=Conn")) // we have to pass DbcontextOptions in .net 5.0 , earlier we could have passed the string itself
        {
        }

        private static DbContextOptions GetSQLOptions(string connectionString)
        {
            //creating dbcontextOptions by passing the connection String            
            return SqlServerDbContextOptionsExtensions.UseSqlServer(new DbContextOptionsBuilder(), connectionString).Options;
        }

Entity Framework data access layer classes have to be known to the FactoryDal which is responsible for creating the objects. Now create the reference in FactoryDAL to access EFDalLibrary and register the type of EFDal that has to be injected by the Unity container.

Note: While Entity Framework doesn’t support the interface, and it is the issue that has been raised many times to Microsoft Team and hasn’t been fixed until EF 6.0 and we have to live with it. So What It means the project – As soon as  EF finds the abstract Customerbase, as the name suggests, it cannot be instantiated and the EF will not be happy. To fix this Customerbase has to change to normal class by removing the abstract Keyword. But there is another problem, the Cusotmer base needs a Validation object injected into the constructor, EF won’t do that. To fix this the constructor in the CustomerBase has to be overloaded with a blank constructor so that EF can use it. Now Factory DAL will have problem, Entity Framework will be looking for CustomerBase whereas the ADO .net will be looking for ICustomer. Since EF cannot be changed, we need to change ADO.net to use CustomerBase instead of ICustomer. I know you don’t like this… but to use EF, replace all ICustomer with using concrete CustomerBase class. (make changes to CustomerForm, Factory and Factory Dal)

Implementing Repository Pattern with ADO.Net and EF is complete. The well-architected application development is completed with decoupled data-access layer utilizing various design patterns. I will further extend the project to explain some more design patterns so that it is easier to understand with the code.

Unit of Work Design Pattern

According to “ Patterns of Enterprise Application Architecture” by Martin Fowler, the Unit of Work maintains a list of objects affected by a business transaction and coordinates the writing out of changes. Unit of Work Design pattern goes together with Repository Pattern or in other words Unit of Work Design Pattern solves the problems of the Repository pattern. Note: To understand UOW better, the name of the IDal interface is changed to IRepository. Let’s first understand what are the problems of the Repository pattern? To Replicate the problems of the Repository pattern and show the implementation of the Unit of work, a command button called “Use UOW” is added in the UI.

 private void cmdUOW_Click(object sender, EventArgs e)
        {                     

            /// Here we are using mulitple Multiple Repositories to insert different customers. 
            CustomerBase cust1 = new CustomerBase();
            cust1.BillDate = DateTime.Today;
            cust1.CustomerType = "Visitor";            
            cust1.FullName = "Cust1";            
            IRepository<CustomerBase> dal = FactoryDAL<IRepository<CustomerBase>>.Create(dbType);
            dal.Add(cust1); // In memory Add 
            dal.Save();


            cust1 = new CustomerBase();
            cust1.BillDate = DateTime.Today;
            cust1.CustomerType = "OldCustomer";
            cust1.FullName = "Cust2";
            cust1.Address = "adsfasdfasdfasdfasdfasdfsdfsadfasfasdfasfasdfasdfasdfasdfasfasdfasfasdfdasfasdsdfasdsdfasfasdfasfdasfdasf";
            IRepository<CustomerBase> dal1 = FactoryDAL<IRepository<CustomerBase>>.Create(dbType);
            dal1.Add(cust1); // In Memory Add
            dal1.Save();
            /// Problem - with Repository pattern
            /// First transaction will be inserted
            /// second insert will have error due to Address length
            /// 
            LoadGridEF();
        }

In this example above two insert queries are executed where the first one gets inserted successfully but the second one had issues with the length of the address and so throws an error. But if the requirement is to execute both successfully or both to fail together then current repository cannot handle the requirement. In ADO.net, Begin Transaction, Commit Transaction on success, or Rollback Transaction on error can be used. Similarly, in Entity Framework, the transactions are handled by DbContext class. To overcome this pitfall of the Repository Pattern of not being able to handle transactions as a unit block, the Unit of Work design has to be implemented. Unit of work helps to put multiple units of Repository transactions into one logical transaction unit, but also respect the decoupling of transactions as performed by Repository. For implementing unit of work:

Create an interface for Unit Of Work (IUow) with the generic method that does Commit and Rollback and create a method in Repository to inject Unit of Work. Then create separate classes to handle Unit of work in each of the ADO.net and EF libraries.

namespace InterfacesDAL
{
    //Design Pattern - Repository Pattern
    // we are making this interface a generic interface to accept any type of class 
    // Since we are using generic type interface theis pattern will be called generic Repository Pattern
    public interface IRepository<InjectType>
    {
        void SetUnitWOrk(IUow uow); // this is for Unit of work injection
        void Add(InjectType obj); // Inmemory add
        void Update(InjectType obj); // Inmemory update
        List<InjectType> Search();
        void Save(); // Physical commit
    }

    public interface IUow // Unit of work design pattern.
    {
        void Commit();
        void Rollback();

    }


using InterfacesDAL;
using Microsoft.Data.SqlClient;
using System.Configuration;

namespace ADONetLibrary
{
    public class AdoNetUow : IUow
    {
        public SqlConnection Connection { get; set; }
        public SqlTransaction Transaction { get; set; }

        public AdoNetUow()
        {
            // Connection now is initialised in this Unit of work class 
            Connection = new SqlConnection(GetConnectionString());

            Connection.Open();
            Transaction = Connection.BeginTransaction();
        }
        public void Commit()
        {
            Transaction.Commit();
            Connection.Close();
        }

        public void Rollback() // Design Pattern :-Adapter pattern
        {
            Transaction.Dispose();
            Connection.Close();
        }

        static private string GetConnectionString()
        {
            // To avoid storing the connection string in your code,
            // you can retrieve it from a configuration file.            
            return ConfigurationManager.ConnectionStrings["Conn"].ConnectionString;
        }
    }
}
Move the task of opening the connection to the Unit of work and remove the connection string from the FactoryDAL and EFAbstractDal. Implement the virtual method  SetUnitofwork in the AbstracDal class.  In TemplateADO override SetUnitWork to open connection and  begin transaction. Close the connection if the only Unit of Work object is null.
// In clas AbstractDal
   public virtual void SetUnitWOrk(IUow uow)
        {
            
        }

/// Template ADO 
using System;
using DataAccessLibrary;
using InterfacesDAL;
using System.Data;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;

namespace ADONetLibrary
{
    public abstract class TemplateADO<InjectType>:AbstractDal<InjectType>
    {
        //Declaring connection and command objects
        protected SqlConnection objConn = null;
        protected SqlCommand objCommand = null;

        IUow uowObj = null;
        public override void SetUnitWOrk(IUow uow)
        {
            // In this one open the connection with transaction attacthed with it.    
            uowObj = uow;            
            objConn = ((AdoNetUow)uow).Connection;
            objCommand = new SqlCommand();
            objCommand.Connection = objConn;
            objCommand.Transaction = ((AdoNetUow)uow).Transaction;
            Save();
        }

        //Pass Inject the connection string as required by the base class
        public TemplateADO(string _connStr):base(_connStr)
        {

        }
        private void OpenConn()
        {

            if (objConn==null) // IF the transaction connection is not open then open a new connection without Transactoin
            {
                objConn = new SqlConnection(ConnectionString);
                objConn.Open();
                objCommand = new SqlCommand();
                objCommand.Connection = objConn;
            }           
        }
        private void CloseConn()
        {
            if (uowObj==null)
            {
                objConn.Close();
            }           
        }
        
        //This will be overridden by the child class as per their sql execution queries.
        // they can attach a search, insert or update queries. 
        protected abstract void ExecuteCommand(InjectType obj);
        protected abstract List<InjectType> ExecuteCommand();

        public void Execute(InjectType obj) // This does the insert 
        {
            ///Follow the fixed ADO.net template 
            OpenConn();
            ExecuteCommand(obj);
            CloseConn();

        }

        public List<InjectType> Execute() // returning the list 
        {
            ///Follow the fixed ADO.net template 
            List<InjectType> lst = null;
            OpenConn();
            lst =  ExecuteCommand();
            CloseConn();
            return lst;
        }

        // override the save function from the ABstractDal
        public override void Save()
        {
            foreach (InjectType obj in lstObj)
            {
                Execute(obj);
            }
        }
        public override List<InjectType> Search()
        {
            return Execute();
        }
    }
}
Register ADONetUow in Factory dal.
namespace FactoryDAL
{
    public static class FactoryDAL<INJECTTYPE>
    {
        static IUnityContainer oUnitCont = null;

        public static INJECTTYPE Create(string Type) // will return whatever type is injected
        {
            if (oUnitCont == null)
            {
                if (ConfigurationManager.GetSection("unity") != null)
                {
                    oUnitCont = new UnityContainer();

                    //Injecting the _connStr in the constructor as main base class Abstract Dal needs connection string to be injected in constructor.
                    //string _connStr = GetConnectionString();
                    //oUnitCont.RegisterType<IRepository<CustomerBase>, CustomerDAL>("ADODal", new InjectionConstructor(_connStr));
                    //oUnitCont.RegisterType<IRepository<CustomerBase>, EFCustomerDAL>("EFDal", new InjectionConstructor(_connStr));
                    
                    oUnitCont.RegisterType<IRepository<CustomerBase>, CustomerDAL>("ADODal");
                    oUnitCont.RegisterType<IRepository<CustomerBase>, EFCustomerDAL>("EFDal");
                    oUnitCont.RegisterType<IUow,AdoNetUow>("AdoUOW");
                }
            }
            return oUnitCont.Resolve<INJECTTYPE>(Type.ToString()); //resolves to any type injected

        }

        //for now we are just passing the connection string here manually 
        // we will have to change this to more elegant way later. 
        //static private string GetConnectionString()
        //{
        //    // To avoid storing the connection string in your code,
        //    // you can retrieve it from a configuration file.            
        //    return ConfigurationManager.ConnectionStrings["Conn"].ConnectionString;
        //}
        // Moved to Unit of work class 

    }
}

Check-in UI, if the transaction is successful then commit else it has to rollback:

 private void cmdUOW_Click(object sender, EventArgs e)
        {
            IUow uow = FactoryDAL<IUow>.Create("AdoUOW"); // Factory creates the IUow object
            try
            {     
                /// Here we are using mulitple Multiple Repositories to insert different customers. 
                /// 
                CustomerBase cust1 = new CustomerBase();
                cust1.BillDate = DateTime.Today;
                cust1.CustomerType = "Visitor";            
                cust1.FullName = "Cust1";   
                

                IRepository<CustomerBase> dal = FactoryDAL<IRepository<CustomerBase>>.Create(dbType);
                dal.Add(cust1); // In memory Add 
                dal.SetUnitWOrk(uow);
                //dal.Save(); // we don't need this for uow


                cust1 = new CustomerBase();
                cust1.BillDate = DateTime.Today;
                cust1.CustomerType = "OldCustomer";
                cust1.FullName = "Cust2";
                cust1.Address = "adsfasdfasdffdgsdfgsdfgdgfsdfgsdfgsdgfdsgfsdfgdsgfsdgfdsgfdsfgdsgfdsfgdsfgdsgfdsgfdsfgdsfgdsfg";
                
                IRepository<CustomerBase> dal1 = FactoryDAL<IRepository<CustomerBase>>.Create(dbType);
                dal1.Add(cust1); // In Memory Add
                dal1.SetUnitWOrk(uow);               
                //dal1.Save();
                /// Problem - with Repository pattern
                /// First transaction will be inserted
                /// second insert will have error due to Address length
                /// 
                uow.Commit(); // if successful then commit
                LoadGridADO();
                MessageBox.Show("Success");
            }
            catch (Exception ex)
            {
                uow.Rollback();// if error rollback
                MessageBox.Show(ex.Message);

            }
        }

Works, when an incorrect address is passed then the transaction is rolled back and when a small length address is passed then both the transactions are executed. Next up, implement a Unit of work for Entity Framework.

Create a class called EfUow which inherits the Dbcontext and IUow and implements all the methods of IUow.

using InterfacesDAL;
using Interfaces;
using Microsoft.EntityFrameworkCore;
using System.Configuration;
using Microsoft.Extensions.Logging;
namespace EFDALLibrary
{
    public class EfUoW : DbContext, IUow
    {

        DbContext context = null;
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Mapping code 
            // We are using EF code first approach for this demo. 
            //Currently we cannot use interface while mapping so we have to use our Customer Abstract class
            modelBuilder.Entity<CustomerBase>().ToTable("tblCustomer");
            
        }
      

        public EfUoW():base(GetSQLOptions())// provide connction string to the EF Dbcontext
        {
            
        }
        public void Commit()
        {
            SaveChanges();            
            
        }

        public void Rollback() // Adaptor pattern
        {
            Dispose();
        }

        private static DbContextOptions GetSQLOptions()
        {
            //creating dbcontextOptions by passing the connection String
            //                       
            return SqlServerDbContextOptionsExtensions.UseSqlServer
                (new DbContextOptionsBuilder(), ConfigurationManager.ConnectionStrings["Conn"].ConnectionString).Options;
        }
    }
}


/// Since Dbcontext OnModelCreating and provinding connection string is moved to UnitOfWork class we no longer neeed EFCustomerDAL class and so we need to make some changes in EFDalAbstract. Here we will remove the constructor that receives the connection string and initialise the EfUow so that if it gets directly accessed for normal trananction then it can handle standalone transactions. 
In SetUnitWork method assign dbcontext to the unit of work. 

using System;
using System.Collections.Generic;
using System.Linq;
using InterfacesDAL;
using Microsoft.EntityFrameworkCore;

namespace EFDALLibrary
{
    public class EFDalAbstract<INJECTTYPE> : IRepository<INJECTTYPE>
        where INJECTTYPE:class /// it is telling the that the type we are injecting is a class
    {

        DbContext dbcont = null; // this Dbcontext will come from UOW
        public EFDalAbstract()
        {
            dbcont = new EfUoW(); // If client doesn't call UOI it will initiated self contained transaction without commit and rollback
        }

        public void Add(INJECTTYPE obj)
        {
            /// Using the Entitytframework Set<>.Add that can be used to save the entity of type INJECTTYPE.          
            /// This only places the objects in memory ready for commit
            dbcont.Set<INJECTTYPE>().Add(obj);
        }

        public void Save()
        {
            dbcont.SaveChanges(); // This is for the physical committ to the database. 
            
        }

        public List<INJECTTYPE> Search()
        {
            //Return the collection of Injected Type objects via Entity Framework
            return dbcont.Set<INJECTTYPE>()
                .AsQueryable<INJECTTYPE>()
                .ToList<INJECTTYPE>();
        }

        public void SetUnitWOrk(IUow uow)
        {
            dbcont = ((EfUoW)uow); // Global Transaction comes into action 
        }

        public void Update(INJECTTYPE obj)
        {
            throw new NotImplementedException();
        }
    }
}
The next step is to register type EFUow in FactoryDal and since all the logic from EFCustomerDAL is moved to class EFUow remove it from FactoryDAL.
  oUnitCont.RegisterType<IRepository<CustomerBase>, CustomerDAL>("ADODal");                    
                    oUnitCont.RegisterType<IRepository<CustomerBase>, EFDalAbstract<CustomerBase>>("EFDal");
                    oUnitCont.RegisterType<IUow,AdoNetUow>("AdoUOW");
                    oUnitCont.RegisterType<IUow, EfUoW>("EfUow");
Finally, execute the EF unit of work from the UI and it should insert multiple rows for the correct address and it should roll back all transactions if any transaction fails.
 private void cmdUOW_Click(object sender, EventArgs e)
        {
            //IUow uow = FactoryDAL<IUow>.Create("AdoUOW"); // Factory creates the ADo.net unit of work object
            IUow uow = FactoryDAL<IUow>.Create("EfUow"); // Factory creates the Entity framework Unit of work object
            try
            {     
                /// Here we are using mulitple Multiple Repositories to insert different customers. 
                /// 
                CustomerBase cust1 = new CustomerBase();
                cust1.BillDate = DateTime.Today;
                cust1.CustomerType = "Visitor";            
                cust1.FullName = "Cust1";   
                

                IRepository<CustomerBase> dal = FactoryDAL<IRepository<CustomerBase>>.Create(dbType);
              
                dal.SetUnitWOrk(uow);
                dal.Add(cust1); // In memory Add 
                //dal.Save(); // we don't need this for uow


                cust1 = new CustomerBase();
                cust1.BillDate = DateTime.Today;
                cust1.CustomerType = "OldCustomer";
                cust1.FullName = "Cust2";
                cust1.Address = "adsfasdfasdffdgsdfgsdfg   adsfsdfasd asdf asdfasd asdf asd";
                
                IRepository<CustomerBase> dal1 = FactoryDAL<IRepository<CustomerBase>>.Create(dbType);
               
                dal1.SetUnitWOrk(uow);
                dal1.Add(cust1); // In Memory Add
                //dal1.Save();
                /// Problem - with Repository pattern
                /// First transaction will be inserted
                /// second insert will have error due to Address length
                /// 
                uow.Commit(); // if successful then commit
                LoadGridADO();
                MessageBox.Show("Success");
            }
            catch (Exception ex)
            {
                uow.Rollback();// if error rollback
                MessageBox.Show(ex.Message);

            }
        }

The Unit of work pattern is used to make various repository transactions into one unit that can utilize the Begin transaction, commit the transaction, and rollback transaction in decoupled data objects.

For the full source code of the project, go to https://github.com/rprateek/WellArchitectedApplication.

The same article is also published in Medium: Well-architected application development with design pattern | by Prateek Regmi | Medium

One Comment

  1. […] I have a post that covers the use of Repository pattern by showing the code that handles ADO.net and Entity Framework. The post is a bit lengthy, I find time I will definately derive the sections from there and will try to embed in this post itself. But for now you can refre to : Well architected application development. […]

Leave a Reply

Your email address will not be published. Required fields are marked *