Software engineers often deal with rich concepts related their lines of business such as suppliers, orders, commodity, authorizations, etc. Since the business logic drives the value of the software, this logic needs to be made a first-class citizen in applications. More specifically, the business concepts need to be modelized within a business layer (or business entities or business objects; all the terms being interchangeable).

The CSLA framework written by Rockford Lhotka provides good guidelines for the required functionalities of such business objects. These functionalities are however not fine-grained enough for some projects. For example authorizations in CSLA depend on the type of the business object, not on the instance.

This article aims at presenting some ideas which have been implemented during one of my latest projects. It is not a full-fledge architectural proposal, but a presentation of workable principles which have increased the productivity and the reliability of our projects. In the first part, we will first define core concepts which are supported by our business objects. In the second part, we will show how these concepts can be reflected into the UI by using data-binding expressions.

Business Objects

A simple scorecard will be used as the case study. A scorecard represents a score affected to a supplier (SupplierID ) by a user (OwnerContactID). The scorecard is also related to a Status. The status can either be:

  • published. The scorecard is then visible to anybody.
  • in draft. The scorecard is just visible by the owner.

The Scorecard is our main business object, and inherits from a base class called BusinessObject.

UML diagram

Authorization

Authorization is a complex issue which depends on many factors such as the status of the object, the authorizations of the current user, the intersection of the perimeter of the current user with the perimeter of the object, etc. The proposed business object implements the following methods:

abstract class BusinessObject {
    public virtual AccessibilityType GetAccessibility() { }
    public virtual AccessibilityType GetAccessibility(string propertyName) {}
}

The AccessibilityType enumeration can be ReadAndWrite, ReadOnly, or None. For example, a scorecard can be modified by its owner or by the administrator if the scorecard is still in draft. The accessibility can be defined at the object level, or can be defined at the property level: once a supplier is associated to a scorecard, the supplier cannot change (i.e., the property SupplierID is ReadOnly).

The accessibility can be enforced at the property level by using AOP and joinpoint methods which can throw an exception when the property is accessed or written.

Validation

Validation using ASP.NET validation controls is permissive as it tightens business logic with the UI. Besides, the definition of what makes a business object valid can be quite complex. Our business object defines this function:

ICollection<ValidationError> Validate()

It returns a collection of ValidationError which contains meta-information about the type and the description of the error. These pieces of information are used by the UI to display the errors. For example, changing the status of a scorecard to Submit will trigger a validation error if the score has not been yet initialized by the user.

Formatting

Properties of the business object need to be formatted in the UI. For example, the property representing the score could be displayed using two or four decimals. This formatting can be dynamic by nature. Hence, the business object implements this function:

string GetFormattingString(string propertyName)

It will return {0:f2} or {0:f4} if the formatting allows two or four decimals, respectively.

Allowed Values

Very often, a property can be initialized from a specific subset of values. For example, the owner of a scorecard needs to be an administrator, or the supplier account manager of the supplier noted by the scorecard, or a commodity buyer which is in the same commodity perimeter than the supplier noted by the scorecard, etc.

A basic solution is to write specific code to populate the selector (like the DropDownList in ASP.NET) with the list of allowed users. On the other hand, and to keep the logic withing the business object, the following method can be overridden:

IEnumerable GetAllowedValues(string propertyName)

In our example, it returns an enumeration of user IDs which is used to feed the selector.

Data Binding

The first part of this paper has presented an object with rules related to the business environment. Applying automatically the business rules to the UI is achieved by a two-way data binding. In the underlying implementation, the ASP.NET control properties such as Visible, Enabled, or ReadOnly are set based on the results of GetAccessibility methods. This simple line of code binds the SupplierID property of the Scorecard object to the selector control selSupplier of the suppliers :

BusinessObjectBindingContext.Current.AddBinding(CurrentScorecard, SupplierID, selSupplier);

The data binding operation also takes into account that the UI may have been explicitly set to read-only. The validation errors are also displayed automatically during data-binding. The goal here is clear: no business logic in the UI. This approach extends the one proposed by Rick Strahl.