Creating a Solid Architectural Foundation from scratch is not really that hard

By | October 20, 2015

I think I have been using S#arp Architecture for 5 years now and its such an amazing solution to combine different technologies to give you a pre-generated Architecture so all you have to do is concentrate on developing items like the User Interface and Business Logic, this solution takes the burden of designing your own architecture the right way, it’s all pre generated for you.  Sad to say there are no movements in this open source project so I have to part ways in using it after successfully deploying more than 2 dozen full-scale projects in 4 years of utilizing this solution and that’s just for 2 to 3 developers working 50% of the time.

Now its time to move on but what can I use as its replacement? well at the moment I think there is none but it’s not hard to start from scratch specially when you are getting some inspiration from a successful Architecture framework like S#arp.  So today I will show you how to move on specially if you’re coming from using S#arp architecture but this article is also helpful for those who whats to start experimenting in developing their own Architecture Framework for your projects, trust me its easy to understand and I will explain each layer as easily as possible.

The only hard part on this exercise is using what technologies to use but I decided to use the following in replacement to what S#arp uses.

On why I used them, I will point it out on a separate article.

S#arpReplacement
NHibernateEntity Framework, LINQ to Entites
NHibernate.ValidatorSystem.ComponentModel.DataAnnotations
Castle WindsorAutofac

I also used an almost similar pattern and naming conventions from S#arp, pattens like the Repository, Unit of Work, Query Object Pattern and Command Patterns this means it will be also easy to transition and we are following some best design practices.  So lets start.

To make it simple lets start with the assumption that we have an Employee Database that looks like this.

Architecture 01

So for this whole article we will be referring to how tables are related to this database.

Lets start with some Layers

  • First is your Domain, this is where your EF Framework Entities go, this is where your Data Model is stored.
  • Next is the Infrastructure, this is the place for our repository implementation.
  • Then we have the Presentation Layer where it will contain your different User Interfaces like Web and Mobile.
  • Then the Task Layer which will contain you Command and CommandHandlers.
  • We will also have the Framework Layer which I wull be using for other frameworks like reporting, mailing engine, helpers that is not directly a part of presentation layer but can be consumed by other layers like the Task, Presentation and Framework (itself).
  • Finally we have the Test layer which I guess does not need further explanation.

So if we have a Solution for that database design called Employees then it will look something like this.

Architecture 02

The Domain Layer

Lets start with Domain, this layer is quite straightforward since we are using Entity Framework.   All you need to do is add an ADO.NET Entity Data Model and let Visual Studio do the rest for you. Just name it as {YourProjectName}DataModel so for our Example it will be EmployeesDataModel.

Architecture 03

The since we already have a database design (BTW this is my preferred way of starting projects, from the Database), choose EF Designer from database

Architecture 04

You then choose your connection and I suggest you name it as {YourProjectName}Entities so in this example we name it as EmployeesEntities

Architecture 05

Now choose all the tables or views if you have one

Architecture 06

And its simple as that you have your Domain layer generated

Architecture 07

The Infrastructure Layer

Next let’s make your Infrastructure Layer by adding a class library project and naming it Employees.Infrastructure

In here we will add our repositories, the Generic Repositories and Repositories we need to extend on a Entity basis.  So lets create project folders for both like such

Architecture 08

Then let’s do some coding, you need the following interfaces which we will put in a folder called interfaces inside the repositories folder

IDatabaseFactory.cs

using System;
using Employees.Domain;
 
namespace Employees.Infrastructure.Repositories.Interfaces
{
    public interface IDatabaseFactory : IDisposable
    {
        EmployeesEntities Get();
    }
}

IUnitOfWork.cs

namespace Employees.Infrastructure.Repositories.Interfaces
{
    public interface IUnitOfWork
    {
        void Commit();
    }
}

IGenericRepository.cs

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
 
namespace Employees.Infrastructure.Repositories.Interfaces
{
    public interface IGenericRepository<T> where T : class
    {
        void AddOrUpdate(T entity);
        void Add(T entity);
        void Update(T entity);
        void Delete(T entity);
        void Delete(Expression<Func<Tbool>> where);
        T Get(int Id);
        T GetBy(Expression<Func<Tbool>> where);
        IEnumerable<T> GetAll();
        IEnumerable<T> GetMany(Expression<Func<Tbool>> where);
    }
}

Now on to the classes.

DatabaseFactory.cs

This is the class that will connect to your Data Context,  so in short it contains factory methods for creating Database objects.

