20

What is your opinion on the following 'generic' code-first Onion-inspired ASP.NET MVC architecture: screenshot of the solution explorer

The layers, explained:

Core - contain the Domain model. e.g. that's the business objects and their relationship. I am using Entity Framework to visually design the entities and the relations between them. It lets me generate a script for a database. I am getting automatically-generated POCO-like models, which I can freely refer to in the next layer (Persistence), since they are simple (i.e. they are not database-specific).

Persistence - Repository interface and implementations. Basically CRUD operations on the Domain model.

BusinessServices - A business layer around the repository. All the business logic should be here (e.g. GetLargestTeam(), etc). Uses CRUD operations to compose return objects or get/filter/store data. Should contain all business rules and validations.

Web (or any other UI) - In this particular case it's an MVC application, but the idea behind this project is to provide UI, driven by what the Business services offer. The UI project consumes the Business layer and has no direct access to the Repository. The MVC project has its own View models, which are specific to each View situation. I am not trying to force-feed it Domain Models.

So the references go like this: UI -> Business Services -> Repository -> Core objects

What I like about it:

  • I can design my objects, rather than code them manually. I am getting code-generated Model objects.
  • UI is driven/enforced by the Business layer. Different UI applications can be coded against the same Business model.

Mixed feelings about:

  • Fine, we have a pluggable repository implementation, but how often do you really have different implementations of the same persistence interface?
  • Same goes for the UI - we have the technical ability to implement different UI apps against the same business rules, but why would we do that, when we can simply render different views (mobile, desktop, etc)?
  • I am not sure if the UI should only communicate with the Business Layer via View models, or should I use Domain Models to transfer data, as I do now. For display, I am using view models, but for data transfer I am using Domain models. Wrong?

What I don't like:

  • The Core project is now referenced in every other project - because I want/have to access the Domain models. In classic Onion architecture, the core is referenced only by the next layer.
  • The DbContext is implemented in the .Core project, because it is being generated by the Entity Framework, in the same place where the .edmx is. I actually want to use the .EDMX for the visual model design, but I feel like the DbContext belongs to the Persistence layer, somewhere within the database-specific repository implementation.

As a final question - what is a good architecture which is not over-engineered (such as a full-blown Onion, where we have injections, service locators, etc) but at the same time provides some reasonable flexibility, in places where you would realistically need it?

Thanks

hyankov
  • 4,049
  • 1
  • 29
  • 46
  • You could use DTO's Data Transfer Objects residing in core and pass them around. Example: Service Layer methods return DTO to controllers and could be used to feed ViewModels – CrazyCoderz Apr 13 '13 at 13:45
  • @CrazyCoderz - so then we have 3 different model types, yes? 1) Domain Model (real business object), 2) DTO (for transfer between the Service and Controller/App), 3) ViewModels in the MVC? – hyankov Apr 13 '13 at 16:31
  • 1
    Hi, although this is a very interesting discussion, I'm afraid it is not on topic at StackOverflow, see the [faq](http://stackoverflow.com/faq#dontask), especially the part "there is no actual problem to be solved", i.e. not one (programming) problem that is likely to have one correct answer. – Gert Arnold Apr 13 '13 at 18:49
  • @GertArnold, hm, sorry - I didn't know that :) I saw a couple of similar opinion-probing threads. Is there a stackoverflow community where I could post my question? – hyankov Apr 14 '13 at 09:33
  • 1
    Not all of these questions are caught. Stack Exchange sites to a large extent are self regulating. But they all have one format: question and answer (Q&A), which means: a "good" question is likely to receive at least one answer that can be marked (accepted) as the one correct answer. It's always hard to select the "best" opinion. What you could do is take a look at [programmers](http://programmers.stackexchange.com/faq) and see if you can break down your question in one problem each. Of course after first checking if similar questions already have been answered. – Gert Arnold Apr 14 '13 at 09:43
  • You don't have domain objects, your classes end up anemic with what is being proposed. – Andy Mar 03 '14 at 23:38

4 Answers4

26

Wow, there’s a lot to say here! ;-)

First of all, let’s talk about the overall architecture.

What I can see here is that it’s not really an Onion architecture. You forgot the outermost layer, the “Dependency Resolution” layer. In an Onion architecture, it’s up to this layer to wires up Core interfaces to Infrastructure implementations (where your Persistence project should reside).

