I don’t know about you, but I have ready allot of articles that talk about what should be in your Controller Actions and what should not. Despite all that I have read, I still find it very easy to let foreign bodies into your controller actions. Adhering to the SRP (Single Responsibility Principle), your controllers also have a single responsibility. Therefore, this article’s is out to provide (one) way to tackle some of those foreign bodies that creep into our controller.
What this article isn’t going to attempt to tackle is…
[list type=”cancel” color=”color1″]- whether a particular implementation of the MVC pattern is really a MVP pattern
- attempt to bring an end to arguments about what responsibilities should be handled by the controller
- provide a one-size-fits-all solution for extracting extrinsic logic
To start off, what are the “foreign bodies” I am referring to. This is the extrinsic code that can be identified as the responsibility of another entity in our system. I am using Trygve Reenskaug (Smalltalk Programmer) who first introduced the concept of the MVC pattern’s definition of controller:
[quote color=”” boxed=”yes”]“A controller is the link between a user and the system. It provides the user with input byarranging for relevant views to present themselves in appropriate places on the screen. It provides means for user output by presenting the user with menus or other means of giving
commands and data. The controller receives such user output, translates it into the appropriate messages and pass these messages on .to one or more of the views.” [/quote]
Since my examples are presented through an ASP.NET MVC application, I figured I will provide Microsoft’s official definition of the controller in context of the ASP.NET MVC framework:
[quote color=”” boxed=”yes”]Controllers. Controllers are the components that handle user interaction, work with the model, and ultimately select a view to render that displays UI.[/quote]
Having established our modus operandi, lets dive in. There is allot of things that we find need to be handled in the context of a controller’s / action’s operation, it isn’t always as easy as grabbing the optional VIEW based on the users input, appropriating the corresponding model and calling it a day. There are an endless number of other decisions that we need to content with before being able to ultimately make the decisions on view/model pairing such validating user input, examining authorization, domain logic and a host of other determinations that need to be made. However, a lot of these fall inside a broad definition of validation. Validating user input, validating the existence of an entity and the list goes on. This is where we are going to focus.
In a recent project, I really wanted to try and extract any all validation logic from the controller action including handling ModelState. The intention was to purify the controller actions and allow it to simply perform its responsibility of determining what view to render and provide the appropriate model. Adhering to the single responsibility principal the idea was to encapsulate the logic for a given rule into a separate object with a way to culminate the validation of all the required rules together.
I decided on using the Specification Pattern as a way to standardize the definition of a rule that needs validating, coupled with a Validator object to handle running all the rules (specifications) it is handed. The specification pattern provided the means of encapsulating the logic that defines a rule into a “specification” and a way to chain those rules if needed.
What are we going to get accomplished?
- Examine a controller action and identify the validation rules
- Implement the specification pattern
- Design an object (Validator) that can run our rules
- Refactor our controller action
[section_headline tag=”h4″ lined=”yes” color=”color2″][headline tag=”div” css_class=”h3″ color=”color2″]Examine A Controller Action and Identify the Rules[/headline][/section_headline]
Lets start with what a controller action might look like.
This is a pretty straight forward action. We can identify the rules in place here
[list type=”tick” color=”color1″]- ModelState is valid
- Authenticated user is the one submitting the survey and is an active user
- The group the user belongs to is a valid group that is authorized to submit surveys
- The valid group has not exceeded the allowed number of submitted surveys
Now, before we run off and start re-factoring the action, we need the catalyst for what will allow us to meet our goals, which was to encapsulate each rule and provide the ability to group related rules together if needed. One bonus of encapsulating the rules will allow us to reuse them. Rewriting the same validation logic over and over again in different places (i.e. actions) would be breaking the D.R.Y. principal. We need to implement a method of doing this, which is through the use of the specification pattern.
Lets do that now.
[section_headline tag=”h4″ lined=”yes” color=”color2″][headline tag=”div” css_class=”h3″ color=”color2″]Implement the Specification Pattern[/headline][/section_headline]
Lets start by implementing a interface for our specification class.
IsSatisfiedBy() : The magic happens in the Specification’s base method where it will house our validation logic. This is not the final version of our interface as I have stripped it down for clarification purposes.
And() & Or() : These are the methods that will allow us to “chain” our validations into groups if we so choose
Not() : This will allow for returning the inverse of a rule or grouping of rules without having to re-write as well as provide readability.
Now lets implement the Specification class.
Nothing fancy here, it is simply an abstract class that will force an implementation of the Specification class. Take notice, with the exception of the IsSatisfiedBy method, each of these methods appear to be a specification themselves. So lets go ahead and implement our first specifications for the AndSpecification, OrSpecification, NotSpecification classes.
These specifications will allow us to group specifications together. As an example
[pre]new FirstSpecification().And(new SecondSpecification).IsSatisfiedBy()[/pre]
You might have noticed, we are not providing any dependencies to our specifications (specifically to the IsSatisfiedBy()). I have done this purposely for clarify of what we are accomplishing and the fact that your needs will be different. Since your back-end, ORM or other dependencies will be different, I am going to use mine. I am using the ORM NHibernate and will be providing a NHibernate Session as well as a IQueryExecutor object that is simply is a wrapper to run more or less named queries. Don’t get hung up on that now, just understand that you need to provide any dependencies that your specifications will need to perform their responsibility.
There is one exception to this and that is the ModelStateDictionary object. I’ll talk about this in a minute, but for now, go ahead and include this in your implementation.
Easily, we are only in need of re-factoring the IsSatisifedBy() method on the interface, abstract class and each of the specification class accordingly. Below are the changes for each:
Your probably familiar with the following code:
[pre]if (!ModelState.IsValid) { }[/pre]
Well, doesn’t this look similar? We’re checking the validity of an object. In this case the model the view is operating off of and for me would fall right into what we have been working on extracting from our controller action. I try to lean on when possible, the available tools that a framework will provide. Therefore, the use of DataAnnotations as just one example provides me additional means to inject validation rules in some context such as a View Model. So I have opted to provide the ModelStateDictionary which will contain the state of a model (if applicable) to any specification if you choose to provide it (more on that later). We’ll revisit this again shortly.
[section_headline tag=”h4″ lined=”yes” color=”color2″][headline tag=”div” css_class=”h3″ color=”color2″]One Validator to Rule Them All[/headline][/section_headline]
I mentioned earlier about utilizing an object to run our specifications. To be clear, you can run the specification out-of-the-box
or chained…
But, I am not so keen on doing just that. I personally, try to always look for ways that I can more clearly express what it is my code is doing (and not in the form of comments), but I am of the opinion that the following is a bit clear and removes some of the cruft.
Therefore, lets look at implementing our IValidator interface and Validator class.
As you see, nothing crazy going on here. Has a single method Validate() that does two things,
[list type=”tick” color=”color1″]- Checks the validity of ModelState
- Runs the IsSatisfiedBy method of the specification(s)
You will also notice that the ModelState property either contains the provided ModelStateDictionary from the constructor or instantiates a new one as well as use the optional parameter syntax for the constructor. This allows the ModelStateDictionary object to be optional. On a side note, this is also a rudimentary implementation of the Null Object Pattern. The first thing we do is check that the ModelStateDictionary is valid before proceeding on. If it’s not, then there is no reason to proceed on with running our specification.
[alert type=”info” icon=”icon-help-2″]Note: If you don’t know, the state of a newly instantiated ModelStateDictionary is valid:new ModelStateDictionary().IsValid() == true[/alert]
[section_headline tag=”h4″ lined=”yes” color=”color2″][headline tag=”div” css_class=”h3″ color=”color2″]Re-factor the Controller Action[/headline][/section_headline]
Before we can run off and re-factor the action controller, lets create the Specifications (rules) that we will leverage back in our action. If you look back at our rules, you will see that 3 rules (not including Validating the state of our Model).
[list type=”tick” color=”color1″]- Authenticated user is the one submitting the survey and is an active user
- The group the user belongs to is a valid group that is authorized to submit surveys
- The valid group has not exceeded the allowed number of submitted surveys
For now, I am going to go ahead and lump the last two together into a specification, leaving me with only 2 to create. At the end of this article, I’ll provide some examples of splitting it out and chaining them together.
So lets start with the a specification to validate the user is eligible:
And the specification to validate all Group related rules:
And finally bring it all together and re-factor the SubmitSurvey controller action:
Now, I don’t know about you, but that sure looks allot more clear as to what is going on here and has also accomplished:
[list type=”tick” color=”color1″]- Letting our controller action only worry about providing the correct view and appropriate model
- Extract all extrinsic logic to their place which also has the bonus ability to be re-usable.
Quick note, in this particular case, order of the validation mattered. The resulting return path for group validation and any issues with the posted model are the same – return the user to the view with the model. As you recall, one of the first things we do with the validator is run the IsValid() method on the ModelStateDictionary object. There might be cases were you will need to explicitly check the validity of the ModelState in the controller.
This might have seemed like allot of work to do what we just did, but once you have the plumbing in place, you can easily whip up specifications and swap them in place for logic in your controller actions, especially when you create specifications that can be reused elsewhere.
Like I mentioned, another option would be to go ahead and split the single Group related specification above into two separate specification and chain them, which has its own benefits such as additional re-usability and clarity.
And those two specifications GroupCanSubmitSurvey and GroupHasNotExceededSurveyQuota
So this is it in its completion. Let me just point out that this pattern will not be for every situation and there will be shortcomings. Because as we all know, there is not one tool for every job. But, I hope you can derive some benefit from this setup or find a way that it can help you create clearer and reusable code.
I would love to hear your thoughts on it, how it can be improved or where there might be some shortcomings.
On a complete side note, you will find that other implementations of the specification pattern will have the dependencies being passed in through the IsSatisfiedBy() method and creating a generic specification abstract class, who’s derived types IsSatisfiedBy() parameters are based on that type. Then allowing you to chain them together, and pass the requirements into the last specifications IsSatisfiedBy() method, who then passes along this requirement down the chain. I opted not to implement my specification pattern this way for this specific reason of limiting my ability to chain based on different requirements, but that might be a better suited setup for you.