using Employees.Domain;
using Employees.Infrastructure.Repositories.Interfaces;
 
namespace Employees.Infrastructure.Repositories
{
    public class DatabaseFactory : DisposableIDatabaseFactory
    {
        private EmployeesEntities ;
        public EmployeesEntities Get()
        {
            return _dataContext ?? (_dataContext = new EmployeesEntities());
        }
        protected override void DisposeCore()
        {
            if (_dataContext != null)
                _dataContext.Dispose();
        }
    }
}

UnitOfWork.cs

The unit of work class coordinates the work of different multiple repositories by creating a single database context class shared by all of them.

using Employees.Domain;
using Employees.Infrastructure.Repositories.Interfaces;
 
namespace Employees.Infrastructure.Repositories
{
    public class UnitOfWork : IUnitOfWork
    {
        private readonly IDatabaseFactory _databaseFactory;
        private EmployeesEntities _dataContext;
 
        public UnitOfWork(IDatabaseFactory databaseFactory)
        {
            this._databaseFactory = databaseFactory;
        }
 
        protected EmployeesEntities DataContext
        {
            get { return _dataContext ?? (_dataContext = _databaseFactory.Get()); }
        }
 
        public void Commit()
        {
            DataContext.SaveChanges();
        }
    }
}

GenericRepository.cs

This class contains all the generic methods that you can perform for your entities, methods like Add, Update and Delete.

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
using System.Linq.Expressions;
using Employees.Domain;
using Employees.Infrastructure.Repositories.Interfaces;
 
namespace Employees.Infrastructure.Repositories
{
    public class GenericRepository<T> : IGenericRepository<T> where T : class
    {
        private EmployeesEntities _dataContext;
        private readonly IDbSet<T> _dbset;
 
        protected GenericRepository(IDatabaseFactory databaseFactory)
        {
            DatabaseFactory = databaseFactory;
            _dbset = DataContext.Set<T>();
        }
 
        protected IDatabaseFactory DatabaseFactory
        {
            get;
            private set;
        }
 
        protected EmployeesEntities DataContext
        {
            get { return _dataContext ?? (_dataContext = DatabaseFactory.Get()); }
        }
        public virtual void AddOrUpdate(T entity)
        {
            _dbset.AddOrUpdate(entity);
        }
        public virtual void Add(T entity)
        {
            _dbset.Add(entity);
        }
        public virtual void Update(T entity)
        {
            _dbset.Attach(entity);
            _dataContext.Entry(entity).State = EntityState.Modified;
        }
        public virtual void Delete(T entity)
        {
            _dbset.Remove(entity);
        }
        public virtual void Delete(Expression<Func<Tbool>> where)
        {
            IEnumerable<T> objects = _dbset.Where<T>(where).AsEnumerable();
            foreach (T obj in objects)
                _dbset.Remove(obj);
        }
        public virtual T Get(int id)
        {
            return _dbset.Find(id);
        }
 
        public virtual IEnumerable<T> GetAll()
        {
            return _dbset.ToList();
        }
        public virtual IEnumerable<T> GetMany(Expression<Func<Tbool>> where)
        {
            return _dbset.Where(where).ToList();
        }
        public T GetBy(Expression<Func<Tbool>> where)
        {
            return _dbset.Where(where).FirstOrDefault<T>();
        }
    }
}

Disposable.cs

This is for Garbage Collection, making sure we clear up the resources used.

namespace Employees.Infrastructure.Repositories
{
    using System;
 
    public class Disposable : IDisposable
    {
        private bool _isDisposed;
 
        ~Disposable()
        {
            Dispose(false);
        }
 
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        private void Dispose(bool disposing)
        {
            if (!_isDisposed && disposing)
            {
                DisposeCore();
            }
 
            _isDisposed = true;
        }
 
        protected virtual void DisposeCore()
        {
        }
    }   
}

These classes will handle all generic repository calls and garbage collection, as you can see from the interface items like Get, Find, Update, Delete are all handled.  For anything non generic it will go into the ExtendedRepository classes.  This means any repository that you would want to extend will go under this directory together with its interface, so if we use the database design we have above it would look something like this.

Architecture 10

On each classes and interface lets say we extend the Employees Entity then it would look something like this where inside the class you can add methods like GetByName or GetAllByTransactionDate.

EmployeesRepository.cs

This is a placeholder for other non Generic repository calls.

namespace Employees.Infrastructure.ExtendedRepositories.Employees
{
    using Domain;
    using Repositories;
    using Repositories.Interfaces;
 