Here’s a brief description of what you should find in an Onion application. What goes in the Core layer is everything unique to the business: Domain model, business workflows... This layer defines all technical implementation needs as interfaces (i.e.: repositories’ interfaces, logging interfaces, session’s interfaces …). The Core layer cannot reference any external libraries and has no technology specific code. The second layer is the Infrastructure layer. This layer provides implementations for non-business Core interfaces. This is where you call your DB, your web services … You can reference any external libraries you need to provide implementations, deploy as many nugget packages as you want :-). The third layer is your UI, well you know what to put in there ;-) And the latest layer, it’s the Dependency Resolution I talked about above.

Direction of dependency between layers is toward the center.

Here’s how it could looks like:

Onion App Structure

The question now is: how to fit what you’ve already coded in an Onion architecture.

Core: contain the Domain model

Yes, this is the right place!

Persistence - Repository interface and implementations

Well, you’ll need to separate interfaces with implementations. Interfaces need to be moved into Core and implementations need to be moved into Infrastructure folder (you can call this project Persistence).

BusinessServices - A business layer around the repository. All the business logic should be here

This needs to be moved in Core, but you shouldn’t use repositories implementations here, just manipulate interfaces!

Web (or any other UI) - In this particular case it's an MVC application

cool :-)

You will need to add a “Bootstrapper“ project, just have a look here to see how to proceed.

About your mixed feelings:

I won’t discuss about the need of having repositories or not, you’ll find plenty of answers on stackoverflow.

In my ViewModel project I have a folder called “Builder”. It’s up to my Builders to discuss with my Business services interfaces in order to get data. The builder will receive lists of Core.Domain objects and will map them into the right ViewModel.

About what you don’t like:

In classic Onion architecture, the core is referenced only by the next layer.

False ! :-) Every layer needs the Core to have access to all the interfaces defined in there.

The DbContext is implemented in the .Core project, because it is being generated by the Entity Framework, in the same place where the .edmx is

Once again, it’s not a problem as soon as it’s really easy to edit the T4 template associated with your EDMX. You just need to change the path of the generated files and you can have the EDMX in the Infrastructure layer and the POCO’s in your Core.Domain project.

Hope this helps!

Community
  • 1
  • 1
MaxSC
  • 4,698
  • 2
  • 23
  • 36
  • Hi, thanks for your invaluable input. So if I understand correctly, I should get rid of the Business layer and integrate it in Core (interfaces), as long as it works only with interfaces, rather than implementations. Also Persistence should be split into two - Interfaces go into Core and implementations go into Infrastructure? I was a fool to think I am simplifying the [Onion architecture](http://onionarch.codeplex.com) that way... – hyankov Apr 15 '13 at 16:55
  • Yes, the idea is to work only with interfaces. But all your business, and only business, implemetations will go into Core (you can have a subfolder called /Services where you put all your business implemetations and one called /Interfaces where you put all your interfaces). For Persistence splitting, yes, that's it! Then, it will be up to the IOC to bind interfaces with the right implementations at run time! – MaxSC Apr 16 '13 at 08:00
  • Thanks. I got it [up to this point](http://i.imgur.com/GYOlWrJ.png). I think it is a great improvement over my initial structure. In the Core now I have the POCO, the business service (TeamService) and the IDataContext interface. In the Persistence/Infrastructure I have the EF IDataContext implementation. In the end my POCOs, DataContext and its interface is generated by T4 templates based on the EDMX design. So I draw in the EDMX and it propagates code for me in all appropriate layers. I am now fixing the final part - Bootstrap and UI :) – hyankov Apr 16 '13 at 08:51
  • Think about moving your EDMX within your Infrastructure folder. Just edit your .tt file to let it generate POCOs at the right place (should be something like ../Business/whatever/) – MaxSC Apr 16 '13 at 09:01
  • But the EDMX is now setup to only be used as a model designer. The POCOs and IDataContext are generated in the Domain folder, the EfDataContext is generated in the Infrastructure. – hyankov Apr 16 '13 at 09:06
  • Ok. Maybe next step would be to switch to code first and get rid of your EDMX ;-) But that's another story. – MaxSC Apr 16 '13 at 09:50
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/28300/discussion-between-hristo-yankov-and-freddy-communal-betclic) – hyankov Apr 16 '13 at 09:53
  • I don't like having a dependency on EF in Core so I would split out domain and have it depend on core. Another reason I use NHibernate though – CrazyCoderz Apr 16 '13 at 22:16
  • @CrazyCoderz Yes, that's what I'm doing (see picture above, Domain is splitted out). Moreover I'm using EF CodeFirst which, IMHO, is way better that deling with EDMX :-) – MaxSC Apr 17 '13 at 08:41
  • I realize this post is hold - but, where do you put the actual business logic (not just the service interfaces)? You say move BusinessServices to core - but no interface implementations should be in core. – Jack Oct 16 '13 at 02:35
  • @Jack You do have interface implementations in Core! Everything that is related to your business needs to be in Core and this includes business services implementation. – MaxSC Oct 16 '13 at 07:57
  • @MaxS-Betclic Can we add WF (as part of Business logic) to Core project? that means add WF libraries to Core. If not, where will be a better place, infrastructure? or UI? – Jaider Mar 05 '14 at 14:20
  • @Jaider you need to keep your Core layer technologically agnostic. No reference to any kind of framework should be done. I'm not really into WF, but you should be able to define the right interfaces, defining the expected behavior and then implement the WF part in the Infrastructure layer (as you would do with IRepositories interfaces defined in the Core and implemented them in Infrastucture with Entity Framework) – MaxSC Mar 05 '14 at 15:05
