Once we've implemented our business rules, and exposed our
RuleViolations like above, it will be relatively easy to integrate it into our
ASP.NET MVC sample.
Because we added the OnValidate partial method to our
Product class, calling northwind.SubmitChanges() will raise an exception if
there are any business rule validation issues with a Product object that we are
trying to save. This exception will abort any database transactions, and
will be caught in our catch block below:
The one extra line of code we'll then add to our error catch
block is some logic to call a UpdateModelStateWithViolations() helper method
defined below. This method retrieves a list of all rule violations from
an entity, and then updates a ModelState collection with appropriate model
errors (including references to the properties on our entity object that caused
them):
Once we do this, we can re-run our application. Now,
in addition to seeing input format related error messages, ASP.NET MVC's
validation helpers will also display our business rule violations as
well.
For example, we could set the unit price to be less than a
$1, and try to set the Reorder level to be -1 (both values are legal from an
input format perspective - but both violate our business rules). When we
do this and hit save we'll see the errors show up in our
Html.ValidationSummary() list, and the corresponding textboxes will be flagged:
Our business rules can span multiple Product
properties. For example: you might have noticed above that I added a rule
that said that the reorder level can't be greater than zero if the product is
discontinued:
The only changes we needed to make to our "Edit"
view template throughout this entire business rules process has been to add two
more Product properties (Reorder and Discontinued) to the file:
Now we can add any number of additional business validation
rules we want to our Product entity, and we do not need to update the Edit view
nor the ProductsController in order to have our UI support them.
We can also unit-test our model and business rules
separately from our Controller and View. We can unit-test our URL routing
separately from our Controller, Views and Models. And we can unit test
our Controller separately from our Views. All of the scenarios shown in
this blog post will support unit testing without requiring any mocking or
stubbing to be used. The end result are applications that are easily
testable, and which can support a nice TDD workflow.