27

Let's say I have a following repo pattern :

interface IGenericRepo<T> where T : class
{
     IEnumerable<T> GetAll();
     T GetById(object id);
     void Insert(T obj);
     void Update(T obj);
     void Delete(T obj);
     void Save();
}

interface ICustRepo : IGenericRepo<Cust>
{
     IEnumerable<Cust> GetBadCust();
     IEnumerable<Cust> GetGoodCust();
}

public class CustRepo : ICustRepo<Cust>
{
     //implement method here
}

then in my controller :

public class CustController
{
     private ICustRepo _custRepo;

     public CustController(ICustRepo custRepo)
     {
         _custRepo = custRepo;
     }

     public ActionResult Index()
     {
         var model = _custRepo.GetAll();
         return View(model);
     }

     public ActionResult BadCust()
     {
         var model = _custRepo.GetBadCust();
         return View(model); 
     }
}

Basically my pattern is something like

View <-> Controller -> Repo -> EF -> SQL Server

but I saw a lot of people doing this

View <-> Controller -> Service -> Repo -> EF -> SQL Server

So my question is :

  1. Why and when do I need service layer? Isn't that just add another unnecessary layer because every non-generic method is already implemented in ICustRepo?

  2. Should the service layer return DTO or my ViewModel?

  3. Should the service layer map 1:1 with my repo?

I've look around for few days but I haven't satisfied with the answers.

Any help will be appreciated and apologize for bad english.

Thank you.

UPDATE :

Difference between Repository and Service Layer?

I've already read this. I already know the difference between those 2, but I wanna know why and the purpose. So that doesn't answer my question

Community
  • 1
  • 1
tickwave
  • 3,335
  • 6
  • 41
  • 82
  • possible duplicate of [Difference between Repository and Service Layer?](http://stackoverflow.com/questions/5049363/difference-between-repository-and-service-layer) – David Arno Jul 02 '15 at 09:41
  • It is more accurate to say `EF -> Database` instead of `EF -> SQL Server`, but we got your point. – carloswm85 Aug 01 '22 at 17:13

2 Answers2

29

TL;DR

  1. See explanation below
  2. Layers above Service Layer should not be "aware" that more Layers exist below the Service Layer.
  3. Not necessarily, because you can have for example Data from 1 Type scattered across 2 tables and the "Core" only see's one, the Data Access Layer is responsible for "Grouping" and returning the Service Layer Type

Explanation

The typical 3-layer architecture is composed of Presentation Layer, Service/Domain Layer, Data Access Layer (DAL).

Think of the Service layer as the "Core" of your Application. Typically, the Service Layer only has Repository Interfaces that will be implemented in the DAL.

Therefore it allows you to "easily" switch the way you access data. The objects returned by the service layer should not be DAO's, because after all, the Presentation Layer doesn't even "know" the DAL exists.

Scenario: You have a 3-tiered Solution. Currently doesn't make much sense in having all layers.

      /-------------------\
      |      Web App      | <--- Presentation Layer
      |-------------------|
      |  Service Library  | <--- Service Layer
      |-------------------|
      | Entity Framework  | <--- Data Access
      \-------------------/

Now you want to have a REST API in ASP.NET MVC WebApi

      /--------------------\
      | Web App | REST API | <--- Presentation Layer
      |--------------------|
      |  Service Library   | <--- Service Layer
      |--------------------|
      |  Entity Framework  | <--- Data Access
      \--------------------/

Now, for example, you no longer want to use Entity Framework as your Data Access and want to use NHibernate.

      /--------------------\
      | Web App | REST API | <--- Presentation Layer
      |--------------------|
      |  Service Library   | <--- Service Layer
      |--------------------|
      |     NHibernate     | <--- Data Access
      \--------------------/

Notice that we added a new form of Presentation and switched the way we access Data, but the Service Layer never changed.

Typically, the Service Layer exposes Interfaces to be implemented in the Data Access Layer so we get the "abstraction" we want.

I implemented a project with this architecture in university. You can check out the code HERE

I hope this helped. Sorry if I'm so boring @ explaining things :P

Mason Tope
  • 40
  • 4
Driver
  • 538
  • 5
  • 12
  • 4
    "Notice that we added a new form of Presentation and switched the way we access Data, but the Service Layer never changed." That's all I need. thanks! – tickwave Jul 03 '15 at 02:20
  • Could you elaborate on why the Service layer uses interfaces to expose itself to clients? The interface seems to usually be a 1:1 match to the actual service class, why bother with the interface? – Halter Mar 31 '17 at 12:09
  • The interfaces are for the data access layer. You have for example a PersonRepository interface which is implemented by the Data Access, e.g.: PersonRepositoryNHibernateRepositoryImpl, which you configure a dependency injection container to inject the classed from the new module/project. – Driver Mar 31 '17 at 13:01
7

Ad.1 Service layer should be place for whole business logic. It's more about separate responsibilities:

  • Controller - responsible for prepare viewModel and pass to the specific view,

  • Repository - abstract layer responsible for gathering entities from DB

  • Service - responsible for complex logic. There is often case that service uses many entities to make some logic and return just DTO.

Ad.2 In my opinion service layer should return DTO objects which should be mapped to the viewModels in Controllers.

Ad.3 No this is not the case. In your example you can move GetBadCust and GetGoodCust from repo to the service and return some DTO

Piotr Czarnecki
  • 1,688
  • 3
  • 14
  • 22
  • 1
    If I move `GetBadCust`, `GetGoodCust` and every method for every logical action, then repo will only contains basic operation like Insert, Update, Delete, GetAll. Is that right? If that's the case, do you think I might be as well remove all repo and only keep the Generic? – tickwave Jul 02 '15 at 10:18
  • 1
    Yes, for me it sounds very reasonable - keep generic repo with only methods like: GetAll, GetById, Insert, Update, Delete and other more 'sexy' methods move to the service level. – Piotr Czarnecki Jul 02 '15 at 10:26
  • I am not expert but...what will happen if you move all methods from repo to service? e.g service need GetGood() then is requesting GetAll from repo (e.g 5000 customers) will transferred to your service and once there, service need to discard Bad (e.g 4000) and return Good (e.g 1000) correct? hence..your service become very slow by the time. Imagine more complex queries and more records in database for enterprise applications where you need to use inner joins with 5, 6 tables to get some values, unions and other stuffs. Isn't better to have the method in Repository directly? – Stelios Oct 19 '20 at 09:55