    public class EmployeeRepository : GenericRepository<Employee>IEmployeeRepository
    {
        public EmployeeRepository(IDatabaseFactory databaseFactory)
            : base(databaseFactory)
            {
            }
    }
 
}

IEmployeesRepository.cs

The implementation of the EmployeeRepository class

namespace Employees.Infrastructure.ExtendedRepositories.Employees
{
    using Domain;
    using Repositories.Interfaces;
 
    public interface IEmployeeRepository : IGenericRepository<Employee>
    {
    }
 
}

The Framework Layer

Same as the Infrastructure Layer this will be the same project type, a class library.

This layer is quite simple, you might not even use it but for my projects I use it for other frameworks like reporting, mailing engine, helpers that is not directly a part of presentation layer but can be consumed by other layers like the Task, Presentation and Framework (itself).

Now for our sample we just add one class here which defines ValidationResult we will be using on our CommandProcessor under the Tasks Layer

Architecture 09

ValidationResult codes look like this, it will contain definition of each ValidationResult when used.

namespace Employees.Framework.Common
{
    public class ValidationResult
    {
        public ValidationResult()
        {
        }
 
        public ValidationResult(string memeberNamestring message)
        {
            MemberName = memeberName;
            Message = message;
        }
 
        public ValidationResult(string message)
        {
            Message = message;
        }
 
        public string MemberName { getset; }
 
        public string Message { getset; }
    }
}

The Task Layer

Again this will be a class library project.  Now this layer will handle the Command and CommandHandlers for each of your Database Entities, we will also create generic classes for these methods.

CommandHandlerNotFoundException.cs

This class will take care of non existent command handlers.

using System;
 
namespace Employees.Tasks.Base
{
    public class CommandHandlerNotFoundException : Exception
    {
        public CommandHandlerNotFoundException(Type type) : base(string.Format("Command handler not found for command type: {0}"type))
        {
        }
    }
}

CommandProcessor.cs

This class is responsible for processing commands

using System.Collections.Generic;
using System.Web.Mvc;
using Employees.Framework.Common;
using Employees.Tasks.Base.Interface;
 
namespace Employees.Tasks.Base
{
    public class CommandProcessor : ICommandProcessor
    {
         public ICommandResult Process<TCommand>(TCommand commandwhere TCommandICommand
        {    
            var handler = DependencyResolver.Current.GetService<ICommandHandler<TCommand>>();
            if (handler == null)
            {
                throw new CommandHandlerNotFoundException(typeof(TCommand));
            }  
            return handler.Execute(command);
 
        }
        public IEnumerable<ValidationResult> Validate<TCommand>(TCommand commandwhere TCommand : ICommand
        {
            var handler = DependencyResolver.Current.GetService<IValidationHandler<TCommand>>();
            if (handler == null)
            {
                throw new ValidationHandlerNotFoundException(typeof(TCommand));
            }  
            return handler.Validate(command);
        }
    }
    
}

CommandResult.cs

This class will handle result executed from the Command Handler

using Employees.Tasks.Base.Interface;
 
namespace Employees.Tasks.Base
{
    public class CommandResult : ICommandResult
    {
        public CommandResult(bool success)
        {
            Success = success;
        }
 
        public bool Success { getprotected set; }
    }
}

CommandResults.cs

Similar with the Command Result but this is more for a collection.

using System.Collections.Generic;
using System.Linq;
using Employees.Tasks.Base.Interface;
 
namespace Employees.Tasks.Base
{ 
    public class CommandResults : ICommandResults
    {
        private readonly List<ICommandResult> _results = new List<ICommandResult>();
 
        public void AddResult(ICommandResult result)
        {
            _results.Add(result);
        }
 
        public ICommandResult[] Results
        {
            get
            {
                return _results.ToArray();
            }
        }
 
