February 22, 2021 06:01 by
Peter
What is Separation of Concern?
Wikipedia says “In computer science, separation of concerns (SoC) is a design principle for separating a computer program into distinct sections, such that each section addresses a separate concern. A concern is a set of information that affects the code of a computer program.”
As said concern is a set of information, in our application concern is known as modules or a set of responsibility, we use this principle to separate application module to manage scalable applications.
You can also think of separation the same as how we use layers in our application as follows:
However we can implement different tiers for databases as well.
The above architecture can be followed in any web or native (desktop) application, in order to use separation of concern.
How separation of concern in ASP.NET
A couple of years ago, Microsoft came up with ASP.NET MVC which is a superset of ASP.NET (now ASP.NET web form). Since before ASP.NET MVC there was Spring (JAVA), Ruby on Rail frameworks and may be others has already implemented MVC architecture.
ASP.NET MVC adds SoC for web (http) and separate Model (business), View(User Interface) and Controller (Processing data to view or vice versa), it gives responsibility to Model, View, Controller as follows :
You may have seen the above diagram in many articles. Herethe model is responsible to handle business logic, don’t get it confused with ViewModel as ViewModel are simple classes in ASP.NET MVC to bind strongly typed views.
Flexibility and its violation of SoC in ASP.NET MVC
As a ASP.NET MVC developer I feel it’s quite flexible to work with MVC as it’s a framework with extensibility as we can implement our own principles if required.
MVC framework uses loose coupling (another form of SoC) for every concern (modules). It’s recommended to use Model for business logic, controller for processing incoming requests and views to display information to end user.
But the actual problem is due to flexibility of ASP.NET MVC and it’s easy to violate these principles.
Examples of violation of MVC principle:
Using ViewBag or ViewData for passing data from controller to view:
// contoller
public ActionResult Index()
{
ViewBag.EmployeeData = getEmplyees(x => x.DOB > DateTime.Now);
}
// view
foreach(var employee in ViewBag.EmployeeData)
{
// using data
}
Above line of code doesn’t restrict developer, but it violates principle to use ViewModel to display data in view.
Using business logic in controller:
Public ActionResult Save(Employee model)
{
If(ModelState.IsValid)
{
_dbContext.Employees.Add(model)
}
Return RedirectToAction(“Success”);
}
Using above code, its violation of SRP because controller is having database logic to save information.
Using business logic in view:
@if(user.Role == ”Admin”)
{
//
}
Else
{
//
}
Using this we are using business logic in view which is only responsible to display information.
Apart from these, there area lot of code snippets you can find in your ASP.NET MVC project as well as online communities.
Recommendations
Where to put business logic:
It’s recommended to use a Service layer to implement business logic in your application as follows:
public class EmployeeService
{
IRepository _employeeRepository;
public EmployeeService(IRepository employeeRepository)
{
this._employeeRepository = employeeRepository;
}
public IEnumeratble < Employee > GetEmplyee(int id)
{
return _employeeRepository.FindBy(x => x.ID == id).FirstOrDefault();
}…………..
}
Repository pattern is a well known pattern for data access, here is a sample:
public class Repository < T > : IRepository < T > where T: class
{
private DbContext Context;
public Repository(DbContext ctx)
{
Context = ctx;
}
public virtual IQueryable < T > GetAll()
{
IQueryable < T > query = Context.Set < T > ().AsQueryable();
return query;
}
public IQueryable < T > FindBy(System.Linq.Expressions.Expression < Func < T, bool >> predicate)
{
IQueryable < T > query = Context.Set < T > ().Where(predicate);
return query;
}
}
Repository can be wrapped with a unit of work to save final changes all together. Here is sample unit of work interface which can be implemented for convenience, however it’s not required.
public interface IUnitOfWork
{
IRepository < TEntity > GetRepository < TEntity > () where TEntity: class;
void Save();
}
And finally we can inject (using DI) service in controller to use business objects.
public class EmployeeContoller
{
IService _employeeService;
Public EmployeeContoller(IService employeeService)
{
_employeeService = employeeService;
}…………
}
I hope readers will avoidthe above mentioned mistakes while working with ASP.NET MVC to deliver scalable applications.