1

I have an ASP.NET MVC3 in C# and Razor. The architecture of the application is divided in Data Access Layer (EF classes + Repository), Service Layer, Controller, ViewModels and View.

My application is a dashboard, it has to display statistics about products by using graphs.

Assume I have Product and ProductCategory tables and in a graph I have to display the percentage of sold Products per ProductCategory per Month. In the x-axis I have the months, in the y-axis the percentage ProductPerCategory/ProductTotal and therefore I have as many lines as ProductCategories.

In this case my Domain Model is made by Product and ProductCategory objects on the EF. My repository gives these domain objects to its upper layer (Service Layer).

My Business Model is made by the ProductGraph object and my Service Layer gives this business object to its upper layer (Controller).

My controller take this ProductGraphobject and map it to the View Model ProductGraphViewModel to be displayed in the view.

Is this distinction between models correct? Is there any shortfall or bad approach on the definition of the objects passed between layers?

CiccioMiami
  • 8,028
  • 32
  • 90
  • 151

2 Answers2

1

Well, you have my layman's thumbs up, this seems pretty standard. Some other things to consider are: 1) is your DAL/Service Layer interfaced? and 2) are you using dependency injection (passing these interfaces to the controller instantiation)? That way you can switch out implementations, or mock for unit tests easily.

This blog post might be of interest.

Scott Weaver
  • 7,192
  • 2
  • 31
  • 43
  • thanks for your reply! I use interfaces between Repository and Service Layer and between Service Layer and Controller. This way I can easily replace the components by conform to the interface. Suppose I have `IRepository` I can create a `FakeRepository` component that implements `IRepository`. I will use NUnit but I am new to DI. Is that what you meant? – CiccioMiami Feb 21 '12 at 10:14
  • yes, just that. :) Many mocking frameworks won't even work unless what you want to mock is an interface. Which makes sense when you think about it.... – Scott Weaver Feb 21 '12 at 10:20
  • my doubt was however about the business model created in the Service Layer. It "wraps" data after being process related to the domain model. The object is really similar to the View Model object. Is that a good practice? – CiccioMiami Feb 21 '12 at 10:38
  • if a totally separate, first-class view model seems like overkill, you *could* use ViewData, TempData, and ViewBag to store additional data without making a new class - not sure this is good design though. – Scott Weaver Feb 21 '12 at 10:44
  • 1
    I don't use ViewData, TempData and ViewBag because they act on the backgorund and I cannot test their behavior – CiccioMiami Feb 21 '12 at 11:08
1

I'll answer your question by asking a few of my own.

  1. What is your distinction between "Domain Model" and "Business Model"? Do each give more/less value than the other? Without knowing more, i would assume they are the same thing.

  2. What benefit does your Service layer give? People (myself included) have often fallen into the "Service layer" trap, when in fact it just wraps your Repository methods. You end up leaking ORM specifics to consuming layers, defeating the point of your abstraction in the first place.

It might help if you give us some code of an example flow between the layers.

And yes, @sweaver2112 is spot on about using DI. Simple setup, maximum benefit.

RPM1984
  • 72,246
  • 58
  • 225
  • 350
  • thanks for your reply. 1) I consider as domain model the model describing the entities involved in the application. I define as business model all the entities involved in a specific function of the application (in this case the dashboard). Business Models are created by the Service Layer, Domain Models are strictly dependent on the data source. 2) The boundaries of the application are not well defined. It has to become a portal, that's why I make use of the Service Layer, in order to minimize the code modification once new requirement has to be implemented. Please, give me your feedback – CiccioMiami Feb 21 '12 at 10:33
  • @CiccioMiami - you can't try and "future proof" your application like this. Your putting in extra effort which both makes your application more complex, and may be wasted effort. Build robust, well defined and simple code that does what is required of it, and nothing more. Then when you need to change, decide then. It sounds like your bussiness model adds no value at all, except projecting a domain model. Your mapping it a ViewModel anyway - so where's the "current" benefit? My advice? Repo pass domain/POCO to Controller, Controller map POCO/View Model. Simple, easy, makes sense. – RPM1984 Feb 21 '12 at 10:48
  • If you need to serve other "clients", then create another project, which can be a Web API (the soon to be released MVC4 makes this very easy). This can call directly into your Repository. If you try and have a common "service" layer which will attempt to do "everything", it will become massive. Create specific modules for specific requirements. – RPM1984 Feb 21 '12 at 10:52
  • you are right but this way when I need to add another function to the application I can just make another service layer (I think is a good approach I rely on your experience). Moreover, with your solution (repository - controller with POCOs) I must perform the business logic needed to create the statistics directly in the controller. I know it is a good practice to keep the controller slim. – CiccioMiami Feb 21 '12 at 10:57
  • @CiccioMiami. I use controller -> repo. And your spot on, its good practice to keep controller slim. Mine is, because I use the pipes & filters technique. A sample action of mine might look like: `var question = _repository.Find().Questions().ThatAreVisible().WrittenByThisUser(userId); return View(Mapper.Map(question));` – RPM1984 Feb 21 '12 at 20:12
  • wow I didn't know somebody actually used that pattern in MVC. Just out of curiosity, I guess you do everything by using extension methods and the yield keyword. Do you place all your extension methods in the repository namespace? This way you business logic is implemented in the repository, am I right? – CiccioMiami Feb 22 '12 at 08:28
  • @CiccioMiami - nope. I have a "Core" (domain) project, which has the POCO's used by EF, and all the pipes/filters (aka `IQueryable` extension methods). The repository project is very EF-specific, has no business logic at all. The only thing that the Repository does is expose generic methods, Find, Save, Delete, etc. The business logic is in the Core project, and consumed by the Controller, as in my previous comment. The Core project also has other business logic. This way i have good segregation, but minimal layers. – RPM1984 Feb 22 '12 at 20:17
  • I guess it is too complex for me to understand yet. Anyway I will deepen my knowledge, thanks for giving me the opportunity to open new horizons! – CiccioMiami Feb 23 '12 at 22:47
  • @CiccioMiami - no problems. If you want to learn more about the pipes and filters technique, watch this excellent video (from an excellent series overall): http://www.asp.net/mvc/videos/mvc-1/aspnet-mvc-storefront/aspnet-mvc-storefront-part-3-pipes-and-filters. Old, but still very relevant. – RPM1984 Feb 23 '12 at 22:56