        public bool Success
        {
            get
            {
                return _results.All<ICommandResult>(result => result.Success);
            }
        }
    }
}

ValidationHandlerNotFoundException.cs

Takes care of any Validation Handler that is not found.

using System;
 
namespace Employees.Tasks.Base
{
     public class ValidationHandlerNotFoundException : Exception
    {
         public ValidationHandlerNotFoundException(Type type)
            : base(string.Format("Validation handler not found for command type: {0}"type))
        {
        }
    }
}

And the interfaces would look like this

ICommand.cs

namespace Employees.Tasks.Base.Interface
{
    public interface ICommand  { }
}

ICommandHandler.cs

namespace Employees.Tasks.Base.Interface
{
    public interface ICommandHandler<in TCommand> where TCommandICommand
    {
        ICommandResult Execute(TCommand command);
    }
}
 

ICommandProcessor.cs

using System.Collections.Generic;
using Employees.Framework.Common;
 
namespace Employees.Tasks.Base.Interface
{
    public interface ICommandProcessor
    {
        ICommandResult Process<TCommand>(TCommand commandwhere TCommand : ICommand;
        IEnumerable<ValidationResult> Validate<TCommand>(TCommand commandwhere TCommand : ICommand;
    }
}

ICommandResult.cs

namespace Employees.Tasks.Base.Interface
{
    public interface ICommandResult
    {
        bool Success { get; }
    }
}
 

ICommandResults.cs

namespace Employees.Tasks.Base.Interface
{
    public interface ICommandResults
    {
        ICommandResult[] Results { get; }
 
        bool Success { get; }
    }
}

IValidationHandler.cs

using System.Collections.Generic;
using Employees.Framework.Common;
 
namespace Employees.Tasks.Base.Interface
{
    public interface IValidationHandler<in TCommand> where TCommand : ICommand
    {
        IEnumerable<ValidationResult>  Validate(TCommand command);
    }
}

Now for the specific Delete, Update and Add Commands and CommandHandlers for each entity it would be coded like this.  Lets say we use the Employees Entity again as an example so here is how it looks.

DeleteEmployeeCommand.cs

Used for deleting entities

namespace Employees.Tasks.Commands.Employees
{
  #region Using Directives
    using Base.Interface;
  #endregion
 
    public class DeleteEmployeeCommand : ICommand
    {
        public DeleteEmployeeCommand(int employeeId)
        {
            EmployeeId = employeeId;
        }
 
        public int EmployeeId { getset; }
    }
}

SaveOrUpdateEmployeeCommand.cs

Used for Saving and Updating Entities, I joined them into one Method call

namespace Employees.Tasks.Commands.Employees
{
  #region Using Directives
    using System;
    using Base.Interface;
  #endregion
 
    public class SaveOrUpdateEmployeeCommand : ICommand
    {
        public SaveOrUpdateEmployeeCommand(
            int? employeeId,
            string firstName,
            string lastName,
            int departmentId,
            int positionId,
            int? employmentStatusTypeId,
            DateTime? birthdate,
            bool? isActive
            )
        {
            EmployeeId = employeeId;
            FirstName = firstName;
            LastName = lastName;
            DepartmentId = departmentId;
            PositionId = positionId;
            EmploymentStatusTypeId = employmentStatusTypeId;
            Birthdate = birthdate;
            IsActive = isActive;
        }
 
        public int? EmployeeId { getset; }
        public string FirstName { getset; }
        public string LastName { getset; }
        public int DepartmentId { getset; }
        public int PositionId { getset; }
        public int? EmploymentStatusTypeId { getset; }
        public DateTime? Birthdate { getset; }
        public bool? IsActive { getset; }
    }
}

DeleteEmployeeCommandHandler.cs

The handler for the Delete Command.

namespace Employees.Tasks.CommandHandlers.Employees
{
  #region Using Directives
    using Domain;
    using Infrastructure.Repositories.Interfaces;
    using Base;
    using Base.Interface;
    using Commands.Employees;
  #endregion
 
    public class DeleteEmployeeCommandHandler : ICommandHandler<DeleteEmployeeCommand>
    {
        private readonly IGenericRepository<Employee> _employeeRepository;
        private readonly IUnitOfWork _unitOfWork;
 
        public DeleteEmployeeCommandHandler(
            IGenericRepository<Employee> employeeRepository,
            IUnitOfWork unitOfWork
            )
        {
            _employeeRepository = employeeRepository;
            _unitOfWork = unitOfWork;
        }
 
        public ICommandResult Execute(DeleteEmployeeCommand command)
        {
            var employee = _employeeRepository.Get(command.EmployeeId);
            if (employee != null)
            {
                _employeeRepository.Delete(employee);
            }
            _unitOfWork.Commit();
 
            return new CommandResult(true);
        }
    }
}

SaveOrUpdateEmployeeCommandHandler.cs

The handler for Save and Update Command

namespace Employees.Tasks.CommandHandlers.Employees
{
  #region Using Directives
    using Domain;
    using Infrastructure.Repositories.Interfaces;
    using Base;
    using Base.Interface;
    using Commands.Employees;
  #endregion
 
