Relaxed architecture DAL or anemic BLL?

Particularly for the sake of unit testing, I’m trying to implement an application with a layered architecture. I’m coding in C# and using ASP.NET Web API for the service layer. I’m aiming at a 3-layer architecture:

  1. Service Layer
  2. Business Logic Layer
  3. Data Access Layer

The Problem

I’m uncomfortable with having to choose between a relaxed architecture DAL or anemic BLL classes and I’m wondering whether it’s because I’m approaching this the wrong way. When I refer to “relaxed architecture DAL”, I mean a DAL that can be called by layers other than the BLL directly above it, i.e. the service layer.

My reason for not wanting a relaxed architecture DAL: makes it easy for business logic to be mistakenly bypassed.

My reason for not wanting anemic BLL classes: don’t want a plethora of classes that do nothing other than pass calls between the service layer and DAL.


Here’s some sample code. First, a service layer method supporting the registration of a student in a class:

public class ClassRegistrationController : ApiController
    private readonly BusinessLogic.ClassRegistration _classRegistrationLogic;

    public ClassRegistrationController(
        BusinessLogic.ClassRegistration classRegistrationLogic)
        _classRegistrationLogic = classRegistrationLogic;

    public IHttpActionResult RegisterForClass(
        int classId,
        [FromBody]ClassRegistrationRequest registrationRequest)
        catch (ClassFullException)
            return BadRequest("Cannot register for class, it is full");

        return Ok();

And the business logic class supporting it:

public class ClassRegistration
    private DataLayer.IClassDataLayer _classDataLayer;
    private DataLayer.IClassRegistrationDataLayer _classRegistrationDataLayer;

    public ClassRegistration(
        DataLayer.IClassDataLayer classDataLayer,
        DataLayer.IClassRegistrationDataLayer classRegistrationDataLayer)
        _classDataLayer = classDataLayer;
        _classRegistrationDataLayer = classRegistrationDataLayer;

    public void RegisterStudentForClass(int classId, int studentId)
        var classDetails = _classDataLayer.GetClassDetails(classId);

        if (classDetails.ClassIsFull)
            throw new ClassFullException();

        _classRegistrationDataLayer.AddStudentToClass(classId, studentId);

The data layer interfaces (implementation isn’t relevant to the question):

public interface IClassDataLayer
    Models.ClassDetails GetClassDetails(int classId);

public interface IClassRegistrationDataLayer
    int AddStudentToClass(int classId, int studentId);

Now, I think this all looks reasonable, and each class has a single (and not insignificant) responsibility. But, now let’s say I want to add a service layer method that exposes details of a class, like:

public IHttpActionResult GetClassDetails(int classId)
    var classDetails = _classDetailsGetter.GetClassDetails(classId);

    if (classDetails == null)
        return NotFound();

    return Ok(classDetails);

The question is, will _classDetailsGetter be an instance of a class from the DAL or from the BLL?

If it’s from the DAL, then I’m effectively saying it’s “OK” for the service layer to go directly to the DAL, which opens up the risk of, say, somebody doing maintenance on the RegisterForClass service layer method deciding to go directly to IClassDataLayer instead of BusinessLogic.ClassRegistration.

But if it’s from the BLL, then that BLL class would only be responsible for 1-to-1 call mapping, which also rubs me the wrong way. Like:

public class ClassDetailsLogic
    private readonly DataLayer.IClassDataLayer _classDataLayer;

    public ClassDetailsLogic(DataLayer.IClassDataLayer classDataLayer)
        _classDataLayer = classDataLayer;

    public Models.ClassDetails GetClassDetails(int classId)
        return _classDataLayer.GetClassDetails(classId);


Is there reason to favour the relaxed architecture DAL or the anemic BLL? Are my concerns regarding one (or the other) unfounded? Or is there something else altogether that I’m missing?


Data Transfer Objects (DTO’s) have one purpose, and one purpose only: to retrieve data from a database and work with it in an object-oriented form.

There’s no such thing as an “anemic BLL object.” It’s either a first-class BLL object, or it’s a DTO. It’s seldom both.

There are reasons why you have things like ViewModel objects. A View Model object contains data from your Model, but it’s tailored to a View. It’s not a DTO, at least not in the sense that you’re transferring data back and forth from a database. It is an object in its own right, having its own specific purpose.

So where does that leave your Business Logic Layer?

The purpose of a Business Logic Layer is to convert business domain operations (such as Transfer Money or Build Widget) into CRUD operations. It doesn’t actually perform the CRUD operations, though; that’s what your DAL and DTO’s do.

It seems like a lot of objects, doesn’t it? But your DTO’s are typically going to be generated by your Object-Relational Mapper, unless you plan on creating the database from your object domain (a perfectly valid technique).

Make use of partial classes.

So how do you marry your business logic code to your business objects? One way to do it is with partial classes. C# allows you to define your own class alongside the code-generated DTO, which will add your custom validation or whatever business logic you choose to add to the business domain object. Because your hand-written logic is in a separate class (having the same name), your code will be protected against being overwritten by the code-generated class, should you choose to re-generate your DTO’s. Your DAL classes will no longer be anemic, because you will have added your own intelligence to them via partial classes.


The two operations you are comparing cannot be compared. RegistrationStudentForClass is a commnand and GetClassDetails is a query. Commands and queries are very different in nature, that’s why implementing your query as your command looks a bit off.

Commands implement a use case, they have validation, logic, rules, etc. Your controller delegate all this to the business logic and your business logic will use a repository or such to retrieve and then save the data models involved (ideally transactionally).

Queries on the other hand, don’t have logic and don’t have side effects. That’s why you end up with nothing in your logic class. They are, as their name say, a query against your data store. The only “logic” they might have is making sure that the requester has access to the requested data. Some times you can do this in the controller, some times you need to parametrise your query. But there is
no point in using the same structure or classes than your commands and I actually recommend against it.

You will find this approach under the name CQRS. Most of the times it’s presented like a very complex pattern not recommended for small projects, but that’s because some people think that CQRS implies using Event Sourcing, separation of read and write data stores, eventual consistency, etc. But if you take it only as the bare minimum definition of the pattern, so separating the stack for reads and for writes, but using the same data store, then it becomes very simple and it makes a lot of sense.

So, my advice is:

Do all your writes/commands as you expose, with your logic classes and repositories to load and save back the data.

Implement the queries completely separate from your commands. Do not reuse logic, models nor repositories. There are many ways of doing this, but a simple one is: Define a query interface like IClassroomQueries with the query methods that you need (don’t let this grow too much, you don’t want to break ISP too much). Each query method should expect a query dto object with the query parameters (classId for example) and it should return a result dto with exacly the fields that the consumer needs (no more, no less). If you have different consumers with different needs, define a different query method or even a different interface. Now feel free to implement every query the way that works best for each scenario. Some queries might use EF mapped directly to the DTOs. Others might map DTOs to a view. Others might use a stored procedure. Queries are not about consistency or code reuse. They are about efficiently returning the right data.

I will stop here, but I can follow up with some more implementation details if you are interested.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *