- Understanding CSLA and the Factory Pattern
- Working with the DataPortal
- Key Features of CSLA Features
- The Pros and Cons of CSLA
- Conclusion
- Further Reading
Key Features of CSLA Features
From inception, CSLA was designed to help you implement a robust enterprise-level application quickly. To do so, the following wish list of features were put into play:
- Source location transparency
- Custom authentication
- Built-in roles authorization
- Built-in business rules validation
- Enhanced parent-child relationship management
- N-level undo
- Support for databinding
- Full support for transactions
Source Location Transparency
Using the class-in-charge variation of the factory pattern in conjunction with the DataPortal framework allows CSLA to create, data-fill, and return an object to a caller without the calling code's having any knowledge of the location of the object's construction or data. Hence, you get the "any object, anywhere" functionality that makes CSLA so useful. (See Figure 4.)
Figure 4 The class-in-charge variation of the factory design pattern means a given class is itself a factory.
CSLA objects work identically regardless of whether you get a given object from your local machine, from an application server on a network, or via a web service. All location information is stored in the application's app.config or web.config file. Making a change is as simple as reconfiguring these files.
Custom Authentication and Built-in Roles Authorization
CSLA ships with a Csla.ApplicationContext object that acts as a common wrapper supporting both the HttpContext object and the Application.Context. In addition, the CSLA framework allows developers to set authorization schemas for user roles. Thus the read/write access for an object's properties can be special for each role.
CSLA business objects have the ability to define and store business rules and validate input against these business rules as a matter of course. The CSLA base business object BusinessBase<T> contains a ValidationRules collection, to which you add business rules using a set of predefined Validation methods. (See Listing 4.) CSLA provides a broken-rules collection that you can traverse to determine the reason for invalidity.
Listing 4 Overriding a CSLA object's AddBusinessRules() method
protected override void AddBusinessRules() { //Add a rule that says that the CountryCode property //can not be greater in length than 4 characters. ValidationRules.AddRule( Csla.Validation.CommonRules.StringMaxLength, new Csla.Validation.CommonRules.MaxLengthRuleArgs("CountryCode", 4)); }
When a CSLA object's rule check takes place, broken rules are added to an object's BrokenRulesCollection. (See Listing 5.) You can inspect the BrokenRulesCollection and respond to rule breakage as is relevant to your application's needs.
Listing 5 Call to ValidationRules.CheckRules(), and resulting BusinessRulesCollection
private void DataPortal_Create(Critieria criteria) { if (criteria != null) { _CountryCode = criteria.CountryCode; } //Fire off rules checking ValidationRules.CheckRules(); if(BrokenRulesCollection.Count >0) { StringBuilder sb = new StringBuilder("Broken rules:"); //Check the BrokenRulesCollection to see if there are //any broken rules. foreach (BrokenRule rule in BrokenRulesCollection) { sb.AppendLine(rule.Description); } throw new ArgumentException(sb.ToString()); } }
Enhanced Parent-Child Relationship Management
CSLA addresses the problem of working with hierarchical data in a very interesting way. It allows you to define an object as a root object that contains constituent collections, which are strongly typed and dedicated to the root. (See Figure 5.)
Figure 5 CSLA provides the plumbing for a parent-child relationship that requires saving only the parent, which is smart enough to save all of its children.
CSLA is very strict about the relation between a parent (root) object and the constituent objects in the various child collections. Upon object creation, CSLA provides a mechanism to mark that object as being a child-to-a-parent object. Once that relationship is established, child objects can be saved only by calling the Save() on the root parent. The developer who is programming to CSLA doesn't need to worry about monitoring a child object's state—CSLA does this behind the scenes. Once you Save() the parent, all existing dirty child objects and newly added objects are saved implicitly.
N-Level Undo
CSLA supports the ability to perform n-level undos. Let's say you have an object, Musician, which has a property, Instruments, which is a collection of Instrument objects describing the one or many instruments played by a given musician. Now imagine that you are editing the collection of Instrument objects. You add a value "guitar", and a value "vocals". Then you add a value "trombone" to the collection. You decide to remove the "guitar" value and then decide you want to remove the "trombone" value.
Your state is that you have "vocals" in the Instruments collection, but you have deleted "guitar" and "trombone". CSLA is smart enough to keep track of the items that you have deleted from the list and can restore these items by undo. Thus by undoing once, you can restore "trombone" to the list; and by undoing again, you can restore "guitar" to the list.
You have to do a little setup in order to implement n-level undo. But once you get the hang of the setup, subsequent implementation is not a chore.
Support for Databinding, and Full Support for Transactions
CSLA allows a programmer to databind a CSLA object to Web form and WinForm controls. All you do is configure the standard control binding properties and call the control's DataBind() method (Listing 6).
Listing 6 Standard databinding techniques to use CSLA object as data source for data-aware controls
//Get the instruments NameValueList InstrumentsList list = InstrumentsList.GetList(); //Bind the NameValueList to the instruments //DropDownList ddInstruments.DataSource = list; ddInstruments.DataTextField = "Value"; ddInstruments.DataValueField = "Key"; ddInstruments.DataBind();
Transaction support is build into CSLA. Invoking transaction support is simply a matter of adding the [Transactional] attribute to data access methods that are to run under the scope of a transaction.