    public class SaveOrUpdateEmployeeCommandHandler : ICommandHandler<SaveOrUpdateEmployeeCommand>
    {
        private readonly IGenericRepository<Department> _departmentRepository;
        private readonly IGenericRepository<Position> _positionRepository;
        private readonly IGenericRepository<EmploymentStatusType> _employmentStatusTypeRepository;
        private readonly IGenericRepository<Employee> _employeeRepository;
        private readonly IUnitOfWork _unitOfWork;
 
        public SaveOrUpdateEmployeeCommandHandler(
            IGenericRepository<Department> departmentRepository,
            IGenericRepository<Position> positionRepository,
            IGenericRepository<EmploymentStatusType> employmentStatusTypeRepository,
            IGenericRepository<Employee> employeeRepository,
            IUnitOfWork unitOfWork)
        {
            _departmentRepository = departmentRepository;
            _positionRepository = positionRepository;
            _employmentStatusTypeRepository = employmentStatusTypeRepository;
            _employeeRepository = employeeRepository;
            _unitOfWork = unitOfWork;
        }
 
        public ICommandResult Execute(SaveOrUpdateEmployeeCommand command)
        {           
            var employee = command.EmployeeId.HasValue
                ? _employeeRepository.Get(command.EmployeeId.Value)
                : new Employee();
 
            employee.FirstName = command.FirstName;
            employee.LastName = command.LastName;
            employee.Department = _departmentRepository.Get(command.DepartmentId);
            employee.Position = _positionRepository.Get(command.PositionId);
            if (command.EmploymentStatusTypeId != null)
                employee.EmploymentStatusType = _employmentStatusTypeRepository.Get(command.EmploymentStatusTypeId.Value);
            employee.Birthdate = command.Birthdate;
            employee.IsActive = command.IsActive;
 
            _employeeRepository.AddOrUpdate(employee);
            _unitOfWork.Commit();
 
            command.EmployeeId = employee.EmployeeId;
            return new CommandResult(true);
        }
    }
}

So I will leave it up to you to do the same with the remaining entities.  For the project structure it will look like this

Architecture 11

The Presentation Layer

For this part we will just use a normal ASP.Net MVC site, so lets create them first by adding one

Architecture 12

Then lets choose Windows Authentication and Rename the Tests Project.

Architecture 13

Now add the needed nuget references needed.  For this project lets use the latest EntityFramework, the latest ASP.Net MVC

Architecture 14

As well as the Autofac and Autofac ASP.Net MVC 5 Integration which we will be using for Dependency Injection

Architecture 15

Now you’re all set, lets do some coding.  Lets start with services, this are the group of classes that will be used to set values to our ViewModels, we do not use the Repositories as they are for Entities not the ViewModels.  So again for example we have Employees then the Query would be coded like such.

EmployeesQuery.cs

You can add methods here specific to your controller but for our example we just need a Get, GetAll and GetForeignKeys Methods

namespace Employees.Web.Controllers.Queries.Employees
{
  #region Using Directives
    using System.Collections.Generic;
    using System.Linq;
    using Domain;
    using Infrastructure.Repositories.Interfaces;
    using System.Web.Mvc;
    using ViewModels.Employees  #endregion
 
    public class EmployeesQuery : IEmployeesQuery
    {
        private readonly IGenericRepository<Department> _departmentsRepository;
        private readonly IGenericRepository<Position> _positionsRepository;
        private readonly IGenericRepository<EmploymentStatusType> _employmentStatusTypesRepository;
        private readonly IGenericRepository<Employee> _employeesRepository;
 
        public EmployeesQuery(
            IGenericRepository<Department> departmentsRepository,
            IGenericRepository<Position> positionsRepository,
            IGenericRepository<EmploymentStatusType> employmentStatusTypesRepository,
            IGenericRepository<Employee> employeesRepository)
        {
            _employeesRepository = employeesRepository;
            _departmentsRepository = departmentsRepository;
            _positionsRepository = positionsRepository;
            _employmentStatusTypesRepository = employmentStatusTypesRepository;
        }
 
