What is your opinion on the following 'generic' code-first Onion-inspired ASP.NET MVC architecture:
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:
Mixed feelings about:
What I don't like:
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?
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:
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
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!
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.