I am still new to ASP.NET MVC world and still try to learn best practices and
best architecture patterns. Here comes one the things where i can't decide on my own and need community support:
I am not sure where I should put all of my business logic and how much of it could be in the controller. I know best would be if ALL business logic is implemented in my service layer. One of the biggest concerns I have is that I want to show not only simple model errors in the view I also want to show error messages in different places when more complex business validation was made. But when I have a service layer which does the full validation and that is completely decoupled from web layer (controller, views) then it makes more complex passing all the errors and assign to the correct view properties.
Which of the following options make more sense or is there no general recommendation?
Just high level examples. no correct syntax or naming :-)
Option 1:
Controller.Action(){
if(ModelState.IsValid){
ServiceLayer.IsAllowedMoreComplexCheck();
ServiceLayer.IsBusinessModelValidCheck1();
ServiceLayer.IsBusinessModelValidCheck2();
ServiceLayer.IsBusinessModelValidCheck3();
ServiceLayer.DoAction1();
ServiceLayer.DoAction2();
ServiceLayer.DoAction3();
ServiceLayer.SaveChanges();
}
}
Option 2:
Controller.Action(){
if(ModelState.IsValid){
ServiceLayer.IsAllowedMoreComplexCheck();
ServiceLayer.DoAllActions();
}
}
ServiceLayer.DoAllActions(){
ServiceLayer.IsBusinessModelValidCheck1();
ServiceLayer.IsBusinessModelValidCheck2();
ServiceLayer.IsBusinessModelValidCheck3();
ServiceLayer.DoAction1();
ServiceLayer.DoAction2();
ServiceLayer.DoAction3();
ServiceLayer.SaveChanges();
}
Option 3:
Controller.Action(){
if(ModelState.IsValid){
ServiceLayer.IsAllowedMoreComplexCheck();
ServiceLayer.IsBusinessModelValidAllChecks();
ServiceLayer.DoAllActions();
}
}
ServiceLayer.DoAllActions(){
ServiceLayer.DoAction1();
ServiceLayer.DoAction2();
ServiceLayer.DoAction3();
ServiceLayer.SaveChanges();
}
there are also few more options... but just to indicate what i am thinking about.
Every feedback is welcome.
Thanks!!!
Simon
As per my experience keep your business logic in service layer because I think by this way you keep the loose coupling motto of MVC intact. Yes it's true you need some extra code to handle validation and error but I think for a good enterprise level application you must design good architecture that must survive for a long time.
Best place to play with MVC is play with its pipeline and provide your custom logic for pipeline components.
For simple implementation you can do following things:-
You can create custom action attributes to do validation.
For error handling you can create custom error action attribute and provide your own OnException() method implementation by implementing IExceptionFilter interface in your custom error.
Refer this link for error handling in detail.
I am not sure where I should put all of my business logic and how much of it could be in the controller.
No business logic should be in controller. Now, what do you mean by putting in Service layer. Service layer should only handle purpose of servicing, Business logic should be in Business logic layer and should be independent of service layer too (what if you want to make changes to the way your service layer serve?).
One of the biggest concerns I have is that I want to show not only simple model errors in the view I also want to show error messages in different places when more complex business validation was made. But when I have a service layer which does the full validation and that is completely decoupled from web layer (controller, views) then it makes more complex passing all the errors and assign to the correct view properties.
In long run that will pay off. Error handling, exception handling should be thoroughly thought of when developing an application.
Related
I'm using ViewModels in MVC. I'm find them incredibly klutzy and wonder if I'm doing something wrong. (Let's leave Automapper out of this for the sake of discussion.) I use viewmodels to send data to the client as well as receive form submissions. Some properties are sent to the browser for display only, others are sent & retrieved (eg. fields).
I typically have to implement the following to make a viewmodel work:
1) Create a view model class
2) Create a general function to initialize the view model & copy the properties from my entities & other sources
3) Write more code to write some values from the viewmodel back to the entities (or other destination) on submission
4) If there are server side validation errors, I need to write more code (particularly messy) to repopulate the read-only parts of the viewmodel (which were included in the submission), while taking care to not overwrite the user submitted data.
For a simple property (eg. "myViewModel.FirstName") this requires code to be written in no less than 4 places. That's not including the stuff in the Domain and Views. This pattern seems fragile to me - it's easy to break code eg. forget to implement a change in all locations. Definitely not DRY.
Am I missing the point or do all patterns using ViewModel have this kind of klutziness?
I'm not sure what you find klutzy? MVC is about separation of concerns. Keeping your business logic, data layer and GUI code separate. This in itself makes your code easier to manage, easier to test and far less confusing to debug.
And lets look at your four points.
Point 1. Firstly is creating a POCO for your view model really that much of an issue? I'd say not, since you can accomplish this in around 3 lines of code, given your example. And should your model need to change, would it not be more beneficial for it to be in its own view model class rather than in code directly in every action method in every controller where you may have used it?
Points 2 + 3. Here you speak about going from data layer to logic layer to view and back again. This is the whole point of MVC. Just because you have to possibly code three classes (model, service, repository) to handle this transaction does not make this cumbersome, it makes it clean. Just imagine if you dumped all this together on the controller action method. How would you handle re-use? How would you prevent repetition of code in other actions or controllers? Things would start to get very difficult.
Point 4. I don't really see this as a valid argument since you can just pass back the model submitted by the user without any need to update it or edit it. By using data annotations and ModelState for validation it is very simple to create a clean and testable unit of code. So I imagine that its not the fact your using a ViewModel but perhaps more to do with your implementation.
I am probably over analyzing here, but with all the reading I have done on MVC, there seem to be so many opinions on how to do things.
Is there a "Best Practices" site or document out there that defines the responsibility of each piece of MVC?
The few questions I have, keep in mind I am using the EF/Repository&UnitOfWork/Service pattern are:
1) How to get the validation results (error messages, etc) of Domain Objects and Business Rules from the Service Layer to the View Models?
2) I am using Domain Objects and a Service Layer that does all the Business Logic, then I send the Domain Objects to the controllers and let them (via AutoMapper) convert them to View Models for the views. What other types of things are the responsibility of the controller? Is the following code OK? Is this too much logic in the controller?:
public ActionResult SomeAction()
{
var model = Mapper.Map<DomainObject, ViewModel>(service.QueryReposForData());
model.SomeCollectionForSelectList = Mapper.Map<IEnumerable<DomainObject>, IEnumerable<ViewModel>>(service.QueryReposForSelectListData());
return View(model);
}
I don't think that the only thing in a controller is one line that returns a view with an object graph mapped to view models?
3) I think it is OK to have properties on the ViewModels that can indicate to a view if something can be hidden for example and then perform that logic in the view? Example:
#if(Model.DisplaySomething)
{
<div>Something to show</div>
}
else
{
<div>Something else to show</div>
}
4) I was thinking of having my services return some sort of TransactionResult object back to the controllers on writes to make it the responsibility of the service to handle the transaction. So I would have an aggregate service that would start a transaction (UnitOfWork) do what ever it needed to do and then return this TransactionResult that could have error messages? I don't think I should make the controller responsible for managing the transaction, but rather have it just pass in a view model mapped to a domain object to the service and let it act on it?
5) Also, how much of ActionFilter's do you want to use? I know it is a huge extensibility point, but I often find myself trying to stuff all of the model creation into a filter.
Just opinions here based on how we work.
We keep our Controllers so skinny they are anorexic, in almost every case.
As for ViewModels, we follow the pattern of having a ViewModel for every view. The Controller loads it up with anything it needs, and kicks it off. From there, the ViewModel drives everything. In our world, the ViewModel is tied directly to the view and contains no code that would/could be used in other parts of the application. It interacts with any part of the larger 'Model' (service layer, etc) that it needs to and packages stuff up for the View to consume.
For your #3 example, I'd say absolutely yes - it's the way we use our ViewModels.
Again, none of this is gospel - just my take on how we handle it.
Excellent questions!
1) How to get the validation results (error messages, etc) of Domain
Objects and Business Rules from the Service Layer to the View Models?
I use EntityFramework in the back-end and implement IValidatableObject both on my models and my entities. On models, I perform cross-field validation, while on entities, I perform cross-entity validations.
2) I am using Domain Objects and a Service Layer that does all the
Business Logic, then I send the Domain Objects to the controllers and
let them (via AutoMapper) convert them to View Models for the views.
What other types of things are the responsibility of the controller?
Is the following code OK? Is this too much logic in the controller?:
This code is perfect. Controllers gather data, transform data into models and feeds them into a view.
3) I think it is OK to have properties on the ViewModels that can
indicate to a view if something can be hidden for example and then
perform that logic in the view? Example:
Yes, this is exactly what a ViewModel is meant for. To capture all data AND logic required for your view to render.
4) I was thinking of having my services return some sort of
TransactionResult object back to the controllers on writes to make it
the responsibility of the service to handle the transaction. So I
would have an aggregate service that would start a transaction
(UnitOfWork) do what ever it needed to do and then return this
TransactionResult that could have error messages? I don't think I
should make the controller responsible for managing the transaction,
but rather have it just pass in a view model mapped to a domain object
to the service and let it act on it?
I struggled with this a bit in my projects. In the end, I moved the SaveChanges method of EntityFramework to the front-end. This allows me to build a transaction in the front-end and then commit it once. Every method in my ApiController which performs an update, create or delete will also do a SaveChanges.
I use ApiControllers as a layer of abstraction between my back-end and actual Controller classes. To elaborate, my application both uses normal Controllers (HTML) and ApiControllers (REST aka Web API). Both types of controllers share a common interface for retrieving data.
Example: http://pastebin.com/uL1NGGqH
The UnitOfWork still resides in my back-end behind a facade. I just expose the SaveChanges to the front-end. Side-effects such as ValidationExceptions are either handled by ASP.NET MVC automagically or captured in custom ActionFilters.
5) Also, how much of ActionFilter's do you want to use? I know it is a
huge extensibility point, but I often find myself trying to stuff all
of the model creation into a filter.
I only used a handful of ActionFilters in the large MVC project I am currently working on. These ActionFilters are mostly used to enforce security and to translate Exceptions (such as ValidationExceptions) to JSON-format so my client-side validation framework can handle it.
Off-topic: You can never over analyze. Asking yourself these fundamental questions of MVC makes you better grasp the concepts of MVC and makes you a better developer in general. Just make sure you don't do it too much in the boss' time ;)
Same here:
base controllers with common actionfilters
Validation is done using DataAnnotation and model validation within the controller.
tiny controllers with injected wrapped context or specific service layer
Automapper mapping ViewModels/EF Pocos.
I don't really bother about implementing UnitOfWork or explicitly using transactions since EF4 automatically creates (if it does not exist) a new transaction for all the changes done within a SaveChanges (http://msdn.microsoft.com/en-us/library/bb896325.aspx. I just have a generic interface exposing the DbSets of the Context as IQuerable and the Add/Delete/Find methods.
But as said it's all personal.
In most documentation you read about ASP.NET MVC, the entire 'Separation of Concerns' is very heavily pushed. Dependency Injection/Inversion of Control, Unit Testing, keeping 'logic' out of the Views, etc.
But how far is this intended to be pushed? Is it bad practice if a specific task requires extra logic beyond the 'three layer' approach of View/Model/Persistence?
For example, I have a solution set up with four individual projects.
Project.Web (ASP.NET MVC) [ References Data.dll, Models.dll ]
Project.Data (Fluent nHibernate Mapping) [ References Models.dll ]
Project.Models (POCO, Helpers, Factories, etc)
Project.Tests (Unit Testing)
Up until now, this has served me pretty well. But I require some very abstract logic for some of my MVC Views, such that I need to take part of the Models and arrange a View Model that is persisted in the database.
This cannot happen in my Data section, as that would dispose the re-usability of it, and there is business logic included in the process. It cannot entirely happen in my Models section, because that would require it to have knowledge of the Data section, which it does not. And I do not want to put it in the Web section because I don't want data access code there.
Question
Is it in massive violation for me to add, say, a Project.Presentation project that references Data.dll and Models.dll to construct what I need to? Moreover project concerns aside, is this a bad approach in general or is this something a lot of you find yourselves having to do at times? Part of me feels that if I am having to resort to this, then I've just built my software wrong - but at the same time I am very confident I have done a fairly good job, it is just too abstract to make a raw HTML interpretation of without middle-man arrangement.
It's been my experience that single responsibility is a great way to write code you expect to change early and often. Like Jan, I too have a solid line between who does what, when. The more you enforce this, the easier it is to replace an slice of your system. I recently removed linq2sql with EF4.1 and because of SRP, once I got the tests passing around my new EF4 layer, everything else just worked.
That said, I typically let unit testing dictate where these things live -- it's my driver for SRP as well as asking the basic question "must =class/service= know about =something else= to do it's job?" If the answer is no, it goes somewhere else -- if yes, it's a dependency. Now, if it becomes painful, that's its way of telling me "this is stupid" (see this question for the stupid) and I've attempted to force something instead of allowing it to fit the way it must.
Onto your core queston : you've clearly identified a gap in your code -- it MUST know about two things (data and model) and I agree, it should be its own thing and pulled out. I would call this a "DomainService" or maybe just DTO, but presentation feels like it would be doing more than just prepping data. (I'd argue the view handles the presentation ... maybe you simlpy mean presenter?). I would also argue against your perception that you did "something wrong" - no, you're learning to write code differently and allowing it to evolving, EXACTLY as it should. :-)
I use the following structure, which more or less solves all problems we've had regarding MVC structures.
Models: contains all ViewModels. Just clean, only getters and setters.
Business logic implementation: Set of projects that contains database logic, DAL entities etc. But only has one interface (in our case this is a WCF API).
ServiceLayer: the bridge between Business Logic and ViewModels. Doesn't know anything about web.
Mapping layer: translation between business entities and ViewModels.
Web project: holds very thin Controllers and Views, and everything web related.
A web page flow will follow this flow:
URL maps to a certain Action
Actions are really clean, they only reference a method in the ServiceLayer
The ServiceLayer executes one or more actions in the Business Logic Implementation (get data, store data, etc.)
The ServiceLayer passes the business entities to the Mapping Layer.
The Mapping Layer translates business entities into ViewModels
In code this would look like:
// action
public ActionResult ListOfObjects () {
var model = new ServiceLayer.ObjectsClient().GetListOfObjects();
return View(model);
}
// Service Layer
public ListOfObjectsModel GetListOfObjects () {
var businessEntities = BusinessDao.GetThingysFromDb();
var model = Mapper.TranslateToViewModel(businessEntities);
return model;
}
// Mapping Layer
public ListOfObjectsModel TranslateToViewModel(List<BusinessEntity> entities) {
// do mapping
}
When handling POSTs you will follow the same flow, but the mapping layer should translate your ViewModel into Data Entities that are given to the Business Logic.
"take part of the Models and arrange a View Model that is persisted in the database"
Then its not a viewmodel.
Does that simplify things?
What is a 'ViewModel':
More than often 'ViewModel' is confused with persistence. If you look at the word more closely it is a combination of 'View' + 'Model' - which essentially means it is a single unit of data that is required to fulfill all the needs of your view. A ViewModel can infer multiple entities or sources to build what is required by the View.
Now Coming to your question:
Is it in massive violation for me to add, say, a Project.Presentation project that references Data.dll and Models.dll to construct what I need to?
Re: If I had to do it, I would have created a seperate namespace (folder) in my MVC project named 'ViewModels' and placed all my Viewmodels in there. In my opinion if you want your ViewModels to be in a separate namespace, it would not actually violate MVC. You are just incresing the separation or making it more unit test friendly.
Just my 2 cents!!!
Here's the scenario:
ASP.NET MVC2 Web Application
Entity Framework 4 (Pure POCO's, Custom Data Context)
Repository Pattern
Unit of Work Pattern
Dependency Injection
Service Layer mediating Controller -> Repository
So basically, all the cool stuff. :)
Flow of events for a basic UI operation ("Adding a Post"):
Controller calls Add(Post) method on service layer
Service layer calls Add(T) on repository
Repository calls AddObject(T) on custom data context
Controller calls Commit() on Unit of Work
Now, i'm trying to work out where i can put my validation.
At this stage, i need two types of validation:
Simple, independant POCO validation such as "post must have a title". This seems a natural fit for Data Annotations on the POCO's.
Complex business validation, such as "cannot add a comment to a locked post". This can't be done by Data Annotations.
Now, i have been reading "Programming Entity Framework, Second Edition" by Julie Lerman (which is excellent BTW), and have been looking into hooking into the SavingChanges event in order to perform "last-minute" validation. This would be a nice way to ensure validation always happens whenever i do "something" (add, modify, delete), but it's also a little late IMO (as the items are already in the state manager) - so what can i do if validation fails, remove them?
I could of course make my POCO's implement an interface (say "IValidatable"), and call a method on this interface during this event.
But this seems "too late" for business validation - is this the consensus?
I'm basically looking for guidance here, i'm trying to design a re-usable, intelligent validation scheme for complex business logic, given my above architecture.
Another curve-ball for you - as you know, POCO's with EF mean the POCO's have all the properties on the DB - so i might have a "PostID" property, with get/set accessors (as EF needs to get/set these properties).
But the problem is, "PostID" is an identity column, so how do i protect the field from being explicity set? E.g if i (for some reason) do the following:
var post = service.FindSingle(10);
post.PostId = 10;
unitOfWork.Commit();
This will throw a SqlException. How can i prevent this? I can't "hide" the property (make it private, or even internal) as the POCO's are in a seperate assembly to the Repository.
A note on validation - i'm planning to create custom exceptions (deriving from Exception). So when validation fails, i need to throw these exceptions.
That way, i can code something like this on my controller:
[HttpPost]
public ActionResult AddPost(Post post)
{
try
{
IUnitOfWork uow = new UnitOfWork();
postService.Add(post);
uow.Commit();
}
catch(InvalidPostOperation ipo)
{
// add error to viewmodel
}
}
Will i have to manually do validation on the service layer everytime i do an Add? Then how can i handle Save? (as this is on the Unit of Work, not the service layer).
So to prevent this from being a "all over the place" question, here are my questions:
Simple POCO validation - should this be done with Data Annotations? Pros/cons/gotchas?
Under what circumstances (if any) should we be hooking into the SavingChanges event of the EF Data Context in order to provide validation?
Where should i be performing complex business validation? In the service explicity, or a method on the POCO's (which i can call from service). How can i create an intelligent/reusable scheme?
How can we "hide" auto-generated properties of POCO's from being tampering with?
Any thoughts would be most appreciated.
Apologize if this post is "too long", but it's an important issue and one that can be solved in many ways, so i wanted to provide all the info in order for the best possible answer.
Thanks.
EDIT
The below answer is helpful, but i'm still (ideally) looking for more thoughts. Anyone else?
Well like you said, DataAnnotations is not appropriate for all situations. Cons are mainly complex validation (multiple property and multiple property different object) in my experience.
If i were you, i would leave business/domain validation out of the Data Layer (EF) as much as possible. If there is a Data Layer validation scenario, then fine (eg. validating complex parent/child relationships - this is purely DB stuff).
Yes, the complex business validation should be in the Service Layer or in the Model Objects (attached, via partial classes or some inheritance approach: interfaces/derived classes). There's debate about this between ActiveRecord people, Repository Pattern people and DDD people, but go with what works for you, is simple and will enable rapid deployment and low cost application maintenance. This is a simple example of how you might attach more complex validation to domain objects yet is still compatible with the DataAnnotations interface and thus is 'MVC friendly'.
Good question. -one i have not found a solution i'm 100% happy with yet. I have played with the idea of private setters and it's not great. Have a quick read of this summarized Evans DDD book. It's great quick read and it might provide some insight about the purpose and difference between Model Objects and Value Objects. This is where i think object design will mitigate the problems your having with the property "tampering" (as you call it) but without fixing the property visibility. Ie, another solution might lie elsewhere. Hope this helps.
Hey, probably a bit late but here goes anyway...
It all depends on your architecture, i.e. Is there a logical seperation, in your application: UI, Service Layer, Repository Layer. If you are hooking onto the Save event, how exactly will that be done? From what I observed you would be calling the repository Layer for Persistance only right? However you are hooking onto the save event, giving control back to the Service Layer/ Business Layer whatever then forcing the save through right?
I personally feel the Service layer/ Business Layer should take care of it in completion then say, hey mr repo layer -> save this object.
With regards to validation, Data Annotations should be used with the UI, so simple valiation like [Required] etc, this will be helpful with the Client Side validation but complex business logic or complex validation should be hooked into the service layer/ business layer, that way it is reusable across all entities/ objects/ POCOS etc.
With regards to preventing certain private fields not being tampered with... only allow your service layer/ business layer to actually set the object that will be persisted (yes i mean :) ...) hand coding it, I felt this was the safest option for me anyway, as I will simple do:
var updatedpost = _repo.GetPost(post.postid);
updatedpost.comment = post.comment;
updatedpost.timestamp = datetime.now;
Kind of wasteful but that way your buseinss layer takes control, however this is just my experience I may be wrong, I have read a lot into model binding, validaiton and other stuff however there seemed to be cases where things never work as expected e.g. [Required] attribute (see Brad WIlson's) post.
Derik Whitaker posted an article a couple of days ago that hit a point that I've been curious about for some time: should business logic exist in controllers?
So far all the ASP.NET MVC demos I've seen put repository access and business logic in the controller. Some even throw validation in there as well. This results in fairly large, bloated controllers. Is this really the way to use the MVC framework? It seems that this is just going to end up with a lot of duplicated code and logic spread out across different controllers.
Business logic should really be in the model. You should be aiming for fat models, skinny controllers.
For example, instead of having:
public interface IOrderService{
int CalculateTotal(Order order);
}
I would rather have:
public class Order{
int CalculateTotal(ITaxService service){...}
}
This assumes that tax is calculate by an external service, and requires your model to know about interfaces to your external services.
This would make your controller look something like:
public class OrdersController{
public OrdersController(ITaxService taxService, IOrdersRepository ordersRepository){...}
public void Show(int id){
ViewData["OrderTotal"] = ordersRepository.LoadOrder(id).CalculateTotal(taxService);
}
}
Or something like that.
I like the diagram presented by Microsoft Patterns & Practices. And I believe in the adage 'A picture is worth a thousand words'.
This is a fascinating question.
I think that its interesting that a large number of sample MVC applications actually fail to follow the MVC paradigm in the sense of truly placing the "business logic" entirely in the model. Martin Fowler has pointed out that MVC is not a pattern in the sense of the Gang Of Four. Rather, it is paradigm that the programmer must add patterns to if they are creating something beyond a toy app.
So, the short answer is that "business logic" should indeed not live in the controller, since the controller has the added function of dealing with the view and user interactions and we want to create objects with only one purpose.
A longer answer is that you need to put some thought into the design of your model layer before just moving logic from controller to model. Perhaps you can handle all of app logic using REST, in which case the model's design should be fairly clear. If not, you should know what approach you are going to use to keep your model from becoming bloated.
You can check this awesome tutorial by Stephen Walther that shows Validating with a Service Layer.
Learn how to move your validation
logic out of your controller actions
and into a separate service layer. In
this tutorial, Stephen Walther
explains how you can maintain a sharp
separation of concerns by isolating
your service layer from your
controller layer.
Business Logic should not be contained in controllers. Controllers should be as skinny as possible, ideally follow the patter:
Find domain entity
Act on domain entity
Prepare data for view / return results
Additionally controllers can contain some application logic.
So where do I put my business logic? In Model.
What is Model? Now that's a good question. Please see Microsoft Patterns and Practices article (kudos to AlejandroR for excellent find). In here there are three categories of models:
View Model: This is simply a data bag, with minimal, if any, logic to pass data from and to views, contains basic field validation.
Domain Model: Fat model with business logic, operates on a single or multiple data entities (i.e. entity A in a given state than action on entity B)
Data Model: Storage-aware model, logic contained within a single entity relates only to that entity (i.e. if field a then field b)
Of course, MVC is a paradigm that comes in different varieties. What I describe here is MVC occupying top layer only, vide this article on Wikipedia
Today, MVC and similar model-view-presenter (MVP) are Separation of Concerns design patterns that apply exclusively to the presentation layer of a larger system. In simple scenarios MVC may represent the primary design of a system, reaching directly into the database; however, in most scenarios the Controller and Model in MVC have a loose dependency on either a Service or Data layer/tier. This is all about Client-Server architecture
If u use Dependency Injectors your business logic will go to them and hence you will get neat and clean controllers.