        public EmployeesViewModel Get(int id)
        {
            var employee = _employeesRepository.Get(id);
            if (employee == nullreturn null;
            var viewModel = new EmployeesViewModel
                {
 
                    EmployeeId = employee.EmployeeId,
                    FirstName = employee.FirstName,
                    LastName = employee.LastName,
                    DepartmentId = employee.DepartmentId,
                    PositionId = employee.PositionId,
                    EmploymentStatusTypeId = employee.EmploymentStatusTypeId,
                    Birthdate = employee.Birthdate,
                    IsActive = employee.IsActive,
                };
 
            viewModel.EmployeesForeignKeysViewModel = GetForeignKeysViewModel();
 
            return viewModel;
        }
 
        public EmployeesGridViewModel GetAll()
        {
            var viewModel = new EmployeesGridViewModel();
            var employees = (from employee in _employeesRepository.GetAll()
                select new EmployeesViewModel
                {
                    EmployeeId = employee.EmployeeId,
                    FirstName = employee.FirstName,
                    LastName = employee.LastName,
                    DepartmentId = employee.DepartmentId,
                    PositionId = employee.PositionId,
                    EmploymentStatusTypeId = employee.EmploymentStatusTypeId,
                    Birthdate = employee.Birthdate,
                    IsActive = employee.IsActive,
                }).ToList();
 
            viewModel.Employees = employees;
            viewModel.EmployeesForeignKeysViewModel = GetForeignKeysViewModel();
 
            return viewModel;
        }
        public EmployeesForeignKeysViewModel GetForeignKeysViewModel()
        {
            var viewModel = new EmployeesForeignKeysViewModel
            {
                Departments = (from x in _departmentsRepository.GetAll() select new SelectListItem {Value = x.DepartmentId.ToString(), Text = x.Name}).ToList(),
                Positions = (from x in _positionsRepository.GetAll() select new SelectListItem {Value = x.PositionId.ToString(), Text = x.Name}).ToList(),
                EmploymentStatusTypes = (from x in _employmentStatusTypesRepository.GetAll() select new SelectListItem {Value = x.EmploymentStatusTypeId.ToString(), Text = x.Name}).ToList(),
            };
 
            return viewModel;
        }
    }
}

IEmployeesQuery.cs

namespace Employees.Web.Controllers.Queries.Employees
{
    using System.Collections.Generic;
    using ViewModels.Employees;
 
    public interface IEmployeesQuery
    {
        EmployeesViewModel Get(int id);
 
        EmployeesGridViewModel GetAll();
 
        EmployeesForeignKeysViewModel GetForeignKeysViewModel();
 
    }
}

The View Models would look like this and what I did is divided them into 3 types of view models, one for individual ViewModel to Entity Mapping, another for use in Grids or any Collections, and the third one is a sub ViewModel for Foreign Keys.  So in our example it would look like this

EmployeesViewModel.cs

For a single Entity with attached Foreign keys

namespace Employees.Web.Controllers.ViewModels.Employees
{
    using System;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Collections.Generic;
    using System.Web.Mvc;
 
    public class EmployeesViewModel
    {
        [DisplayName("Employee Id")]
        public int? EmployeeId { getset; }
 
        [DisplayName("First Name")]
        [MaxLength(50)]
        [Required]
        public string FirstName { getset; }
 
        [DisplayName("Last Name")]
        [MaxLength(50)]
        [Required]
        public string LastName { getset; }
 
        [DisplayName("Department Id")]
        [Required]
        public int DepartmentId { getset; }
 
        [DisplayName("Position Id")]
        [Required]
        public int PositionId { getset; }
 
        [DisplayName("Employment Status Type Id")]
        public int? EmploymentStatusTypeId { getset; }
 
        [DisplayName("Birthdate")]
        [DataType(DataType.Date)]
        public DateTime? Birthdate { getset; }
 
        [DisplayName("Is Active")]
        public bool? IsActive { getset; }
 
        public EmployeesForeignKeysViewModel EmployeesForeignKeysViewModel { getset; }
 
    }

EmployeesGridViewModel.cs

For a multiple similar Entity with attached Foreign keys

namespace Employees.Web.Controllers.ViewModels.Employees
{
    using System;
    using System.Collections.Generic;
    using System.Web.Mvc;
 
    public class EmployeesGridViewModel
    {
        public IList<EmployeesViewModel> Employees { getset; }
 
        public EmployeesForeignKeysViewModel EmployeesForeignKeysViewModel { getset; }
 
    }
}

EmployeesForeignKeysViewModel.cs

Model for foreign keys that are exposed as a Collection of SelectListItem so we can easily use them for drop downs.

namespace Employees.Web.Controllers.ViewModels.Employees
{
    using System.Collections.Generic;
    using System.Web.Mvc;
 
    public class EmployeesForeignKeysViewModel
    {
        public IList<SelectListItem> Departments { getset; }
 
        public IList<SelectListItem> Positions { getset; }
 
