This article is compatible with the latest version of Silverlight.
Introduction
In Part 3 of this series I looked into the methods of communicating with the WCF service on the server. The focus of this article is to create a business object framework to manage our business objects. Changes to business objects need to be validated against a set of business rules to ensure the integrity of the data within the database, and invalid data needs to be clearly pointed out to the user so they can resolve any issue. After building this framework we will create a Product business object that contains the primary data for a product and define a number of rules to validate this product. This article isn’t really Silverlight specific but could apply to various client types when implementing a line of business application. However it is a very important step in building a line of business application, and since it’s a line of business application we’re building I decided to devote an article to it. I will return to more Silverlight specific topics in the next article in this series.
Source Code and Live Demo*
Instructions on setting up the sample project can be found in Part 1.
*To login in the sample application use the following Username: demo and Password: demo.
Be sure to check all articles of the series: Part 1, Part 2, Part 3, Part 4, Part 5 and Part 6
Creating the Business Objects
As discussed in part 3 of this article series, we are sharing our business objects/entities (sometimes also referred to as a domain objects among other names) between the server and the client. I could write a book on what exactly constitutes a business object but that’s a whole different topic to the one I’m trying to cover with these articles. I can recommend however if you are looking for further information o business objects “Expert C# 2008 Business Objects” by Rocky Lhotka. You might notice if you visit Rocky’s website that he has a special version of his free CSLA.NET business object framework for building business applications in Silverlight, called CSLA Light. I’ve previously used the full CSLA.NET framework in a project and found it a very nice framework to work with, and I believe using it contributed towards the success of that project. I initially considered using the CSLA Light framework in this application but after careful consideration I have decided to use my own simple lightweight framework instead. The DLL required to support the CSLA Light framework comes in at 300kb, and compresses down to 100kb when included with the .xap file, so it isn’t particularly light (depending on your scenario and bandwidth availability this may or may not be an issue). It is however a very robust and respected framework so I recommend evaluating it first before disregarding it purely for this reason, as its features (such as n-level undo) may greatly benefit your project. See the Resources section at the end for a link to an article on implementing the CSLA Light framework in Silverlight applications. In any case, for the purposes of this project we’ll keep things simple and use a very basic “home made” business object framework instead.
Essentially what we need from our business objects is a set of properties (some possibly being references to other related objects), a means of notifying binding clients that the value of a property has changed, a means for defining rules to indicate whether a business object is valid (based upon the values of the business object properties), and a means of validating the business object against these rules. To implement the framework, our business objects need to inherit from my BusinessObjectBase class that contains some of this functionality. Note that as a part of our business object design I haven’t included any persistence functionality, which is often found in other business object implementations. As described in my previous article I have chosen to implement a service layer pattern architecture where our business object is the entity and the persistence logic is separated out into a separate “service”. Thus we can share the business objects / entities between the server and the client, whilst enabling the persistence logic (“service”) to be implemented separately for the client and the server. Note that my implementation of the “service” part of the architecture is not currently in place but is still somewhat ad-hoc, spread throughout the code. This will be rectified in future versions.
As an example of creating a business object, let’s walk through creating our Product business object. The first task is to create our class (linking it with both the full framework and Silverlight framework class libraries containing our business objects), and have it inherit from the BusinessObjectBase class that I created for our simple business object framework.
public class Product : BusinessObjectBase
Step 2 is where we define all the properties of our business object. Unfortunately we can’t use the auto-implemented properties functionality that came with C# 3.0 as these don’t raise the PropertyChanged event that the INotifyPropertyChanged interface implements (required for binding clients such as our data entry form to be notified of changes to properties on this underlying business object). Therefore we need to implement a full property getter/setter with backing field / member variable, and call our functions to validate the property value (to be discussed shortly) and raise the PropertyChanged event. A sample property implementation is as follows:
public string Name
{
get
{
return m_name;
}
set
{
m_name = value;
ValidatePropertyValue("Name");
OnPropertyChanged("Name");
}
}
The final step is to define the business rules. A business rule is essentially logic to validate the property values of the business object, often checking one or more of the following:
- Ensuring that there is a minimum amount of data entered
- A property value follows a specified format
- A property value matches a set of valid values
- A string property value is less than a maximum length
- Comparing various property values (such as ensuring one date is later than another)
For a business object to be valid, all of the business rules defined for that object should pass. We therefore need the ability to check all the rules at once to validate the business object, but we also need to support validation on a per property basis - the rule to be validated once the value of a property is changed. Since we have multiple locations where we need to validate the business object (or a single property) against the rules we ideally need to define the rules in a central location whilst enabling one or all of them to be run from multiple locations within the code (such as in a property setter to run a single rule or in a validation function that validates all rules together). Our simple business object framework enables this by overriding the DefineRules base function and defining your business rules within this function with the validation logic as delegates:
protected override void DefineRules()
A sample definition of a business rule is as follows:
m_rules.Add("ListPrice", new BusinessRule("ListPrice",
"Invalid value - must be greater than or equal to 0",
delegate { return (this.ListPrice >= 0); }));
m_rules is a Dictionary (which has an underlying hash table for the keys, where each key will be the name of the property that rule belongs to), allowing us to quickly obtain the BusinessRule object for a specified property, whilst also being able to enumerate through all the rules for the business object. When we define a business rule we are providing it with the name of the (primary) property it relates to, the error message to display on rule failure, and a delegate containing our business rule logic. By containing our business rule logic in a delegate we can define it in a central location, easily pass it around, and run it from multiple places in our code. Business rules like this are generally short (such as the example above), so a delegate is a perfect way to implement their logic.
I took a bit of inspiration from Paul Stovell in this business rule definition design (who in turn took inspiration from Rocky Lhotka’s CSLA.NET business rule design), albeit with my own further redesign and additional features. I see this as a nice way to define the business rules once and use them from multiple places. A link to Paul’s article on his design can be found in the Resources at the end of this article.
Going back temporarily to our property setter, I included a call to the ValidatePropertyValue function on our base business class which would run each time the value of the property was changed. As a discussion of what this does, we pass it the name of the property and it looks up the rules collection to see if a rule was defined for this property (the property name being the key). If a matching rule is found then we test the object against the business rule to determine whether it passes or fails. If it fails we will raise an exception with the error message set for the rule as the message. The effect of raising this exception will be that the BindingValidationError event will be raised on the data entry field bound to this property that had the invalid value entered. This can then be handled by the binding client to notify the user somehow. If you have implemented binding in the full .NET Framework you no doubt will be wondering why I didn’t just implement the IDataErrorInfo interface to handle notifying the binding client that the value failed validation. The answer was that the IDataErrorInfo interface isn’t included in Silverlight, and though I could create it (or something similar) myself other limitations and issues come into play (such as the fact that there is no DataContextChanged or similar event for Silverlight controls to allow me to attach a handler to an event on the business object that would be handled by my custom validator control when an error occurs). I decided to just work with what I had available.
There is one issue in validating and raising exceptions on assigning property values which might occur when loading the business object from the database. As properties are assigned values the associated rule with each property will be run. If for example that rule was comparing the property value with that of another not yet assigned property the validation rule may fail, raising an exception that would thus cause the population of the business object to fail. Therefore you might need a way in the business object design to turn off the validation when the business object is being populated and turn it back on once it is in “edit mode”. This has not been a problem so far in this project so I haven’t implemented a solution, though might do so in the near future. You may wish to disable the validation by default, and add an Edit() or EnableValidation() method to turn it back on once you have loaded it.
As mentioned in the previous article, the server upon receiving a business object from a client should not assume that the business object passes the validation rules – the client passing the business object may not be a valid or authorised client, and may not have validated the passed in data against the rules. Therefore as soon as the web service receives a business object from a client it should immediately validate the business object against the rules and throw an exception if it fails.
When defining the business rules for our Product business object I used the logic from the check constraints defined in the Product database table as the rules. Business rules aren’t always defined in the database, but the AdventureWorks sample database is a very detailed sample database so I decided to make use of the rules it had defined as the product object would need to pass these rules to make it into the database successfully anyway.
That’s all there is to implementing a business object in this simple framework. In summary, to implement a business object:
- Create a class that inherits from the BusinessObjectBase class
- Link it to both business object class libraries
- Define the properties of the business object
- Override the DefineRules() method and define the business rules
On a slightly controversial topic, you could produce the business object’s code via code generation of some sort (controversial as from a purist perspective your business object model doesn’t necessarily have a 1:1 mapping to your data model). If you generate your business objects from your entity framework model you more or less overcome this issue, as the Entity Framework gives you the ability to model your domain and map it to your underlying data model, which will often pretty closely match the structure of your business objects. Therefore ideally you could generate your business objects from the .edmx file (which is an xml file) that defines your Entity Framework model in the above format. The business rules couldn’t be automatically generated, but you could define these in a separate partial class perhaps. In any case, I started writing a template that does this in the free MyGeneration code generator but moved on when I realised how much work it would be. However, as a proof of concept I determined it would be possible to do this and might be inclined to complete it if I had a lot of business objects to produce from my Entity Framework model.
Other functionality you might want to add to the business logic framework is support for authorisation (note: the CSLA Light framework has this functionality built in) to determine what properties the current user is permitted to view and edit based upon their role in the system, and what functions they can run (such as deleting a product – but this technically would be on the service). This functionality is not available in my simple framework but you may want to consider implementing it if you decide to use this framework on larger enterprise scale projects.
Dictionaries
If you look at the code for the Product business object you might have noticed that I send the ID of several related entities (such as the product model, unit measures, etc) to the client. The user will be required to set a value for each of these when editing the details of the product (eg. select the model of the product, the units that the weight is measured in, etc) and of course you can’t expect them to know what the related IDs are (or even realise that the IDs exist). Instead users would expect to be able to select a related item from a list (often a combo box) that displays the description of the available choices. For example:

In this example, against the Product business object we have a ModelID property and a CategoryID property. In our data entry form however, we need to display the description of the assigned model and category, and allow the user to select different options from a list for these (the available options for the category property is “dropped down” and displayed above). Therefore we need a means for sending the available options to the Silverlight client to be used in this form. I refer to groups of these options as dictionaries. For example all the available categories would be a category dictionary. What each dictionary generally has in common is that it is a collection of keys each with a corresponding value. In the example above, each of the descriptions being displayed in the list would be the value of a dictionary item, whilst the matching key of each (the automatically assigned integer ID from the database) is hidden in the background, but will be assigned to the CategoryID property on the Product business object when a new item is selected from the list.
Note that the keys in some dictionaries are integers, but in other dictionaries they may be strings. Our dictionary needs to support either of these options. The perfect data structure to hold our dictionary items is built into the Silverlight/.NET Framework and allows the keys to be strongly typed whilst being defined as either integers or strings (using generics) – funnily enough it’s the Dictionary class! The Dictionary class is a collection of KeyValuePair objects, and both the Key and the Value types are set using generics when defining the dictionary – perfect for our requirements.
For each business object there might be a number of associated dictionaries. For example our Product business object has the following associated dictionaries: Models, Categories, Subcategories, and Unit Measures. When we need to edit our Product business object for the first time we also need to retrieve these dictionaries from the server. Rather than retrieve these one by one, we’ll group these together as Product Dictionaries and request them from the server in one go. These can be added to a cache so we don’t need to request them each time the user wants to edit a Product business object. Dictionaries often have the characteristic of being relatively static (some more so than others), so caching them reduces the amount of traffic between the server and the client. Depending on how often you expect these to change you may want to refresh the cache periodically, only once each time the application is loaded, or if they rarely/never change you might cache them to the Silverlight isolated storage. In this application we’ll assume that the product dictionaries are updated only occasionally, so we’ll request them when they are first required by the application each time after it is loaded (ie. not saved between sessions).
In summary, our application has a dictionary cache. In this cache are a number of dictionary groups. Each dictionary group contains a number of dictionaries. Each dictionary contains a number of items (ie. key/value pairs).
Often you will find in the real world that the options the current user can choose from the dictionary may be limited by their role or some other limiting factor. I haven’t implemented this sort of functionality in this project as yet, but I mention it as it is a fairly regular requirement in LOB applications.
My final topic in regards to dictionaries is to do with cascading dictionaries. For example, on our Product business object we have the CategoryID and SubcategoryID properties. The subcategories that can be chosen from will depend on the selected category. Essentially, the available subcategories to select will be filtered to just those associated with the selected category. The question is how to implement this. Each subcategory belongs to a category, so we can associate each one with a category ID (I refer to this as its parent ID). To support this, I created the CascadingDictionaryItem class. This is a simple class that just stores the ID of a dictionary item, its description, and most importantly its parent ID. When defining the subcategories dictionary, instead of defining it as Dictionary<int, string> we’ll define it as Dictionary<int, CascadingDictionaryItem>. When the user selects/changes the product category, we can capture this event (in the presentation layer) and repopulate the subcategory combo box with only the subcategories with a parent ID matching the ID of the selected category (via a LINQ query). This will be discussed further in the next article.
Updating the WCF Service
Now we have our Product business object, we need to add the ability to populate this from the database, add a new product to the database, update an existing product in the database, and delete a product from the database. Essentially these are your standard CRUD (create, read, update, and delete) functionality. I’ve been asked why I’m implementing this functionality myself instead of using ADO.NET Data Services (previously code named Astoria) which was designed for precisely this scenario. Essentially my answer is that to obtain the simplicity that ADO.NET Data Services provides you need to trade off power. I have to say that I haven’t spent a lot of time playing with ADO.NET Data Services so I’m not working from a fully informed opinion, but from what I’ve seen it looks as though I’d have to still implement a lot of custom code to do the things I need to do, so I might as well just implement the whole web service boundary myself and save myself any problems (it’s a fairly basic task to write my own web service so I don’t believe I really have a lot to gain by using ADO.NET Data Services). Any feedback and alternative opinions are most welcome.
In our GetProduct web service method we are simply querying the Entity Framework for a single product entity with a matching ID. In our LINQ query we populate our business object directly from the data from the returned entity and return it to the client. Very similar to how we populated our ProductSummary DTO previously. Note that there is a lot of associated data with the product that we could have returned to the client (such as the product inventory records, product photos, cost history, list price history, etc) but haven’t. We will probably want to do this as the development advances, but at this stage we are keeping things simple and excluding this associated data from being returned.
Adding and updating a product has been combined into a single SaveProduct function on our web service. If the ProductID of the passed in object is 0 then we assume we are adding the product to the database, otherwise we update the existing record with the matching product ID. Note that we are validating the passed in business object against the business rules before persisting it to the database, throwing an exception if it fails the rules. Of note in this function, if we are updating an existing product we don’t bother loading the existing product from the database first, saving a database round-trip. Instead we simply create a new product entity, set its product ID, and use the AttachTo function on our entity to attach it to our entity model. This effectively does an update of the existing record in the database. Note also that since the ID properties of the entities associated with the product (such as the ProductCategoryID property) are not exposed on the entity we need to do a similar thing by creating an instance of the associated entity, set it’s ID to the value set against our business object, and attach it to the model. Not straightforward, but easy enough to do once you know what to do. We then update the modified date of the entity to the current time (I decided to use the UTC time rather than the local time to indicate the last modified date/time), then save the changes to our entity model context. Finally we return the ID of the product back to the client – important when adding products so that multiple saves on the client of a new product doesn’t create multiple new products in the database.
Note that in updating products we are not currently taking concurrency into account, but simply overwriting whatever the current values in the database are despite whether someone else has updated this product since the product details were retrieved. To briefly explain concurrency, if user 1 requests the details of a product, and in the meantime user 2 updates those details in the database, once user 1 sends their changes to the product back to the database it will overwrite the changes that user 2 made. Ideally you would want to handle this situation and notify user 1 that user 2 updated the product in the meantime, and attempt to merge the changes together somehow. In a large enterprise project you would want to identify any concurrency conflict (using a time stamp, guid, or some other means) rather than simply having a last change wins policy. There is a bit of work to implement this well, and I have chosen to focus on the Silverlight specific issues in this article series rather than these general issues, but I raise it as a situation you should consider and handle in your own projects.
The final change to the web service is to return our dictionaries. The GetProductDictionaries() method was added to the web service to return the product group of dictionaries to the client in one call. This just populates our ProductDictionaries class with the results of several queries to the entity framework, each returning collections of key/value pairs to populate each dictionary with.
Conclusion
We now have a framework for our business objects and create a basic Product business object that uses it. We’ve also defined a means for getting dictionaries from the server and caching them. Finally we updated our web service to provide the CRUD functionality for our Product business object and to return our product dictionaries. Stay tuned for my next article which will cover methods to implement the user interface to view/add/edit/delete a product.
Resources
Rocky Lhotka’s CSLA Light:
http://www.lhotka.net/cslalight/download.aspx
Using CSLA .NET for Silverlight to Build Line-of-Business Applications:
http://www.code-magazine.com/article.aspx?quickid=0811061
Adventure Works Cycles Business Scenarios:
http://msdn.microsoft.com/en-us/library/ms124825.aspx
Paul Stovell’s Business Rule Validation Design:
http://www.codeproject.com/KB/cs/DelegateBusinessObjects.aspx