I am developing application having business objects created from EF 4.0. The application is layered with Data Layer having repository of classes. Above that is a business layer where business processes are mapped as per the requirements. Business layer is calling data layer.
Business objects have complex associations. One scenario:
Merchant has Multiple Addresses
Merchant belongs to one Category
Merchant has an Account
Account has a Wallet
User will be creating a new merchant along with above mentioned business objects (graph). There are various business rules when creating and updating a merchant.
I would like to split my validations into two sub sections. 1) Scalar Property Validation to be handled by Validation Blocks 5.0 and 2) Business Process Rules Validation to be handled in business layer components. However, i am facing difficulty on having a centralized way to report broken rules (Scalar Properties validation and Business Process Rule Validation). I don’t want to inject exceptions everywhere where business rule in is violated as per the business process mapped.
One e.g is following:
When creating a new merchant, Category needs to be validated. Because if a certain type category is associated with this new merchant then business rule says that such merchant cannot exists twice in the system.
Now, when a UI pass the new merchant graph to business layer component, i first validate BO Scalar properties validation (validated bu Validation Blocks) then this BO is passed into business process rule validation methods to check various rules. There are possible violation points which i want to report and shall not allow the merchant and graph objects to be persisted.
Please share any value able design approach to manage centralized validation rule logging and reporting to UI layer.
EDIT: I don’t want to incorporate validations on EF SaveChanges, ChangeAssociation etc event handlers.
While you said you don’t want to throw exceptions, I found throwing exceptions very effective. Especially when you having multiple sub systems validating the system, throwing one single type of exception as a facade will be very effective.
What you can do is creating a custom exception (i.e. named
ValidationException) that will be thrown either when your Validation Application Block (VAB) reports error or the business rules report errors. In the presentation layer you will have to catch thisValidationExceptionand report this exact type of exception in a user friendly way to the end user.Using a single exception type for both validation sub systems, allows you to report errors in a consistent way, and also ensures that validation errors won’t get unnoticed when you (or an other developer) forgets to handle validation errors. Handling errors should be very explicit IMO. When you let methods return a list of errors it is easy to forget to handle them. When creating a custom exception, it is easy to add a property to that exception type that contains a list of validation errors. Such a list of errors is easily extracted from VAB. I don’t know what validation system you use for your business rules validation, but it can’t be to hard to extract a list of error codes from it.
The most simple way to handle this in UI is of course by using a
try–catch:Of course having these
try–catchstatements all over the place is ugly, but at least this code is easy to follow. Dependent on how you structured your business layer and the UI technology you use, there are prettier solutions you could use. For instance, you can wrap the actual operation that can fail with an action as follows:The
UIValidationHelperwould look like this:An other option, that I’ve used myself in the past, is by extending the business layer with events. For this to work you need a construct such as commands, as I use in my examples. When using events, the UI could look like this:
This example hooks a static method to the
ValidationErrorOccurredevent of a command instance. The trick here is to let theExecutemethod of that command catchValidationExceptions and route them to theValidationErrorOccurredwhen it is registered. When no method is registered, this exception should bubble up the call stack, because an unhandled validation exception should of course not get unnoticed.While it is possible to of course do this directly from your business layer, it would make your business layer dependent on a particular validation technology. Besides this, this method allows clients to choose to handle validation errors in any way they want or decide not to handle them at all (for instance when you don’t expect any validation errors to occur in a particular use case).
When using ASP.NET Web Forms, the
DisplayValidationErrorsmethod of theUIValidationHelpercould look like this:This static helper method injects the messages of the reported errors into a
ValidationSummarycontrol on the page. It expects the page to contain aValidationSummarycontrol at root level of the page. A more flexible solution can easily be created.The last thing that I like to show you is how the the
BusinessCommandwould look like when adopting this solution. The base class of these commands could look something like this:The
ValidationErrorEventArgslooks like this:I hope this all makes sense and sorry for my long answer 🙂
Good luck.