        public IList<SelectListItem> EmploymentStatusTypes { getset; }
 
    }
}

Now lets go to the controllers, this one will be straightforward it will be nearly as similar as the default ASP.Net MVC Template.  So again for example lets create one for EmployeesController.

EmployeesController.cs

If you will notice below POST and GET are separated.  All of the common Actions are implemented like Index, Details, Create, Edit and Delete.

namespace Employees.Web.Controllers
{
  #region Using Directives
    using System.Net;
    using System.Web.Mvc;
    using Tasks.Base.Interface;
    using Tasks.Commands.Employees;
    using Queries.Employees;
    using Web.Controllers.ViewModels.Employees;
    using Queries.Departmentsusing Queries.Positionsusing Queries.EmploymentStatusTypes  #endregion
 
    public class EmployeesController : Controller
    {
        private readonly IEmployeesQuery _employeesQuery;
        private readonly IDepartmentsQuery _departmentsQuery;
        private readonly IPositionsQuery _positionsQuery;
        private readonly IEmploymentStatusTypesQuery _employmentStatusTypesQuery;
        private readonly ICommandProcessor _commandProcessor;
 
        public EmployeesController(
            IEmployeesQuery employeesQuery,
            IDepartmentsQuery departmentsQuery,
            IPositionsQuery positionsQuery,
            IEmploymentStatusTypesQuery employmentStatusTypesQuery,
            ICommandProcessor commandProcessor)
        {
            _departmentsQuery = departmentsQuery;
            _positionsQuery = positionsQuery;
            _employmentStatusTypesQuery = employmentStatusTypesQuery;
            _employeesQuery = employeesQuery;
            _commandProcessor = commandProcessor;
        }
 
        // GET: Employees
        public ActionResult Index()
        {           
            var viewModel = _employeesQuery.GetAll();
            return View(viewModel);
        }
 
        // GET: Employees/Details/1
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
 
            var viewModel = _employeesQuery.Get(id.Value);
 
            if (viewModel == null)
            {
                return HttpNotFound();
            }
            return View(viewModel);
        }
 
        // GET: Employees/Create
        public ActionResult Create()
        {
            var viewModel = new EmployeesViewModel();
            viewModel.EmployeesForeignKeysViewModel = _employeesQuery.GetForeignKeysViewModel();
 
            return View(viewModel);
        }
 
        // POST: Employees/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(EmployeesViewModel viewModel)
        {
            if (ModelState.IsValid)
            {
                var command = new SaveOrUpdateEmployeeCommand(
                                viewModel.EmployeeId,
                                viewModel.FirstName,
                                viewModel.LastName,
                                viewModel.DepartmentId,
                                viewModel.PositionId,
                                viewModel.EmploymentStatusTypeId,
                                viewModel.Birthdate,
                                viewModel.IsActive
                    );
 
                if (ModelState.IsValid)
                {
                    _commandProcessor.Process(command);
                    viewModel.EmployeeId = command.EmployeeId;
                }
 
                return RedirectToAction("Index");
            }
 
            return View(viewModel);
        }
 
        // GET: Employees/Edit/1
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
 
            var viewModel = _employeesQuery.Get(id.Value);
 
            if (viewModel == null)
            {
                return HttpNotFound();
            }
            return View(viewModel);
        }
 
        // POST: Employees/Edit/1
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(EmployeesViewModel viewModel)
        {
            if (ModelState.IsValid)
            {
 
                var command = new SaveOrUpdateEmployeeCommand(
                                viewModel.EmployeeId,
                                viewModel.FirstName,
                                viewModel.LastName,
                                viewModel.DepartmentId,
                                viewModel.PositionId,
                                viewModel.EmploymentStatusTypeId,
                                viewModel.Birthdate,
                                viewModel.IsActive
                    );
 
                if (ModelState.IsValid)
                {
                    _commandProcessor.Process(command);
                    viewModel.EmployeeId  = command.EmployeeId ;
                }
 
                return RedirectToAction("Index");
            }
 
            return View(viewModel);
        }
 
        // GET: Employees/Delete/1
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            var viewModel = _employeesQuery.Get(id.Value);
 
            if (viewModel == null)
            {
                return HttpNotFound();
            }
            return View(viewModel);
        }
 
