- Authorization - Uses Enterprise Library's Authorization block. Basically you can set up AD groups and create a XML file that maps Users to the Entities and it's methods. So for example, if you had a 'Reader' AD group and that group can only call the Get... methods.
- Exception Handling - Again, uses Enterprise Library's Exception block and you can set up Exception polies quite easily.
Even if you do not put any business logic in the Service Layer, generating this tier will still provide the CRUD methods with the Authorization and Exception handling pre-wired. More specifically, the contract will be basically the same as the Data Provider methods with added functionality of Authorization and Exception Handling (which is worth it!).
If you would like to use this Service Layer for more robust business logic, it provides the framework based on some best practice patterns: Command Pattern, Processor Pattern, Routhing Slip Pattern, and Strategy Pattern. The Routing and Strategy is optional if you wanted to implement the processor pattern.
Processor Pattern: As I just mentioned, the Processor class represents each logical unit of work in any given Use Case (they could overlap, thus making them more flexible and resuable). For example, a processor called 'ValidateInventoryProcessor' may be used in the OrderService.CreateOrder and also OrderService.ManageNightlyOrders. You would create a new Processor class for each logical unit of work. This Processor class will inherit NetTier's generated class 'ProcessorBase' which implements IProcessor interface. Basically, override the Process() method for your custom implementation in your new processor class.
So for new processor classes ValidateInventoryProcessor, LocateInventoryProcessor, and PlaceOrderProcessor you would do something like this to add them to the command/workflow pipeline for that service:
orderService.ProcessorList.Add(new ValidateInventoryProcessor(order));
orderService.ProcessorList.Add(new LocateInventoryProcessor(order));
orderService.ProcessorList.Add(new PlaceOrderProcessor(order));
The ProcessorList provides the workflow pipeline for the order service. When execute is called it will iterate and call the Process() method for each of the processors loaded in that sequence. Additionally, NetTiers will track the results and state of each processor and store the results in a ServiceResult class. This class will track broken rules and exception errors as it's iterating each processor. This generated class implements the IProcessorResult and returns a GenericProcessorResult. So the execution of the service works as simple as this:
ServiceResult = orderService.Execute();
If you want to know if any problems occurred, you would simple call the HasErrors:
if( ServiceResult.HasErrors) ...{handle them here...}
Here is the diagram of the Processor Manager Pattern: As mentioned earlier, this ProcessManager manages sequence and state of each processor (logical unit of work).
Routing Slip Pattern: This is an extension of the Processor pattern when sequence is not known at design time. Implementing this pattern is optional and can add more flexibility to your application. The idea here is that instead of coding the Manager to load each Processor in a certain sequence you implement the routing slip to instruct the manager what to process next. To implement this, attach a Slip to the message specifying sequence of processing steps (as opposed to the process manager coded for this). Next attach special message router class that reads the Routing Slip. Here is a diagram of the Routing Slip Pattern:
Strategy Pattern: Finally, for even more flexibility you can utilize the Strategy pattern. This pattern utilizes small classes that contain different algorithms. So instead of putting the caculateInventory logic in the Process() method of the ValidateInventoryProcessor class, you can create a strategy class called 'EasternRegionInventoryStrategy', 'CentralRegionInventoryStrategy', and 'WesternRegionInventoryStrategy'. Each one of these concrete classes inherits from a base strategy class 'RegionalInventoryStrategyBase'. Now, any processor class can call the algorithm based on the context.
Class Diagram for Strategy:
Example of Strategy class: 'EasternRegionInventoryStrategy'
Context Class: ValidateInventoryProcessor
Abstract Strategy Class: 'RegionalInventoryStrategyBase'
Concrete Classes: 'EasternRegionInventoryStrategy', 'CentralRegionInventoryStrategy', and 'WesternRegionInventoryStrategy'
Obviously, this adds quite a bit more complexity and can always be implemented later by pulling out the algorithm in the Process() methods. If you are new to patterns or NetTiers you may want to do this later.
Implementing best practice patterns has long been accepted as a way of architecting software. The key is to go ahead and do your homework, understand the patterns, and then implement them. The great thing about NetTiers is that the framework is generated quickly and ready to use.
References used:
http://nettiers.com/ComponentLayer.ashx
http://www.dofactory.com/


2 comments:
Great article.
Nettiers is very powerful and goes beyond the data access layer. I´ve used it in multiple projects with excellent results
This is a great article. Thanks for sharing this. Unfortunately despite a lot of great architecture and tools inside .NetTiers the documentation is quite weak overall (the forums are great but forums != documentation in my view). Is NT something you will continue to work with? It would be great to have some of the concepts you've discussed in a working demo of some type!
Thanks again,
Post a Comment