3

I inject my services into my controllers. The services return DTO's which reside in Core. The model you have looks good, I don't use the repository pattern but many people do. I is difficult to work with EF in this type of architecture which is why I chose to use Nhibernate.

A possible answer to your final question.

  1. CORE
  2. DOMAIN
  3. DI
  4. INFRASTRUCTURE
  5. PRESENTATION
  6. SERVICES
CrazyCoderz
  • 1,351
  • 1
  • 15
  • 30
  • Hi, would you please elaborate on the service injection part? Do you use some framework to do that? What is the difference between it and simply adding a reference to the service project? In the list you provided, why is Presentation before Services? – hyankov Apr 13 '13 at 16:54
  • Sorry for the delay. Yes I use Castle Windsor as my container. The Presentation layer holds the MVC project and any other UI – CrazyCoderz Apr 15 '13 at 12:31
2

In my opinion:

  • "In classic Onion architecture, the core is referenced only by the next layer." That is not true, Core should be reference by any layer... remember that Direction of dependency between layers is toward the center (Core).

enter image description here

"the layers above can use any layer beneath them" By Jeffrey Palermo http://jeffreypalermo.com/blog/the-onion-architecture-part-3/

  • About your EF, it is in the wrong place.... it should be in the Infrastructure layer not in the Core layer. And use POCO Generator to create the entities (POCO classes) in Core/Model. Or use a Auto-mapper so you can map Core Model (Business objects) to Entity Model (EF Entities)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Jaider
  • 14,268
  • 5
  • 75
  • 82
1

What you've done looks pretty good and is basically one of two standard architectures that I see a lot.

Mixed feelings about:

Fine, we have a pluggable repository implementation, but how often do you really have different implementations of the same persistence interface?

Pluggable is often touted as being good design but I've never once seen a team swap out a major implementation of something for something else. They just modify the existing thing. IMHO "pluggability" is only useful for being able to mock components for automated unit testing.

I am not sure if the UI should only communicate with the Business Layer via View models, or should I use Domain Models to transfer data, as I do now. For display, I am using view models, but for data transfer I am using Domain models. Wrong?

I reckon view models are a UI (MVC Web) concern, if you added a different type of UI for example it might not require view models or might need something different. So I think the Business layer should return domain entities and allow them to be mapped to view models in the UI layer.

What I don't like:

The Core project is now referenced in every other project - because I want/have to access the Domain models. In classic Onion architecture, the core is referenced only by the next layer.

As others have said this is quite normal. Usually everything ends up having a dependency on the Domain.

The DbContext is implemented in the .Core project, because it is being generated by the Entity Framework, in the same place where the .edmx is. I actually want to use the .EDMX for the visual model design, but I feel like the DbContext belongs to the Persistence layer, somewhere within the database-specific repository implementation.

I think this is a consequence of Entity Framework. If you used it in "Code First" mode you actually can - and usually do - have the context and repository in the Persistance layer with the Domain (represented as POCO classes) in what you've called Core.

As a final question - what is a good architecture which is not over-engineered (such as a full-blown Onion, where we have injections, service locators, etc) but at the same time provides some reasonable flexibility, in places where you would realistically need it?

As I touched on above I wouldn't worry about the need to swap things out except to allow for automated unit tests. Unless there is a specific requirement you know about that will make this very likely.

Good luck!

Community
  • 1
  • 1
Justin Ricketts
  • 236
  • 2
  • 5