        // POST: Employees/Delete/1
        [HttpPostActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
 
            var command = new DeleteEmployeeCommand(id);
            _commandProcessor.Process(command);
 
            return RedirectToAction("Index");
        }
    }
}

Now for the views I will leave it up to you, it will depend on your requirement.

Finally lets do some Dependency Injection, we will be using AutoFac in this instance and here is how it all hangs together.

Bootstrapper.cs

The main class to inject dependencies for your Controller, Query, Repository and Tasks.

using System.Data.Entity;
using System.Web.Mvc;
using Autofac;
using Autofac.Integration.Mvc;
using Employees.Domain;
 
namespace Employees.Web.DependencyInjection
{
    public class Bootstrapper
    {
        public static ContainerBuilder Builder;
 
        public static void Initialise()
        {
            Builder = new ContainerBuilder();
            
            ControllerInstaller.Install();
            QueryInstaller.Install();
            RepositoryInstaller.Install();
            TaskInstaller.Install();
 
            var container = Builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }
        
    }
}

ControllerInstaller.cs

Registers your Controllers.

using System.Reflection;
using Autofac.Integration.Mvc;
 
namespace Employees.Web.DependencyInjection
{
    public class ControllerInstaller
    {
        public static void Install()
        {
            Bootstrapper.Builder.RegisterControllers(Assembly.GetExecutingAssembly());
 
        }
    }
}

QueryInstaller.cs

Registers Assembly Types in your Web Project that ends in Query.

using System.Reflection;
using Autofac;
 
namespace Employees.Web.DependencyInjection
{
    public class QueryInstaller
    {
        public static void Install()
        {
            Bootstrapper.Builder.RegisterAssemblyTypes(Assembly.Load("Employees.Web"))
                .Where(t => t.Name.EndsWith("Query"))
                .AsImplementedInterfaces()
                .InstancePerLifetimeScope();
 
        }
    }
}

RepositoryInstaller.cs

Registers all your Generic Types in your Tasks Layer, this also registers the Repository Assembly types in your Infrastructure Layer.

using System.Reflection;
using Autofac;
using Employees.Infrastructure.Repositories;
using Employees.Infrastructure.Repositories.Interfaces;
 
namespace Employees.Web.DependencyInjection
{
    public class RepositoryInstaller
    {
        public static void Install()
        {
            //Register Generic Repositories
            Bootstrapper.Builder.RegisterType<UnitOfWork>()
                .As<IUnitOfWork>()
                .InstancePerLifetimeScope();
 
            Bootstrapper.Builder.RegisterType<DatabaseFactory>()
                .As<IDatabaseFactory>()
                .InstancePerLifetimeScope();
 
            Bootstrapper.Builder.RegisterAssemblyTypes(Assembly.Load("Employees.Infrastructure"))
                .Where(t => t.Name.EndsWith("Repository"))
                .AsImplementedInterfaces()
                .InstancePerLifetimeScope();
        }
    }
}

TaskInstaller.cs

Registers your Command Processors, Command Handlers and Validation Handlers.

using System.Reflection;
using Autofac;
using Employees.Tasks.Base;
using Employees.Tasks.Base.Interface;
 
namespace Employees.Web.DependencyInjection
{
    public class TaskInstaller
    {
        public static void Install()
        {
            var services = Assembly.Load("Employees.Tasks");
 
            Bootstrapper.Builder.RegisterType<CommandProcessor>()
                .As<ICommandProcessor>()
                .InstancePerLifetimeScope();
 
            Bootstrapper.Builder.RegisterAssemblyTypes(services)
                .AsClosedTypesOf(typeof(ICommandHandler<>))
                .InstancePerLifetimeScope();
 
            Bootstrapper.Builder.RegisterAssemblyTypes(services)
                .AsClosedTypesOf(typeof(IValidationHandler<>))
                .InstancePerLifetimeScope();
        }
    }
}

The we call this from Global.asax in Application_Start() like this

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
 
        Bootstrapper.Initialise();
    }
}

Finally don’t forget to copy the connection string created on your Domain Layer from the App.config file to your Presentation Layers Web.config

So if you are wondering how it all hangs together then refer to the image below.

Architecture 16

For the dependencies on each layer please refer to the diagram below on how they relate to each other.

Architecture 17

That’s it, an easy to follow architecture based on best practice patterns inspired by S#arp Architecture, if you want to download the whole project so it saves you time in copying and pasting them as well as putting dependencies to each other you can do so here.  But in a weeks time I will be releasing an open source generator (which I used on the sample project) that will do all the hard-work for you following the same principle demonstrated in this article, if you had used my S#arpener before it would be something similar.

Recommended

One thought on “Creating a Solid Architectural Foundation from scratch is not really that hard

  1. Pingback: Effinator | Raymund Macaalay's Dev Blog

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.