Professional Documents
Culture Documents
UsingCsla4 02 Objects
UsingCsla4 02 Objects
Rockford Lhotka
Using CSLA .NET 4: Creating Business Objects
All rights reserved. No part of this work may be reproduced or transmitted in any form or by any
means, electronic or mechanical, including photocopying, recording, or by any information
storage or retrieval system, without the prior written permission of the copyright owner.
Trademarked names may appear in this book. Rather than use a trademark symbol with every
occurrence of a trademarked name, we use the names only in an editorial fashion and to the
benefit of the trademark owner, with no intention of infringement of the trademark.
The information in this book is distributed on an “as is” basis, without warranty. Although every
precaution has been taken in the preparation of this work, the author shall not have any liability
to any person or entity with respect to any loss or damage caused or alleged to be caused directly
or indirectly by the information contained in this work.
The source code for this book (CSLA 4 version 4.1.0) is available at
http://www.lhotka.net/cslanet.
Revision: 1.1
Acknowledgements
Neither this book, nor CSLA 4, would have
been possible without support from Magenic.
Magenic is the premier .NET development
company in the US, and is a Microsoft Gold
Certified Partner.
List of Figures
Figure 1. Process followed when setting a property value ........................................................... 21
Figure 2. Setting the assembly and namespace names in a .NET project ..................................... 51
Figure 3. Setting the assembly and namespace names in a Silverlight project ............................. 51
Figure 4. Setting the assembly and namespace names in a Windows Phone project ................... 52
Figure 5. Class library containing code files ................................................................................ 52
Figure 6. Add an existing item ...................................................................................................... 53
Figure 7. Adding files as a link ..................................................................................................... 53
Figure 8. Project containing linked files ....................................................................................... 54
By the end of this book you will understand the base classes, their related stereotypes and the
primary features of each base class supporting these areas of functionality.
Stereotypes
Object-oriented design and programming involve the idea of taking similar concepts and
implementations and grouping them together into classes and stereotypes. You know about classes,
they are bits of code that organize related behaviors together so you can create individual instances
of those classes. Stereotypes are a broader concept that group together broad types of behavior.
Not necessarily specific behaviors, but specific types of behavior.
For example, a class might implement a specific business rule, and all instances of that class
(objects) have that rule. A stereotype is broader, suggesting that there’s a type of class that can
implement rules. So any class that has a rule is part of this “type that has rules” stereotype.
Good object-oriented design relies on stereotypes to help organize such broad concepts into
classes, allowing developers to combine those classes through composition, inheritance, or other
techniques into reusable and comprehensible types.
CSLA .NET relies on this concept of a stereotype to help define how it supports the creation of
powerful and flexible business domain objects that compose a business layer. The stereotypes
directly supported by CSLA 4 are listed in Table 1.
Read-only child list List containing read-only child objects; list ReadOnlyListBase<T,C>
is contained within another object and ReadOnlyBindingListBase<T,C>
can not be retrieved directly from
database.
Name/value list List object containing read-only NameValueListBase<K,V>
name/value objects.
Serialization
All business domain objects created for use with CSLA .NET must be serializable. The term
serializable means that the .NET and CSLA .NET frameworks are allowed to pull the field values
(even if not public) from a business object instance, and then use those field values to create an
exact clone of the original object, either on the same computer or on a computer across the
network.
This serialization, or cloning, is required by the mobile object concept I discussed in the Using
CSLA 4: CSLA .NET Overview ebook. Because mobile objects are a central feature of CSLA .NET, it
should make sense that all business types must be serializable to work with CSLA .NET.
The .NET framework has numerous types called serializers or formatters that clone object
graphs. Only two are capable of creating true clones of objects: the BinaryFormatter and the
NetDataContractSerializer (NDCS).
Silverlight and WP7 have no serializers that can create true clones, so CSLA .NET includes the
MobileFormatter, which provides the necessary functionality on Silverlight, WP7 and .NET.
In all cases, to be serializable, you must apply an attribute on your business class to give the
runtime permission to serialize your objects. Normally, this is the Serializable attribute.
When using the NDCS, you can choose to use the DataContract and DataMember attributes over
the Serializable attribute. I recommend against this, because it prevents the use of the
BinaryFormatter or MobileFormatter. Even worse, you must remember to apply the DataMember
attribute on every single field declaration in your business class or you won’t get a complete clone
of the object. This “opt-in” technique is great for creating public service APIs, but is extra manual
work when creating business objects.
Later in this ebook, I’ll discuss the recommended property declaration and implementation
syntax for use in business types. That syntax is connected to serialization, and specifically, to the
way the MobileFormatter serializer works.
Whereas the BinaryFormatter and NDCS are able to use reflection to get and set non-public
field values in your objects, that type of reflection is prohibited in Silverlight for security reasons.
This is the reason those serializers don’t exist in Silverlight.
The MobileFormatter serializer avoids this issue by not using reflection, and instead relying on
active participation from each object to get and set the field values. CSLA .NET includes several base
class types that mostly automate this entire process, so you don’t have to worry about serialization.
As I’ll discuss later, you can choose to manually declare your own private fields for your
property values. In that case, you assume responsibility for overriding methods to get and set those
field values for serialization.
Choosing Serializers
When running on the .NET platform, the BinaryFormatter is used for serialization by default. When
running on Silverlight or WP7 (or if a .NET application server is interacting with a Silverlight client),
the MobileFormatter is used for serialization.
The MobileFormatter is the only option for Silverlight and WP7 applications.
For .NET applications you can choose between the three serializers through configuration.
I recommend that you only configure CSLA .NET to use the NDCS if you use the
DataContract attribute instead of the Serializable attribute in your business
classes. Because I don’t recommend using the DataContract attribute, I generally
don’t recommend forcing the use of NDCS.
To configure CSLA .NET to use the NDCS you must add an element to the appSettings of your
app.config or web.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="CslaSerializationFormatter" value="NetDataContractSerializer"/>
The important thing to remember is that all business classes must use Serializable for
DataContract to work with CSLA .NET. Throughout the rest of the book I’ll assume the use of the
Serializable attribute.
Normally the BinaryFormatter is a faster and more efficient serializer, so you shouldn’t override
the default. That said, the MobileFormatter avoids the use of reflection and so it may work in
medium trust environments where the BinaryFormatter is disallowed.
Again, I recommend not overriding the default configuration of the serializer in most application
scenarios.
Object Lifetime
Within the .NET framework all object instances have a lifetime. Typically an object is created using
the new keyword, and it is removed from memory by the .NET garbage collector some time after all
references to the object have been removed.
Business objects created using CSLA .NET often have a slightly more complex lifetime, because it
is assumed that these objects often contain data that must be retrieved from a database and later
saved into that database. The Using CSLA 4: Data Access ebook will cover these processes in detail.
For now you should understand that most business objects are created using the data portal, not
the new keyword. This allows CSLA .NET to help you manage the object’s lifetime, including
initializing the object’s state and metastate, as I’ll discuss later in this ebook.
Object Relationships
An object is a specific instance of a class, or type. Objects can have properties that refer to other
objects, creating a relationship between those two objects. It is important to understand that there
are different kinds of relationship that can exist between objects. Table 2 lists some important kinds
of relationship.
Relationship Description
Containment One object contains another object, such that the contained
object is part of the containing object. This is often referred to as
a parent-child relationship, because the child is part of the
parent.
Using CSLA 4: Creating Business Objects Page 6
Rev 1.1
Using One object uses the behaviors of another object, collaboring with
that object to accomplish some end goal. In this type of
relationship the objects are separate and independent, and
neither contains the other.
Containment
For example, an OrderEdit object contains a LineItems collection, which in turn contains
LineItemEdit objects. These are all containment relationships, and all these objects together form
something called an object graph.
An object graph is a family of related objects that directly rely on each other to implement their
respective behaviors. In this example, the OrderEdit object may calculate a TotalAmount value, and
that can only be done given access to the LineItemEdit objects it contains.
There are some important terms used to describe the objects in a containment relationship:
parent and child.
A parent object is an object that contains other objects. A child object is an object that is
contained within a parent object. It is important to realize that an object can be both a parent and a
child at the same time.
For example, consider that the LineItemEdit object could contain a LineItemDetails collection
of LineItemDetailEdit objects. In that case the LineItemEdit object is a child of LineItems, but is
also a parent.
A parent object that is not a child is called a root object. A root object is special, because it is the
top of the object graph. It is the one object that isn’t contained within another object, and so it is
the root of the object graph.
Using
A using relationship is quite different. For example, each LineItemEdit object might need to
calculate a tax on its price. But the concept of calculating a tax can vary from country to country,
and between provinces and states. Rather than embedding the tax calculation in the LineItemEdit
class, it is better to have a separate TaxCalculator type, allowing different implementations for
different geographic settings.
In this case the LineItemEdit objects might use a TaxCalculator to calculate the tax, but
there’s no way you could argue that the TaxCalculator is a child of a LineItemEdit object.
Not only is there an important conceptual difference here, but the actual code that implements
such relationships is different, as you’ll see when I walk through the implementation of the various
stereotypes and show how they interact.
If result is true then you know that the two fields are pointing to the same object in memory.
You can also ask if two objects are equal to each other, but this is a much more complex
question. Obviously an object instance is always equal to itself, but what if you have two different
instances (and therefore consume different memory), but which share exactly the same public
property values?
Such objects might be considered equal, but suppose they have different private field values,
even though their public properties match?
Your application might need to apply a different definition of equality from other applications for
various reasons, and so the .NET framework allows you to override the Equals method in your
classes, and to implement the IEquatable interface.
Prior to .NET 3.0, this was fairly common practice. Now, WPF imposes some very severe
restrictions on equality, at least for items contained within collections. For collections to function
properly when bound to any WPF UI elements, the items in a collection can implement only a
couple forms of equality:
Reference equality
100% property and field equality between both objects
For all practical purposes this means that you should avoid overriding Equals, because the
default implementation is reference equalty.
This is important for CSLA .NET developers, because earlier versions of CSLA .NET enabled the
use of something called logical equality, where CLSA .NET made it relatively easy for you to override
Equals by implementing a method called GetIdValue in your business classes.
You should avoid overriding GetIdValue, as it is now considered deprecated and will
be removed in a future version of CSLA .NET.
CSLA .NET 3.0 and higher doesn’t support logical equality. The GetIdValue method exists only
for backward compatibility.
Limitations on reflection
Asyncronous server access
Threading
Data Access
I’ll discuss these differences here, and you’ll see examples of them in Chapter 3 as I walk through
each business object stereotype.
Limitations on Reflection
On the .NET platform reflection can be used to do many things, even interacting with non-public
members of an object. For example, you can use reflection to get or set private field values in an
object, or invoke a private method, or even create an instance of an object that has no public
constructors.
The .NET and CSLA .NET frameworks make use of these capabilities to do things like serialize
objects and make dynamic method calls. The CSLA .NET framework also uses reflection to get
information about business objects, such as retrieving a list of the object’s properties.
On the Silverlight and WP7 platforms reflection is restricted for security reasons. It is not
possible to use reflection to interact with non-public members of an object.
You can use reflection to interact with non-public members in your specific class.
Not in a subclass or base class, just your class. And certainly not in other types,
which prevents reflection from being useful in any scenario required by CSLA .NET.
Starting with CSLA .NET 3.6 the framework has included features to avoid and minimize the use
of reflection so the framework could support Silverlight 2 and higher. Table 3 lists some specific
places this affects your code.
Scenario Description
Property implementation CSLA .NET supports two basic ways to implement properties. The
concept of managed backing fields (discussed later) allows
automatic serialization of objects without using reflection.
Member scope In CSLA .NET code for .NET, many members can be private,
including the PropertyInfo<T> fields, data portal methods, and
the AddObjectAuthorizationRules method. In Silverlight
these must be public, otherwise CSLA .NET won’t be able to
discover or interact with these members and your business
Using CSLA 4: Creating Business Objects Page 9
Rev 1.1
objects won’t function correctly.
Constructors In CSLA .NET code for .NET I used to recommend that all business
classes have a non-public default constructor. The idea was to
remind users of the business class that they should use factory
methods, not the new keyword, to create instance of the type. In
Silverlight you must supply a default public constructor for
serialization to function.
Feature Description
Asynchronous data portal The data portal can be invoked synchronously or asynchronously
on .NET, and only asynchronously on Silverlight and WP7.
Asynchronous business rules Business and validation rules can be synchronous or
asynchronous. You should use asynchronous rules if your rule
needs to interact with the data portal or another object’s factory
methods in an async manner.
Busy status tracking Business objects have properties such as IsBusy and
IsSelfBusy that indicate whether the object (or one of its
properties) is currently executing an async operation.
You should be aware that asynchronous operations are usually beneficial for any smart client
applications, including Silverlight, WPF, WP7, and Windows Forms. The primary benefit comes
through the fact that interactions with the server don’t lock up the UI, so the user has a better
overall experience.
That said, you should keep in mind that asynchronous operations make web development more
complex. This is because each web request is a non-interactive request from the browser that
normally runs on a single thread. It is critical that this primary thread not complete its work until
any async operations are complete, and that doesn’t happen automatically. This means you need to
write your own synchronization code to prevent that main thread from completing before all your
async operations complete. This leads to complexity, so I recommend avoiding the use of async
operations in ASP.NET applications as a general rule.
Threading
Threading is closely related to asynchronous operations, because the completion callback from a
normal async operation in .NET normally occurs on a background thread. You are responsible for
moving that callback to the UI thread before interacting with any UI objects, or objects that are data
bound to the UI.
Silverlight and WP7 avoid this complexity by automatically shifting completion callback calls to
the UI thread for you. This is a pretty significant difference between the .NET and Silverlight
platforms.
CSLA 4 helps you avoid confusion and complexity by also automatically shifting completion
callback calls from the data portal and async business rules to the UI thread for you. This means
that when using the async features of CSLA 4 you shouldn’t normally have to worry about
marshaling calls to the UI thread, as all completion callbacks are already on the UI thread.
In Chapter 4, I’ll discuss asynchronous business rules in more detail, including a discussion of
where you can write code that will run on a background thread, and where your code is
automatically running on the UI thread.
Data Access
Silverlight has no data access API such as ADO.NET, and so it is not possible to write typical data
access code in Silverlight. You can use simple files for data storage through the isolated storage API
in Silverlight, but a typical Silverlight application will either use the data portal to interact with a
remote application server, or will make remote service calls to a service API by using WCF.
Using CSLA 4: Creating Business Objects Page 11
Rev 1.1
I’ll discuss data access in more detail in the Using CSLA 4: Data Access ebook. What is important
to understand right now, is that any data access code you might write in your business classes
needs to be wrapped in a compiler directive so the classes aren’t built on the Silverlight or WP7
platforms:
#if !SILVERLIGHT
// .NET-only data access code goes here
#endif
CSLA 4 tries to abstract the differences between the .NET and Silverlight platforms. Where this
isn’t possible, you will need to accommodate the differences in your own code, often using the
compiler directive strategy I’ve just discussed.
Property Declarations
Any .NET developer knows how to declare a standard property using the long and short syntax
available in C# or VB. For example:
public int MyNumber { get; set; }
For simplistic coding scenarios, this code can work fine. The story is very different if you are
creating business objects that support data binding, business rules, validation and authorization. In
that case, property declarations can become much more complex.
As an example, before returning a value in the property getter, you should check to see if the
user is authorized to see this value. Similarly, in the property setter you should do all the following:
The GetProperty method checks authorization to make sure the current user is allowed to see
the value before returning the value.
The SetProperty method does a lot more, including:
Checks authorization to make sure the current user is allowed to change the value
Ensures the new value is different from the existing value
Raises the PropetyChanging event
Records the new value
Runs any business and validation rules associated with this property
Runs any business and validation rules associated with related properties
Marks the object as having been changed
Raises the PropertyChanged event (using the correct behavior for Windows Forms or other
UI environments as appropriate)
Using CSLA 4: Creating Business Objects Page 13
Rev 1.1
In short, all the behaviors you’d otherwise have to implement by hand are encapsulated in the
GetProperty and SetProperty helper methods.
Helper Methods
I’ve already mentioned the GetProperty and SetProperty helper methods. There are several
additional helper methods you’ll need to use to implement all the different property
implementation options. These are listed in Table 5.
Method Description
GetProperty Gets a property value, first checking authorization rules
ReadProperty Gets a property value without checking any authorization rules
SetProperty Sets a property value performing all processing as discussed in
the previous section in this chapter (running business rules, etc.)
LoadProperty Sets a property value without checking any rules, raising any
events or marking the object as having been changed
GetPropertyConvert Gets a property value, first checking authorization rules and
converting the backing field value to the appropriate property
value type
ReadPropertyConvert Gets a property value without checking any authorization rules
and converting the backing field value to the appropriate
property value type
SetPropertyConvert Sets a property value performing all processing as discussed in
the previous section in this chapter (running business rules, etc.)
and converting the new property value to the appropriate
backing field type
LoadPropertyConvert Sets a property value without checking any rules, raising any
events or marking the object as having been changed and
converting the new property value to the appropriate backing
field type
RegisterProperty
The RegisterProperty method is responsible for registering metadata about a property. This
method has numerous overloads to accommodate different property declaration scenarios, and
you’ll see them in use as I walk through each type of property declaration.
Ultimately, RegisterProperty does two basic things.
First, it gets or creates an IPropertyInfo (from the Csla.Core namespace) instance that
contains the property metadata. Typically, this is a PropertyInfo<T> instance as shown in this
example. That value is returned as a result of the RegisterProperty method, so you can store the
value in a static field for use throughout your code.
Second, this IPropertyInfo instance is added to a static data structure maintained by CSLA
.NET so it is possible for the framework (and therefore your code) to get a list of all the properties
registered for a business class type without the need for reflection.
Avoiding reflection is often a good idea for performance reasons, and that’s a nice side-benefit in
this case. But the real value here is that this mechanism allows CSLA 4 to automatically serialize and
deserialize objects on the Silverlight and WP7 platforms where reflection has restrictions that make
it otherwise impractical to create a normal .NET serialization component.
From a day to day practical perspective, the benefit to registering properties like this is that your
business code has easy access to a static field that represents the property. This makes it easy to
use metadata about the property, or to refer to the property without resorting to the use of the
property name in string form.
So you can use MyTextProperty instead of “MyText” to talk about the MyText property. This
increases the maintainability of your code, because standard refactoring tools will automatically
rename the strongly typed metadata field, but wouldn’t rename any string literal names referring to
your properties.
Element Description
Name Gets the name of the property (or method)
Type Gets the type of the property
FriendlyName Gets the human readable friendly display name of the property
DefaultValue Gets the default value for a new instance of the property
NewFieldData Gets a new field data container for the property; for advanced
scenarios only
RelationshipType Gets the relationship type for the property
Index Gets the index position of the property in the internal field
manager data store; for internal CSLA .NET use only
In this case, the _myText field is the backing field for the property, and it is manually declared.
When using the more compact C# (or VB) syntax for property declaration a field is still declared,
but the compiler makes up a name for the field on your behalf. Even this property has a backing
field:
public int MyNumber { get; set; }
Even though you don’t explicitly declare the field or know its name, it is there thanks to some
compiler magic.
CSLA 4 allows you to implement properties using a manual backing field, or with what is called a
managed backing field. In the case of a managed backing field, the CSLA .NET base class manages
the property’s value on your behalf. Examine this property implementation carefully:
public static readonly PropertyInfo<string> MyTextProperty =
RegisterProperty<string>(c => c.MyText);
public string MyText
{
get { return GetProperty(MyTextProperty); }
set { SetProperty(MyTextProperty, value); }
}
Notice that no backing field is explicitly defined, and in this case there’s no compiler magic
involved either; there is no real backing field. Instead, the CSLA .NET base class (usually
BusinessBase<T>) is managing the value of the property on your behalf.
The advantage of using manual backing fields is that you gain a slight performance benefit,
because private fields are directly allocated in memory. If you are building Silverlight or WP7
applications, the drawback to using these fields is that you must write code to explicitly serialize
those property values during all serialization and deserialization processing. CSLA 4 supports this
scenario, but you need to be aware that this extra work is required. I’ll discuss the specifics later in
this chapter.
The advantage of using managed backing fields is that your code is simpler, and if you are
building Silverlight or WP7 applications all managed field values are automatically serialized and
deserialized as needed. It is important to note that there is a small performance impact to using
managed backing fields; because the CSLA .NET base class must manage the values in a data
structure somewhat like an optimized dictionary.
In the next section of this chapter I’ll walk through the types of property declaration and
implementation using managed backing fields, and then I’ll show how they are implemented using
manual backing fields.
Read-Write
Perhaps the most common type of property is the read-write property. This is a property with a
public getter and setter designed to allow code using the object to get and set the property value,
subject to all authorization and business rules, and triggering all appropriate data binding and other
behaviors.
public static readonly PropertyInfo<string> MyTextProperty =
RegisterProperty<string>(c => c.MyText);
public string MyText
{
get { return GetProperty(MyTextProperty); }
set { SetProperty(MyTextProperty, value); }
}
Notice that the RegisterProperty method is generic, and so it gets the type of the value being
stored for the property (string in this case). Also notice that a lambda expression is passed as a
parameter to RegisterProperty to provide a strongly-typed reference to the property itself:
c => c.MyText
Behind the scenes, the RegisterProperty method takes this lambda expression and uses
reflection to get access to the PropertyInfo object from System.Reflection corresponding to this
property. It uses that PropertyInfo object to obtain other metadata about the property.
1. Check authorization rules and throw an exception if user isn’t allowed to change the value
Add a few more elements, and the process can become much more complex, as illustrated in
Figure 1.
New value
Yes No
different?
Raise
Mark field as
Yes PropertyChanging
changed?
event
Change value
No
Mark field as
changed
Change value
Raise
PropertyChanged
event
No Hook changed
event
Done
At this point, you should have an understanding of the property registration process and how
property getters and setters work with read-write properties. The other types of property
implementation are mostly variations on this same set of concepts.
Remember from Table 5 that these two helper methods get and set property values without
invoking any business rules. When implementing read-write properties in classes other than those
inheriting from BusinessBase, this is the syntax you should use.
If you want to create a “private field” you can make the property non-public:
public static readonly PropertyInfo<string> MyTextProperty =
RegisterProperty<string>(c => c.MyText);
private string MyText
{
get { return ReadProperty(MyTextProperty); }
set { LoadProperty(MyTextProperty, value); }
}
Notice that I’ve left the static metadata field public in scope, even though the property itself is
private. You may choose to make the metadata field private in scope, but this will block certain
data access models. In particular, you won’t be able to easily use the ObjectFactory data access
models because the factory object will have no way to interact with the field value. I’ll discuss this
in more detail in the CSLA 4: Data Access ebook.
While this technique is widely used, it is important to realize that it doesn’t lend
itself to localization because there’s no way to change the enum to reflect the user’s
culture or language.
This is the value you want to have in your object, but you want to expose the value to the UI or
other consuming code as its string representation, with automatic parsing of any input values into
the enum value type and having your property getter convert the enum to a string.
Using CSLA 4: Creating Business Objects Page 23
Rev 1.1
In this example, a string property should only allow the values "Item1", "Item2" or "Item3",
because those are the text representations of the underlying numeric enum value.
This can be done by using GetPropertyConvert and SetPropertyConvert in your property
implementation:
public static readonly PropertyInfo<TestEnum> MyStringEnumProperty =
RegisterProperty<TestEnum>(c => c.MyStringEnum);
public string MyStringEnum
{
get { return GetPropertyConvert<TestEnum, string>(MyStringEnumProperty); }
set { SetPropertyConvert<TestEnum, string>(MyStringEnumProperty, value); }
}
Notice that the property type is string, but the RegisterProperty call uses the type TestEnum.
What this means is that the CSLA .NET field manager infrastructure will store a value of type
TestEnum in memory, but the public-facing property is of type string.
The GetPropertyConvert method takes two generic type parameters. The first is the type of the
backing field value (TestEnum) and the second is the type of the property (string). Code setting the
property might look like this:
obj.MyStringEnum = "Item2";
The code could attempt to set the value to text that can’t be parsed as an enum value:
obj.MyStringEnum = "abc";
That will result in a PropertyLoadException from the Csla namespace being thrown by the
SetPropertyConvert method.
Any code reading the property value will get a string result, containing the text name of one of
the valid enum values.
As I mentioned earlier, this value conversion process will work as long as the property type and
the backing field type are convertible following the .NET type conversion rules. There are many
mechanisms by which .NET allows a value of one type to be converted into another type, and CSLA
.NET will attempt to apply every one of those techniques to perform the conversion. If two types
are not convertible, then GetPropertyConvert and SetPropertyConvert will throw type conversion
exceptions at runtime.
Read-Only
Perhaps the second most common type of property is a read-only property. There are a couple
variations on how you will implement a read-only property, depending on the CSLA .NET base class
from which you inherit to create your business class.
In this case, the property getter is the same as with a read-write property, and the GetProperty
method will enforce any authorization rule associated with this property as I discussed earlier.
The property setter is private in scope, and uses the LoadProperty method instead of
SetProperty. The LoadProperty method is used based on the assumption that read-only properties
won’t normally be changed during the lifetime of the object.
If you do intend to change the value of a read-only property during the lifetime of the object,
you will typically change the property setter to call SetProperty instead, so you get normal
business rule and data binding behaviors as the property changes.
The basic structure is the same, but in this case the ReadProperty method is used, so no
authorization rules are checked when the property getter is invoked.
Similarly, you can have a read-only property with value conversion that applies authorization
rules in the getter by using GetPropertyConvert:
public static readonly PropertyInfo<TestEnum> MyStringEnumProperty =
RegisterProperty<TestEnum>(c => c.MyStringEnum);
public string MyStringEnum
{
get { return GetPropertyConvert<TestEnum, string>(MyStringEnumProperty); }
private set { LoadPropertyConvert<TestEnum, string>(MyStringEnumProperty, value); }
}
Once the static metadata field has been declared, you have access to all the getter and setter
helper methods and can mix and match them as necessary to implement your properties.
The CSLA .NET framework uses this relationship type information to understand that this is a
child reference, so it can automatically handle a number of scenarios around n-level undo and
object persistence on your behalf.
Notice that the getter uses the GetProperty method, so only authorized users can get access to
the child object, and that the setter is private in scope and uses the LoadProperty method to set
the field value with the child object reference.
With a property implementation like the one shown here, the child object is typically created as
part of the process of creating the parent object. I’ll discuss this in more detail in the Using CSLA 4:
Data Access ebook, but in general your code that creates or retrieves the parent object will include
a line of code to initialize the child property:
Addresses = DataPortal.CreateChild<AddressEditList>();
If the user usually views or uses the child object, it is more efficient to create or
retrieve the child object at the same time you create or retrieve the parent object.
Lazy loading is typically implemented by leaving the child property value as null until the
property getter is invoked. Only if some code calls the property getter do you know that the child
object is required, and so that’s the point at which you create or retrieve the child object. This
process is different depending on whether you are using synchronous or asynchronous data access.
While I will show you how to implement each type of property here, I’ll cover the sync vs async
issues in more detail in the Using CSLA 4: Data Access ebook.
You must specify another relationship type in RegisterProperty to tell CSLA .NET that you are
using lazy loading for the property: RelationshipTypes.LazyLoad. This information is used by CSLA
.NET to properly handle child properties that are lazy loaded. For example, the previous Addresses
property could be changed like this:
public static readonly PropertyInfo<AddressEditList> AddressesProperty =
RegisterProperty<AddressEditList>(c => c.Addresses,
RelationshipTypes.Child | RelationshipTypes.LazyLoad);
Notice that both the Child and LazyLoad values are specified because this is a lazy loaded child
property.
#if !SILVERLIGHT
public static AddressListCreator GetAddressListCreator()
{
return DataPortal.Fetch<AddressListCreator>();
}
Notice how the example data access code in the AddressListCreator class populates the
Result property with the newly created child object.
Again, the specifics of this code can be different depending on which data access model you are
using, but the basic concept is the same: an instance of the child object is created or retrieved, and
the property value is set to reference that child object instance.
This AddressListCreator is then used to implement the lazy loading of the child object in the
parent class’s property getter. The specific code to do this will be somewhat different for synch vs
async scenarios, so I’ll cover each option.
The parent object’s Addresses property value is then set to this Result value. Notice that the
setter includes an explicit call to OnPropertyChanged, because LoadProperty doesn’t raise the
PropertyChanged event, but when doing lazy loading it is a good idea to ensure this event is raised
so any UI elements or other code bound to this property value are notified that there is now a child
object available.
Now that the property value has been loaded with a value, the normal GetProperty method is
invoked to return the value to the calling code.
The primary difference from the synchronous implementation is that the BeginFetch method is
called on the data portal instead of the Fetch method. This means that the AddressListCreator is
retrieved asynchronously.
Obviously this has a pretty significant impact on the overall workflow. The calling code that
attempted to call this property will get a null result, because the property doesn’t yet exist, but the
attempt to access the property starts the async process of loading the property with a value.
It is important to always check the e.Error value to find out if any exceptions occurred during
the async operation. One of the most common challenges people face when doing async
programming is that an exception occurs on a background thread or on the server, and they forget
to check e.Error and so are unaware of what went wrong.
If there was no exception, e.Object contains the result of the BeginFetch call, which means it
contains the AddressListCreator object. That means the code can load the Addresses property
value from its Result property.
When the Addresses property is set, the OnPropertyChanged method is invoked in the setter,
which means the PropertyChanged event is raised for the child property. This is the signal to any
calling code (such as the UI) that there is now a child object available. In most cases, data binding
will automatically respond to the PropertyChanged event and will rebind the UI controls to the
newly available child object.
I will revisit lazy loading of child properties in the Using CSLA 4: Data Access ebook, because your
implementation of the “child creator” object (AddressListCreator in this example) is dependent
on the data access model you choose.
The important thing to understand is that the parent object’s property implementation is
unaffected by the data access model. The implementation I’ve shown here is consistent, and any
differences due to data access choices are abstracted within the child creator class implementation.
Inter-graph references
Using CSLA 4: Creating Business Objects Page 30
Rev 1.1
Using relationship references
Scenarios where you need to apply attributes to fields
High-performance scenarios where using managed backing fields is a performance
bottleneck
The first three items in the list are inter-related, because implementing an inter-graph reference
or using relationship requires that you apply attributes directly to the backing field for the property.
The last item, performance, should be relatively rare. While there is some performance benefit
to using manual backing fields over managed backing fields, it is typically not a meaningful
difference. My recommendation is to implement using managed backing fields, and fall back to
using manual backing fields only if you encounter an issue where their performance benefit is worth
the extra complexity.
Even when using a manual backing field, you will still register a static metadata field for the
property. It is important to specify the PrivateField relationship type when registering such a
property.
Overloads of the helper methods exist that work with private fields. So the overall structure of
a property remains consistent. For example:
public static readonly PropertyInfo<string> CityProperty =
RegisterProperty<string>(c => c.City, RelationshipTypes.PrivateField);
private string _city = CityProperty.DefaultValue;
public string City
{
get { return GetProperty(CityProperty, _city); }
set { SetProperty(CityProperty, ref _city, value); }
}
Notice how a private backing field is manually declared, and initialized with the DefaultValue
property from the static metadata field. Initializing the field like this helps maintain consistency
with the behavior of managed backing fields.
Next, look at the GetProperty and SetProperty method calls, and notice how the backing field is
passed as a parameter to each method. Most notably, it is passed by ref to SetProperty so that
helper method can efficiently change the field value, while still applying the same authorization,
business rules and other processing that you get with managed backing fields.
In fact, the behavior of this property is identical to its managed implementation, which would
look like this:
public static readonly PropertyInfo<string> CityProperty =
RegisterProperty<string>(c => c.City);
public string City
{
get { return GetProperty(CityProperty); }
set { SetProperty(CityProperty, value); }
}
It is important to realize that only GetProperty and SetProperty have overloads that support
manual backing fields. There’s no need for ReadProperty, LoadProperty or the type conversion
overloads, because your code always has direct access to the field itself. If you need to get or set
the field value without invoking business rules or other standard processing, you can interact
These overloads exist to enable certain data access layer scenarios and I’ll discuss them in more
detail in the Using CSLA 4: Data Access ebook. You should know that they involve the use of some
late bound technologies to get and set the value and so do have some performance cost. Despite
this performance cost, they can provide a standard, loosely typed way to get and set values, and so
are very valuable when building certain types of decoupled data access layers.
If you do not add the code to support serialization, your field values will not be
copied between client and server, nor will n-level undo operate against those field
values.
For simple property types (not reference types), this is a matter of overriding two methods in
your class: OnGetState and OnSetState. If your property is a reference type, you’ll need to override
OnGetChildren and OnSetChildren, and you’ll also need to make certain that the object being
referenced implements the IMobileObject interface from Csla.Core.
Table 8 lists the types that are considered “simple types” by MobileFormatter. These types are
directly supported as field values by the serialization process.
Type Description
Value types Types such as int, double, DateTime, etc.
string The string data type
Zero-based enum values A value of type enum can be serialized, as long as
the enum is zero-based (has a value
corresponding to 0)
Because string is a simple property type, the value can be added to the serialization stream in
OnGetState, and retrieved from the serialization stream in OnSetState. The result is that when
MobileFormatter serializes the object, the _city value is included in the serialized data, and when
it deserializes the byte stream, the _city value is restored from the serialized data.
The following code is necessary to serialize and deserialize this reference on Silverlight and WP7:
protected override void OnGetChildren(
Csla.Serialization.Mobile.SerializationInfo info,
Csla.Serialization.Mobile.MobileFormatter formatter)
{
base.OnGetChildren(info, formatter);
if (_person != null)
{
var personInfo = formatter.SerializeObject(_person);
info.AddChild("_person", personInfo.ReferenceId);
}
}
The OnGetChildren method serializes the PersonEdit object by calling the SerializeObject
method of the provided formatter object. The resulting serialized data is added to the serialization
stream by calling the AddChild method.
In the OnSetChildren method, the PersonEdit object is restored from the serialization stream
by retrieving the serialized data, and then calling the GetObject method on the supplied formatter
object. The result is cast to the correct type and used to set the _person field value.
Inter-Graph Reference
Sometimes you’ll have one object in your object graph that references another object, but it isn’t a
child relationship. For example, a PersonEdit object might contain a list of AddressEdit objects,
and those would be child objects. But PersonEdit might also have a PrimaryAddress property that
references one of the addresses in the list. This is an inter-graph reference, but isn’t a child
reference.
The distinction here is subtle but important, and it relates to the way n-level undo works within
CSLA .NET. Calling BeginEdit on a parent object raises the parent’s edit level by one, and also raises
all its child objects’ edit levels by one. This allows you to later call CancelEdit or ApplyEdit on the
parent to undo or commit all changes made to the object graph in memory.
If a child object is considered to be a child twice then when BeginEdit was called on the parent
object, that child object would have its edit level raised twice instead of once. The result would be
an edit level mismatch, because the child would be doubly edited and out of sync with the rest of
the object graph.
To avoid this issue, you need to mark the reference with the NotUndoable attribute. This
attribute goes on the backing field for the property, and so you must implement this property using
a manual backing field. For example, here’s a PrimaryAddress property from the PersonEdit class:
public static readonly PropertyInfo<AddressEdit> PrimaryAddressProperty =
RegisterProperty<AddressEdit>(c => c.PrimaryAddress, RelationshipTypes.PrivateField);
[NotUndoable]
private AddressEdit _primaryAddress = PrimaryAddressProperty.DefaultValue;
public AddressEdit PrimaryAddress
{
get { return GetProperty(PrimaryAddressProperty, _primaryAddress); }
set { SetProperty(PrimaryAddressProperty, ref _primaryAddress, value); }
}
Notice the use of the NotUndoable attribute on the backing field. This tells CSLA .NET that this
object reference should not be included as part of any n-level undo operation.
Remember that you must override the OnGetChildren and OnSetChildren methods for this
property value to correctly serialize to and from the server if this code is used on Silverlight or WP7.
Using Reference
A using relationship is a reference to an object outside the object graph. In other words, you have a
business object that is referencing another object, and that other object is not contained within, or
included as part of, the same set of objects. Another way to think about this, is that this other
object shouldn’t serialize to and from the server along with your business object.
The best way to implement a using relationship is to avoid storing any reference to the other
object at all. Instead, any time you need to interact with this other object you should create an
While the InvoiceEdit object is retrieving and using a PersonEdit object, it doesn’t keep the
reference, and so there are no issues with maintaining object references, n-level undo or
serialization. This is the ideal situation.
Maintaining a Reference
There may be scenarios where you do need to maintain a reference to an object you are using over
a period of time. In that case you’ll need to implement a property with a manual backing field so
that field can be decorated with the NotUndoable and NonSerialized attributes.
It is also the case that this type of property is typically implemented with a form of lazy or on-
demand loading of the object to be used. This is important, because after deserialization the
property value will always be null, so the property getter must handle that case and initialize the
value.
public static readonly PropertyInfo<PersonEdit> PersonProperty =
RegisterProperty<PersonEdit>(c => c.Person);
[NonSerialized]
[NotUndoable]
private PersonEdit _person = PersonProperty.DefaultValue;
public PersonEdit Person
{
get
{
if (_person == null)
_person = PersonEdit.NewPerson();
return GetProperty(PersonProperty, _person);
}
}
Notice the use of the NonSerialized and NotUndoable attributes, which prevent this field from
being serialized by .NET and from being part of n-level undo processing in CSLA .NET.
Also notice that the getter includes lazy loading code to get an instance of the object on-
demand. This way the target object is created when necessary, even after serialization and
deserialization.
In this example I’ve chosen not to implement a setter at all, because the value is only retrieved in
the getter. This is a pretty typical implementation. If necessary you may certainly implement a
setter.
Finally, you should not override OnGetChildren or OnSetChildren for this field value. The whole
idea is to not serialize the value, so you don’t want to add code to serialize it by overriding these
methods.
Using CSLA 4: Creating Business Objects Page 36
Rev 1.1
Non-Generic LoadProperty Method
Several types of property implementation use the LoadProperty method to set a property’s value
without executing business rules. The LoadProperty method shown in the examples in this chapter
is a generic overload of the method that accepts an IPropertyInfo<T> parameter to identity the
affected property.
There is also a non-generic LoadProperty method overload designed for use in certain scenarios.
Specifically, this non-generic overload is designed for use when implementing web or service
interfaces, or data access code, where the types of the input data and property aren’t known until
runtime.
The non-generic overload is substantially slower than the generic overload, because the value
types aren’t known at compile time. You should use the non-generic overload only if there’s no way
to invoke the generic overload.
Normal property implementation code should always have access to the field containing the
property’s metastate, and so should be able to use the generic overload.
At this point, you should understand how to declare and implement properties using managed
and manual backing fields, as well as properties that reference child and non-child objects.
Method Declarations
As with properties, CSLA 4 provides a formal syntax for declaration and implementation of methods
in a business class. This includes a static field containing metadata about the method, and a helper
method that invokes authentication so your method can easily determine whether the current user
should be allowed to invoke the method.
As you might guess, this means there’s a RegisterMethod method that corresponds to
RegisterProperty, and an IMethodInfo interface in Csla.Core that corresponds to the
IPropertyInfo interface. You use RegisterMethod to establish metadata about the method, and to
create a static metadata field you can use to represent that method when adding your
authorization rule.
public static readonly MethodInfo TestMethod = RegisterMethod(typeof(EditableProperties), "Test");
public void Test()
{
CanExecuteMethod(TestMethod, true);
// do some work here
}
The primary difference from a property is that it is up to the author of the method to check the
authorization rule before allowing the method to execute. This means that the first line of code in
your method is typically a call to CanExecuteMethod, which will throw a SecurityException if the
current user isn’t authorized to execute the method.
Metastate
The CSLA .NET framework helps you create business domain objects that maintain their own status
or metastate. These days this type of object is sometimes called a self-tracking object.
Accessing Metastate
The metastate values tracked by business objects are available directly on editable objects, and also
through interfaces.
Public Properties
The metastate properties listed in Table 10 are all public properties of BusinessBase (and
BusinessListBase where appropriate). This means you can access these properties directly on any
editable business object instance.
INotifyBusy Interface
The INotifyBusy interface enables you to write polymorphic code to determine the busy status of
any business object. Through this interface, you can access the object’s busy status and also handle
its BusyChanged event to be notified when the status has changed.
INotifyChildChanged Interface
The INotifyChildChanged interface defines an event you can use to determine when a child object
in an object graph has been changed. The ChildChanged event is unique, in that it cascades all the
way up the object graph, starting with the immediate parent of the object that changed, but being
raised by every parent object all the way to the root object of the object graph.
You can use this interface to be notified of changes to an object graph regardless of the type of
objects in the graph.
Data Binding
The metastate properties do not directly support data binding, and as they change they do not raise
the PropertyChanged event. This is due to the way Windows Forms data binding works, and due to
the way Visual Studio has implemented its drag-and-drop data binding support.
In WPF, Silverlight and WP7 you will want your UI to bind to many of these metastate properties
to automatically enable and disable various UI elements. In the Using CSLA 4: Silverlight 4 and WPF
ebook I’ll discuss how the ViewModelBase, ViewModel and CslaDataProvider types in the
Csla.Xaml assembly/namespace address this issue.
Basic Status
The basic status properties indicate whether the object is believed to be new or old, and whether it
has been marked for deletion.
IsNew Property
A “new” object is one where there is a reasonable expectation that the object has no corresponding
data in the database or data store. Typically this means that the object’s primary key value doesn’t
correspond to a primary key in the database.
Objects are typically new when:
They were created by the data portal by calling Create, BeginCreate or CreateChild
The object has been deleted
IsDeleted Property
Any subclass of BusinessBase will have an IsDeleted property. This property will be true if the
object is marked for deletion.
CSLA .NET supports two models for deleting editable root objects: immediate and deferred. I’ll
discuss these in more detail in the Using CSLA 4: Data Access ebook, but you should know that it is
rare for an editable root object to support deferred deletion. As a result, IsDeleted is almost
always false for root objects.
Conversely, editable child objects are always deleted through deferred deletion. This means that
the object is marked for deletion, and is only deleted when the object graph is saved. After a child
object has been marked for deletion, IsDeleted is true.
Once an object’s IsDeleted property has been set to true, it can’t be directly changed to false.
You must use the undo concept provided by CSLA .NET to revert the object graph to a previous
state in order to “undelete” an object.
The reason for this requirement is that when a child object is marked for deletion the parent
object is usually also affected. For example, removing a child object from a BusinessListBase
collection not only causes the child’s IsDeleted property to be true, but it causes the parent
collection to move the child out of the active collection and into to a DeletedList collection object.
To undelete the child, the object must be moved back into the active collection, and its IsDeleted
property must be set to false.
The undo behavior will automatically ensure that both the parent and child objects are reverted
to an earlier state prior to the deletion of the child object.
IsSavable Property
The IsSavable property exists on all editable objects, and it indicates whether the object is in a
state where it can be saved (inserted, updated or deleted in the data store). The IsSavable
property is a combination of several other properties and exists as a convenience.
An object is considered savable if:
The primary purpose of this property is to allow a UI developer to easily determine whether the
object can be saved so appropriate buttons, links and menu items can be enabled and disabled as
appropriate.
Using CSLA 4: Creating Business Objects Page 41
Rev 1.1
MarkDeleted and Delete Methods
The MarkDeleted method is a protected method of BusinessBase, and you can call this method to
mark an object for deletion. This method sets the IsDeleted property to true. You should not
normally need to directly call MarkDeleted, because it is invoked automatically in almost all cases.
There is a Delete method as well, and it is public in scope. This method calls MarkDeleted, but it
only operates on editable root objects. By default, calling Delete on an editable child object will
cause an exception to be thrown. The Delete method exists to help support the use of deferred
deletion of editable root objects.
The reason Delete isn’t available on child objects, is that child objects should be deleted through
their parent. Typically child objects are contained in collections (a subclass of BusinessListBase),
and they are “deleted” by calling one of the remove methods on the collection. When an object is
“removed” from a BusinessListBase or BusinessBindingListBase collection, it is marked for
deletion and is moved to a DeletedList, so when the object graph is saved the underlying data can
be deleted from the database. This is all automatic and you don’t need to do anything for this to
occur.
The Delete method is virtual, so if you need to customize the rules around marking editable
root objects for deletion, you can override the existing behavior.
Once an object is marked for deletion there is no “undelete” concept. If you need to “undelete”
an object, you chould call CancelEdit on that object, or its parent object, thus causing the
IsDeleted property value to be restored to its previous state.
MarkNew Method
The MarkNew method is a protected method of BusinessBase, and you can call this method to mark
an object as being new. You should not normally need to directly call MarkNew, because it is invoked
automatically in most cases.
This method sets the IsNew property to true, the IsDeleted property to false and calls the
MarkDirty method (which I’ll discuss later).
The MarkNew method is virtual so you can override its behavior. The most common reason for
overriding MarkNew is to change whether a new object is considered to have been changed or not.
By default, when MarkNew is called it invokes MarkDirty. This means all new objects are also
considered to have changed. Sometimes people prefer that new objects not be considered to have
changed, and so they override MarkNew as follows:
protected override void MarkNew()
{
base.MarkNew();
MarkClean();
}
The result of this change is that new objects are considered to be new (IsNew is true), but they
are considered to have no changes (IsSelfDirty is false).
MarkOld Method
The MarkOld method is a protected method of BusinessBase, and you can call this method to mark
an object as being old (not new). An “old” object is an object where there’s a reasonable
Using CSLA 4: Creating Business Objects Page 42
Rev 1.1
expectation that the object’s data corresponds to data in the database or data store. In most cases
this means that the primary key value of the object directly corresponds to a row with that primary
key in the database.
The MarkOld method sets IsNew to false and calls MarkClean (which I’ll discuss later). Normally
this method is called automatically by CSLA .NET when an object is inserted or updated into the
database, at which point there is clearly a reasonable expectation that the data in the object
corresponds directly to a set of data in the database.
This method is virtual, so you can override its behavior.
Change Tracking
Editable business objects keep track of whether their state has been changed. An object is
considered “dirty” if any of its properties have been changed.
For performance and memory optimization reasons, CSLA .NET uses a fairly simplistic
mechanism to track whether an object has been changed. If a property value is changed, the object
is considered to have been changed. Even if the property is changed back to its orginal value, the
object is still considered to have been changed.
If you need finer grained information over whether the object has been changed, it is possible
(with some work) to override the way CSLA .NET tracks that whether objects and properties have
been changed. The technique involved is covered by Jason Bock in this blog post:
http://www.jasonbock.net/JB/Default.aspx?blog=entry.9cc70d85bef34e2b9a683ba82615f8a3
IsDirty Property
The IsDirty property is true if the object, or any of its child objects, have been changed. The data
portal uses this property to avoid trying to save objects that haven’t been changed, and you can use
this property to detect whether the object graph has changes as well.
This property is virtual, so you can override its behavior to implement more complex change
tracking mechanisms, though in most cases you should look at overriding the IsSelfDirty property
instead.
IsSelfDirty Property
The IsSelfDirty property returns true if the object’s state has been changed. This includes
changes to the object’s properties, as well as some metastate. For example, calling MarkDeleted will
cause IsSelfDirty to return true, because that represents a change to the object’s state.
When any property in the object is changed, a Boolean flag is set to true. By default, the
IsSelfDirty property returns the value of that flag. This is a very low-impact implementation of
change tracking that provides high performance and little memory consumption.
This property is virtual, so you can override its behavior to implement more complex change
tracking mechanisms. For example, if you replace the way field values are managed as described in
Jason Bock’s blog post, you can override IsSelfDirty to determine whether the object has been
changed by finding out whether any specific properties of the object have been changed.
Using CSLA 4: Creating Business Objects Page 43
Rev 1.1
MarkClean Method
The MarkClean method is a protected method on BusinessBase. Normally you don’t have to call
this method directly, as it is invoked automatically by CSLA .NET. This method sets the internal
Boolean change tracking flag to false, indicating that the object has no changes.
The MarkClean method also tells the field manager to mark every property as being unchanged.
By default this has no impact, but if you’ve replaced the default field management types with more
complex types you can use this information to update your internal field storage values.
Finally, the method calls OnUnknownPropertyChanged, which raises the PropertyChanged event
with a property name of string.Empty. This tells data binding to refresh the bindings on all the
properties of the object, ensuring that the UI is up to date based on any changes that were
committed to the object’s state or metastate.
PropertyHasChanged Method
The PropertyHasChanged method is a protected method on BusinessBase that is invoked when
individual property values of a business object are changed. You don’t normally need to invoke this
method, as it is invoked automatically by CSLA .NET when property values change.
This method calls the MarkDirty method (discussed later), and raises the PropertyChanged
event as appropriate based on the value of Csla.ApplicationContext.PropertyChangedMode . The
default mode is Xaml, which means the PropertyChanged event is raised in a way that is compatible
with all UI technologies, including WPF, Silverlight, WP7 and Windows Forms. Please note that it is
not optimized for Windows Forms and the default will cause a lot of extra UI refresh activity. So if
you are building a Windows Forms application you should change the mode to Windows to optimize
for that environment.
Be aware that setting the PropertyChangedMode to Windows will cause WPF data
binding to work incorrectly.
If you do set the PropertyChangedMode, remember it is a global setting that affects the way the
PropertyChanged event is raised by all editable objects in your application.
MarkDirty Method
The MarkDirty method is a protected method on BusinessBase. You don’t normally have to call
this method directly, as it is invoked automatically by CSLA .NET (typically from the
PropertyHasChanged method). This method sets the internal Boolean change tracking flag to true,
indicating that the object has been changed.
By default this method not only effectively sets IsSelfDirty to true, it also raises the
PropertyChanged event with a property name of string.Empty. This tells data binding to refresh
the bindings on all the properties of the object, ensuring that the UI is up to date based on any
changes that were committed to the object’s state or metastate.
It is also possible to call a MarkDirty overload that accepts a Boolean value indicating that the
method should suppress the raising of the PropertyChanged event. In this case the method marks
the object as having been changed.
IsValid Property
The IsValid property returns true if the current object and all its child objects are valid. If the
current object or any of its child objects have any broken validation rules then IsValid will return
false.
This property is virtual so you can customize its behavior if required. This would be an
advanced scenario where you’ve decided to create your own validation mechanism or something of
that sort.
IsSelfValid Property
The IsSelfValid property returns true if the current object has no broken validation rules. The
state of child objects is ignored by this property. You can use this property to determine the validity
of a specific object rather than an object and its children.
This property is also virtual so you can customize its behavior if required. This would be an
advanced scenario where you’ve decided to create your own validation mechanism or something of
that sort.
Busy Tracking
A “busy” object is an object that is executing an asynchronous operation. Examples of asynchronous
operations include:
Asynchronous business and validation rules are managed at the property level. This means a
specific property is busy, as well as the business object. Another way to say this, is that a business
object is busy if it is busy, or if any of its properties are busy.
A busy object can’t be saved. This is because the results of the asynchronous operation won’t be
known until that operation completes, so the object is in an indeterminate state while any async
operation is executing.
IsBusy Property
The IsBusy property returns true if the object or any child object is executing an async operation.
This property allows you to easily determine of an object graph has any async operations running,
so you can do things like disable UI elements or show a busy animation as appropriate.
Using CSLA 4: Creating Business Objects Page 45
Rev 1.1
This property is virtual so you can override its behavior. You shouldn’t normally need to
override the IsBusy property, because even if you customize the way async operations work in your
objects, you’d normally override the IsSelfBusy property.
IsSelfBusy Property
The IsSelfBusy property returns true if the object or any of its properties are executing async
operations. The state of child objects is ignored by this property. Again, you can use this property to
enable busy animations or disable parts of the UI as appropriate.
This property is virtual so you can override its behavior. You may choose to do this if your
object has alternate ways of becoming busy. If you implement new ways to execute async
operations beyond the ones I’ve listed in this chapter, you would override the IsSelfBusy property
so you can include your async operations as part of the object’s busy status.
IsPropertyBusy Method
The IsPropertyBusy method can be used to determine if a specific property is busy. A property is
busy if one or more async business or validation rules attached to the property are currently
executing.
BusyChanged Event
The IsBusy property can change for several reasons:
The BusyChanged event is raised when the busy status of the object or a property on the object
changes, and includes a BusyChangedEventArgs parameter that contains information about the
change.
The BusyChangedEventArgs type includes a Busy property and a PropertyName property.
When a property of the object becomes busy or idle, the BusyChanged event is raised to indicate
the change for that specific property. In that case the PropertyName property contains the name of
the affected property.
When the object or a child of the object becomes busy or idle, the BusyChanged event is raised
and the PropertyName property of the event args parameter is string.Empty. An empty
PropertyName value indicates that the state of the object itself has changed, not only the state of a
specific property.
MarkBusy Method
If you want to directly mark the object as busy you can call the MarkBusy method. This is a
protected method available in BusinessBase and ReadOnlyBase. Normally MarkBusy is invoked
automatically, and you don’t need to call this method.
Using CSLA 4: Creating Business Objects Page 46
Rev 1.1
It is important to understand that calling MarkBusy has no effect on whether there are async
operations running for specific properties, this method only impacts the object’s busy status.
An object is only allowed to become busy if it is idle. Calling MarkBusy when the object is already
busy will result in an exception.
Calling MarkBusy marks the object as busy and raises the BusyChanged event.
MarkIdle Method
If you want to directly mark the object as idle you can call the MarkIdle method. This method marks
the object as idle and raises the BusyChanged event. It is important to understand that calling
MarkIdle has no effect on whether there are async operations running for specific properties, this
method only impacts the object’s busy status.
You should not normally need to call the MarkIdle method, because it is called automatically as
appropriate. You should only call MarkIdle if it was your code that explicitly called MarkBusy to
make the object appear busy.
At this point, you should have an understanding of the basic concepts surrounding business
domain objects created using CSLA .NET. These concepts include support for various object
relationships, property and method declarations and metastate management.
Next, I’ll discuss the basic solution structures typically used when creating applications using
CSLA .NET. Then I’ll cover the different object stereotypes supported by the CSLA .NET base classes.
Finally, I’ll cover business rules.
Table 12. Common project types and related CSLA assembly references
Taking some care to reference the correct assemblies and assembly builds when setting up each
project can save you a lot of headaches when you start trying to build and run your solution code.
While it is possible to combine all the code into a single project, I recommend using
this type of multi-project solution to help reinforce the concept of the logical layers
within your application’s architecture. Even most highly skilled and disciplined
developers have a very difficult time maintaining clear layer boundaries without
using this technique.
In an n-tier physical deployment, you’ll have at least one server between the client and
database. For example, Table 14 shows a 4-tier Silverlight solution.
This is the consistent theme you should look for in any CSLA .NET solution. In general terms,
there should always be a presentation project, a business layer project and a data access project.
Other projects may exist to provide specialized functions such as hosting the data portal, or
providing more flexible data access layers (as discussed in the Using CSLA 4: Data Access ebook).
But the overall pattern should remain consistent.
Figure 4. Setting the assembly and namespace names in a Windows Phone project
By setting the assembly and default namespace values to be the same in all the projects, you are
ensuring that when the solution is built that you’ll end up with compiled Library.dll files, built for
.NET, Silverlight, and WP7 respectively. And you help ensure that all the classes in both assemblies
share the same namespace.
The whole idea here is that the exact same class code gets compiled for .NET, Silverlight, and
WP7. The only difference is the platform for which the code is compiled, not the code itself.
Linking Files
Once the projects have been set up and their assembly and namespace names changed to be
consistent you can start adding code files to one of the projects. I recommend putting all the code
files into one of the projects and linking the files into the other projects to keep things as simple as
possible.
As an example, Figure 5 shows the .NET project containing code files.
Editable Objects
Editable objects can be created, retrieved, updated, and deleted from the database. These objects
typically contain public read-write properties or child objects, and business rules to support
business, validation, and authorization behaviors for these properties and objects.
A parent object’s IsChild property is false, while a child will return true. This property affects
how the object is persisted by the data portal, and is an important distinction I’ll discuss further in
the Using CSLA 4: Data Access ebook.
For the purposes of this ebook, you can consider that editable root and child objects share the
same basic class structure.
[Serializable]
public class EditableRoot : BusinessBase<EditableRoot>
{
public static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(p => p.Name);
public string Name
{
get { return GetProperty(NameProperty); }
set { SetProperty(NameProperty, value); }
}
protected override void AddBusinessRules()
{
// TODO: add validation rules
base.AddBusinessRules();
//BusinessRules.AddRule(new Rule(NameProperty));
}
#if !SILVERLIGHT
public static EditableRoot NewEditableRoot()
{
return DataPortal.Create<EditableRoot>();
}
Because this is the first stereotype I’m covering, I’ll walk through this code in some detail.
First, notice that the class is marked with the Serializable attribute:
[Serializable]
The T type parameter must always be the type of the business class you are creating. This is
because the BusinessBase class needs to have access to this type value for implementation of
strongly-typed property declarations, object cloning and object persistence.
Your class will define its own properties. The one shown here is just an example:
public static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(p => p.Name);
public string Name
{
get { return GetProperty(NameProperty); }
set { SetProperty(NameProperty, value); }
}
Next notice the override of the AddBusinessRules method. I’ll discuss this method in more
detail in Chapter 4. For now, you should understand that this is the method you need to override to
attach custom business, validation and authorization rules to the properties of your business class.
protected override void AddBusinessRules()
{
// TODO: add validation rules
base.AddBusinessRules();
//BusinessRules.AddRule(new Rule(NameProperty));
}
If you override this method, it is important to call the base implementation because that is
where the DataAnnotations validation attributes are integrated into the CSLA 4 business rules
subsystem.
The next bit of code is an implementation of the AddObjectAuthorizationRules method:
public static void AddObjectAuthorizationRules()
{
// TODO: add authorization rules
//BusinessRules.AddRule(...);
}
This is a static method where you can write code to register authorization rules with your
business class at the type level. I’ll discuss per-type authorization rules in Chapter 4. For now you
should understand that these rules allow you to control which users are allowed to create, retrieve,
update and delete instances of this business type.
For editable child objects this is all the code that is relevant. The remaining code implements the
public factory methods and is found in root objects only. Child types don’t have public factory
methods.
These factory methods call the data portal, which I’ll cover in detail in the Using CSLA 4: Data
Access ebook. You can think of each data portal call as a potential call to an application server,
where the business object will be persisted by your application’s data access layer.
The first set of factory methods are wrapped in a compiler directive that prevents them from
being compiled for Silverlight (or WP7). This is required because these are synchronous methods,
and Silverlight doesn’t support synchronous calls to an application server.
#if !SILVERLIGHT
public static EditableRoot NewEditableRoot()
These factory methods are pretty straightforward. They are static methods that perform
create, retrieve or delete operations for this business type. They rely on the data portal to do all the
work. The factory methods are an abstraction to make it easy for UI code to interact with your
business type. For example, if someone wants to retrieve a specific EditableRoot object, code like
this will do the job:
var obj = EditableRoot.GetEditableRoot(123);
This level of abstraction is very important, because the calling code doesn’t know how the object
was created or loaded with data.
The remaining factory methods are asynchronous, and so can be used on .NET, Silverlight or
WP7.
public static void NewEditableRoot(EventHandler<DataPortalResult<EditableRoot>> callback)
{
DataPortal.BeginCreate<EditableRoot>(callback);
}
These factory methods do the same thing: create, retrieve or delete the business class. But they
are asynchronous, and so return no value directly. Instead, any values they return become available
when the asynchronous operation completes, at which time the callback parameter is invoked.
This callback parameter is the address of a method you supply, so it is your method that is invoked
when the operation is complete.
Typical calling code would look like this:
EditableRoot.GetEditableRoot(123, (o, e) =>
{
if (e.Error != null)
throw e.Error;
else
_editableRoot = e.Object;
});
An editable list is, by definition, a parent object because the whole idea of a collection is to
contain other objects. The difference between an editable root and child list, is that an editable root
list can be directly persisted through the data portal, while a child list is persisted as part of its
parent.
Changes made to child objects contained in an editable list are made in memory, and are only
persisted to the database when the object graph is persisted through the data portal. The user can
change many child objects, and they’ll be saved to the database as a batch, not one at a time.
[Serializable]
public class EditableRootList :
BusinessListBase<EditableRootList, EditableChild>
{
public static void AddObjectAuthorizationRules()
{
// TODO: add authorization rules
//AuthorizationRules.AllowGet(typeof(EditableRootList), "Role");
}
#if !SILVERLIGHT
public static EditableRootList NewEditableRootList()
{
return DataPortal.Create<EditableRootList>();
}
The AddChild method itself would still use a Unit of Work object to create the child object, but it
can encapsulate that effort, and can also hide the details of synchronous vs asynchronous
implementations. A synchronous AddChild method would look like this:
public void AddChild()
{
Add(EditableChildCreator.CreateChild());
}
The calling code can rely on the collection’s CollectionChanged event to know when the async
operation is complete and the new object has been added to the collection.
The advantage of the AddChild method technique is that you encapsulate the details of creating
and adding the child object within the collection class itself. Also, your AddChild method can accept
parameters that might be required to initialize the new child object.
Implementing AddNew
The final technique you can use is the standard AddNew method on editable list objects. This is very
similar to the idea of implementing your own AddChild method, except that you can’t pass
parameter values to the AddNew method.
The benefit of using the AddNew method is that this technique integrates with data binding and
many datagrid controls (in smart client UI technologies) so when the user moves to the bottom row
of a datagrid control a new object is automatically created and added to the collection (and thus the
datagrid).
Although the implementiation of the AddNew is different between .NET and Silverlight, you do
need to set the AllowNew property to true in your collection’s constructor in both platforms:
AllowNew = true;
Setting this property to true tells the runtime that you have implemented the behaviors
necessary for AddNew to work.
Again, I’m using a Unit of Work object to create and initialize a new child object. That child
object is then added to the collection, and is returned as a result of the method.
The code is a little different in Silverlight and WP7, where the implementation is asynchronous.
protected override void AddNewCore()
{
EditableChildCreator.CreateChild((o, e) =>
{
if (e.Error != null)
{
throw e.Error;
}
else
{
Add(e.Object);
OnAddedNew(e.Object);
}
});
}
Because the operation is async, AddNewCore is a void method. Once the new child is created, this
method must call the OnAddedNew method to indicate that the new child has been added to the
collection.
This will cause the data portal to directly create an instance of the child object without any
attempt at talking to an application server.
Similarly, you can do the same thing on Silverlight:
protected override void AddNewCore()
{
var child = DataPortal.CreateChild<EditableChild>();
Add(child);
OnAddedNew(child);
}
The data portal’s CreateChild method is synchronous, so this converts the Silverlight
implementation into what is effectively a synchronous operation. Notice, that OnAddedNew is still
invoked, because that closes the loop to tell the collection and runtime that the add operation is
complete.
The default .NET and Silverlight implementations of AddNew use the data portal’s CreateChild
method that I’ve shown here.
The editable list stereotype enables batch updates of changes to a list of child objects, along with
authorization rules at the type level.
As the user edits and leaves each row in the datagrid control, they are effectively concluding the
edit of a root object in the list, so the dynamic root list collection automatically saves the changes to
that object. This occurs automatically and immediately as the user leaves the row in the datagrid
control.
Dynamic Root
A normal editable root object has public factory methods allowing the UI to directly retrieve
instances of the business type. A dynamic root is an editable root designed to be contained within a
dynamic root list, and so responsibility for retrieving each object belongs to the collection.
In most cases this means that a dynamic root object is a normal editable root object without a
public factory method for retrieving (getting) an instance of the type. This also impacts the
implementation of the data access code for fetching the object, because that code will now be
invoked by the “parent” collection instead of directly by the data portal. I’ll get into more details in
the Using CSLA 4: Data Access ebook.
Otherwise, a dynamic root is like an editable root. It will have the same properties, business
rules, factory method for creating the object and so forth.
public DynamicRootList()
{
AllowNew = true;
}
#if SILVERLIGHT
protected override void AddNewCore()
{
DynamicRoot.NewDynamicRoot((o, e) =>
{
if (e.Error != null)
{
#if !SILVERLIGHT
public static DynamicRootList NewDynamicRootList()
{
return DataPortal.Create<DynamicRootList>();
}
As with the other editable types I’ve discussed, this one implements the
AddObjectAuthorizationRules method where you can associate authorization rules to specify the
users that are allowed to create, get, and save this collection.
This class has a constructor that sets AllowNew to true, because the code overrides AddNewCore
to implement the AddNew behavior. While this is optional, you will usually implement the AddNew
behavior so the user can automatically add new items to the datagrid by moving to the last row in
the display.
The concept of overriding AddNewCore is the same as I discussed earlier for the editable list
stereotype. The implementation is different for .NET and Silverlight because the Silverlight
implementation must be asynchronous.
And as with the other root object stereotypes, the dynamic root list implements public factory
methods to allow creation or retrieval of the collection. The synchronous factory methods are
wrapped in a compiler directive so they only build for .NET, while the asynchronous factory
methods are available to .NET, Silverlight, and WP7 code.
Read-Only Objects
Read-only object stereotypes support the idea that there are many objects that contain read-only
data. These include objects with read-only properties, and collections that don’t allow adding or
removing of items. Read-only objects are generally “lighter weight” than editable objects, because
they don’t need to support concepts like validation rules or change notification for data binding.
Read-only objects don’t track the IsChild metastate value, or most other metastate values.
Because a read-only object only supports read-only properties or child objects, there’s no need to
track whether the object is new, marked for deletion, is valid, or has been changed. None of these
concepts make sense for a read-only object.
#if !SILVERLIGHT
public static ReadOnlyRoot GetReadOnlyRoot(int id)
{
return DataPortal.Fetch<ReadOnlyRoot>(id);
}
#endif
The base class that supports the read-only object stereotype is ReadOnlyBase<T>. Notice that
this type is serializable and that it inherits from the appropriate base class.
You can use any of the read-only property implementations I discussed earlier in the chapter. It
is important to understand that the SetProperty and SetPropertyConvert helper methods do not
exist in ReadOnlyBase, because those only make sense for read-write properties.
The GetProperty method exists, because it applies authorization rules as the user attempts to
read the property.
The AddBusinessRules and AddObjectAuthorizationRules methods are similar to those you’d
find in an editable object, except that the only rules enforced in a read-only object are authorization
rules dealing with reading properties and getting an instance of the business type. There is no
concept of business rules, validation rules, or authorization rules covering writing to a property or
saving the object.
It makes no sense to create a “new” read-only object, because that would create an object that
has no data in its read-only properties. It does make sense to retrieve a read-only object, so that
you can see the factory methods (synchronous and asynchronous) which use the data portal to
fetch an instance of the read-only type:
#if !SILVERLIGHT
public static ReadOnlyRoot GetReadOnlyRoot(int id)
{
return DataPortal.Fetch<ReadOnlyRoot>(id);
}
#endif
Only a read-only root will have these factory methods. A read-only child will be retrieved as part
of its parent.
The read-only object stereotype is very valuable, because most applications have a lot of
information that needs to be retrieved for display. This stereotype supports that requirement, with
authorization rules and data portal integration.
#if !SILVERLIGHT
public static ReadOnlyList GetReadOnlyList(string filter)
{
return DataPortal.Fetch<ReadOnlyList>(filter);
}
#endif
The base class that supports the read-only list stereotype is ReadOnlyListBase<T,C>. The only
type of business rules available in a read-only list are per-type authorization rules that are set up by
implementing the AddObjectAuthorizationRules method. As you might expect, the only
meaningful authorization rule deals with the retrieval of the list object.
The remaining code applies to root objects only, and illustrates the basic factory method
structure you’ve seen in previous stereotypes. Again you see the synchronous .NET-only factory and
the asynchronous factory that applies to all platforms.
Name-Value List
In many older applications one of the most common requirements for a read-only list was to
retrieve a simple name-value pair for use in populating a listbox or combobox control in the UI. This
requirement was so common that I defined the NameValueListBase<K,V> base class to support a
name-value list stereotype.
The name-value list stereotype is an example of a read-only list, but with a pre-built read-only
child object type that only contains a key and a value.
This stereotype is sometimes still useful, but I find that most XAML-based applications require
richer information than a name-value pair for populating their listbox and combobox controls. The
fact that modern UI technologies allow the display of more than a single string value means that
the name-value list stereotype has become less useful over time.
You should feel free to use the NameValueListBase base class if it fits into your application’s
requirements. If you need something more than name-value pairs then you should create a read-
only list with richer read-only child objects.
The most interesting part of the following code is probably the implementation of a simple
client-side cache using a static field. This is entirely optional, but is pretty common for name-value
lists because they often contain data that doesn’t change while the application is running:
[Serializable]
public class NameValueList : NameValueListBase<int, string>
{
private static NameValueList _list;
#if !SILVERLIGHT
public static NameValueList GetNameValueList()
{
if (_list == null)
_list = DataPortal.Fetch<NameValueList>();
return _list;
}
#endif
The class declaration uses the NameValueListBase base class, providing it with the types of the
key and value for the child objects in the list:
public class NameValueList : NameValueListBase<int, string>
In this example the key is of type int and the value is of type string.
The next bit of code implements a simple static field as a cache for the list:
private static NameValueList _list;
There’s also a method to clear the cache, which can be useful if the application does need to
force the cache to be reloaded with data from the server.
The factory methods are very similar to those you’ve seen, except that they check the static
cache field and return that value if it exists. The data portal is only invoked if there is no pre-existing
cached value.
You can use this same static field cache technique with read-only object and read-only list
objects as well.
The read-only stereotypes are widely used in most applications, because it is extremely common
to display read-only data to a user. In contrast, if your object requires a read-write property, or your
collection must support adding or removing of items, then you should use the editable object
stereotypes.
Command
Unit of Work
Command
The command object stereotype supports a specific sequence of code execution as listed in Table
15.
Step Description
Create object The command object is created by the calling code, typically on
the client workstation.
Initialize object The command object is initialized by the calling code, either
through its constructor or by explicitly setting properties on the
object.
Client execution The command object can run any code that needs to run on the
client before interacting with the server.
Server execution The command object is executed by the data portal, which means
any server-side code is executed after the data portal has moved
the object to the application server.
Client execution The command object comes back from the server through the
data portal, and it can run any code that needs to run on the
client after the server interaction.
Calling code reacts The calling code can interact with the command object once its
execution is complete, often reading property values as results
The code starts out with static factory methods that make it easy to invoke the command
synchronously and asynchronously. These factory methods follow the sequence of steps from Table
15, calling methods that are stubbed out for illustration purposes.
The only helper methods provided by CommandBase are ReadProperty and LoadProperty.
Command objects have no inherent business rule concept, nor do they support data binding, so the
other helper methods have no meaning.
You can implement any properties that are required by your business requirements. Property
values automatically flow from the client to the server and back to the client through the data
portal as the object moves to and from the application server. This ensures that both client-side and
server-side code have access to the same set of properties.
Unit of Work
The unit of work (UOW) stereotype has always been important, but its use has become more
widespread with the increasing popularity of asynchronous server access techniques.
This is because it is very common for a UI to require several objects be present in memory on the
client before a page, form, or window can be fully rendered or data bound. If you asynchronously
request each of these objects you can’t predict the order in which they’ll be returned to the client,
and writing code to hold off rendering the UI until all the objects are available isn’t easy.
A simpler solution is to make a single request to the server for all the objects required by the UI.
This makes retrieval of several different objects into a single unit of work.
Another somewhat less common scenario, is where more than one object needs to be saved at
the same time, as part of the same logical operation. Perhaps the application allows the user to
enter information about a customer and sales order on the same screen. When the user clicks the
Save button both the CustomerEdit and SalesOrderEdit objects must be saved at the same time. If
either fails, both must fail.
Again, a simple solution to this requirement is to make a single call to the server that combines
the save operations of both objects into a single unit of work.
Data Retrieval
Data retrieval can be described as combining what would have been several object fetch requests
into a single request. The individual objects being requested might be of almost any stereotype
[Serializable]
public class CustomerEditRetriever : ReadOnlyBase<CustomerEditRetriever>
{
public static PropertyInfo<CustomerEdit> CustomerEditProperty =
RegisterProperty<CustomerEdit>(c => c.CustomerEdit);
public CustomerEdit CustomerEdit
{
get { return GetProperty(CustomerEditProperty); }
private set { LoadProperty(CustomerEditProperty, value); }
}
#if !SILVERLIGHT
public static CustomerEditRetriever GetCustomerEditRetriever(int customerId)
{
return DataPortal.Fetch<CustomerEditRetriever>(customerId);
}
#endif
This UOW class defines two read-only properties; one for each of the objects it will be retrieving.
It implements synchronous and asynchronous factory methods to call the data portal to do the
retrieval. When this object is returned by the data portal, those two properties will contain
references to the objects that were requested.
Although I’ll go into more detail about the data access aspects of this process in the Using CSLA
4: Data Access ebook, here’s one example of how the server-side code might be implemented. This
DataPortal_Fetch method would be included in the CustomerEditRetriever class:
#if !SILVERLIGHT
private void DataPortal_Fetch(int customerId)
{
CustomerEdit = CustomerEdit.GetCustomer(customerId);
SalesRegionList = SalesRegionList.GetList();
}
#endif
I am assuming that the CustomerEdit and SalesRegionList classes are normal root editable and
read-only list objects, and so they have factory methods. The “data access” code in the UOW class
needs to use those factory methods to retrieve the two objects so they can be returned to the
calling code.
Using CSLA 4: Creating Business Objects Page 73
Rev 1.1
This technique is something you should consider any time you need to retrieve multiple objects,
and where the calling code needs to have access to all those objects before it can proceed to use
them.
Data Update
The data update UOW stereotype is slightly different, because any save operation is a “round trip”.
The object starts on the client, and the save operation moves it to the application server so the
object’s state can be saved into the database by the data access layer. Then the object is returned
to the client, because you must assume the object was changed during the save operation.
For example, insert operations typically create new primary key or id values for the object.
Update operations typically create new timestamp values for the object. Delete operations convert
the object from being an existing (old) object into being a new object.
The CommandBase base class is designed to move from client to server and back to the client,
carrying any property values with the object. So it is the perfect base class for building a data
update UOW:
[Serializable]
public class DataUpdateUow : CommandBase<DataUpdateUow>
{
public static PropertyInfo<CustomerEdit> CustomerEditProperty =
RegisterProperty<CustomerEdit>(c => c.CustomerEdit);
public CustomerEdit CustomerEdit
{
get { return ReadProperty(CustomerEditProperty); }
private set { LoadProperty(CustomerEditProperty, value); }
}
#if !SILVERLIGHT
public static DataUpdateUow Update(CustomerEdit customer, SalesOrderEdit order)
{
var cmd = new DataUpdateUow { CustomerEdit = customer, SalesOrderEdit = order };
cmd = DataPortal.Execute<DataUpdateUow>(cmd);
return cmd;
}
#endif
First, you should notice the CustomerEdit and SalesOrderEdit properties. These properties
contain the business objects that are to be updated. Those objects will be serialized from the client
to the server along with the DataUpdateUow object, and they’ll come back from the server through
the data portal as well.
One possible implementation of the server-side code you might write in DataUpdateUow is this:
Using CSLA 4: Creating Business Objects Page 74
Rev 1.1
#if !SILVERLIGHT
[Transactional(TransactionalTypes.TransactionScope)]
private void DataPortal_Execute()
{
CustomerEdit = CustomerEdit.Save();
SalesOrderEdit = SalesOrderEdit.Save();
}
#endif
Both business objects are carried to the application server by the UOW object, which then saves
them within a single transactional context. The resulting business objects are then returned to the
client, so the calling code can make use of any new database-generated id values, timestamp
values, or other new values.
Notice how the factory methods in the UOW class return the UOW object as a result, which is
how the calling code gains access to the resulting properties or results.
The unit of work pattern is a powerful one, and can be used for retrieving or updating data as
I’ve shown here, or for any other scenario where you need do perform more than one operation as
a logical unit of work.
Criteria Objects
When you create a factory method to fetch a root object the factory method typically calls the
Fetch or BeginFetch method of the data portal. This method takes zero or one parameter, which is
the criteria used on the server to find the right information to create and populate the root object
being requested. The same is true for the data portal’s Create, BeginCreate, Delete, and
BeginDelete methods.
That single parameter value is the criteria value used to identify the root object. Criteria values
can be any serializable type. If you are building a pure .NET application this means any value that
can be serialized with the BinaryFormatter or NDCS. If your code will run on Silverlight or WP7 this
means any value that can be serialized with the MobileFormatter.
Generally this means any primitive value type (such as int or double), and some special
reference types like string. It also means any class you’ve created that is serializable.
Simple Criteria
Simple criteria values include:
Most business objects use simple primary keys of type int or Guid, which means most of your
data portal calls can pass the simple id or key value as the criteria value.
Using CriteriaBase
The CriteriaBase base class is designed to make it easy to create complex criteria types that are
serializable in .NET, Silverlight and WP7. This base class only supports the ReadProperty and
LoadProperty helpers for property implementation, and has no support for business rules,
authorization or data binding.
Here’s an example of a criteria class containing two values:
[Serializable]
public class CustomerCriteria : CriteriaBase<CustomerCriteria>
{
public static PropertyInfo<int> RegionIdProperty = RegisterProperty<int>(c => c.RegionId);
public int RegionId
{
get { return ReadProperty(RegionIdProperty); }
private set { LoadProperty(RegionIdProperty, value); }
}
You would use these criteria in a factory method. For example, the following might be a factory
method for a CustomerEdit editable root:
public static CustomerEdit GetCustomerEdit(int regionId, int customerId)
{
var criteria = new CustomerCriteria(regionId, customerId);
return DataPortal.Fetch<CustomerEdit>(criteria);
}
Notice how the criteria class is used within the factory, so the code calling the factory doesn’t
have to worry about those details. The calling code provides strongly typed parameter values and
gets back the result.
The value provided by CriteriaBase is that it includes the field manager so you can implement
properties as shown in this example, following the same basic structure as with any other business
type.
The only real difference is in the property implementations, which are now standard read-write
properties. I’ve also removed the constructor, because the idea is that these property values will be
set by the user through data binding.
Whether you use CriteriaBase or BusinessBase, the central point I’m making is that if your
criteria consists of multiple values, you need to create a serializable type to contain those values.
LINQ Types
CSLA 4 collection objects automatically work with LINQ to Objects, like any IEnumerable<T> in the
.NET framework.
The one problem with LINQ to Objects queries is that they return an IEnumerable<T>, which is
the most basic collection type in the .NET framework. This means that if you perform a query with
an identity projection (a query that returns the child objects from a collection) the result is a much
more primitive collection type than the one you had originally.
For example, suppose you have a CustomerInfoList read-only list, and you want to sort that list:
var sorted = from r in _customerList
orderby r.Name
select r;
The original _customerList field is a CustomerInfoList, which fully supports data binding and
provides all the other services and features of a ReadOnlyListBase object. The query result, the
sorted field, is a simple IEnumerable<T> and doesn’t support data binding or any of the features of
a read-only list.
Using CSLA 4: Creating Business Objects Page 77
Rev 1.1
This is even more confusing if you start with an editable list object. In that case, your query will
also return a simple IEnumerable<T> that doesn’t support data binding. But worse, if you add or
remove items from the query result they are not added or removed from the original list. It is that
original list that will be saved through the data portal!
Sometimes these issues aren’t a problem. Sometimes you need a sorted or filtered version of the
original list and you won’t bind it to a UI or otherwise manipulate the result of the query. But if you
do need to use the result of the query for data binding or manipulation, CSLA 4 includes a solution:
the LinqObservableCollection type.
LinqObservableCollection
The LinqObservableCollection class is an “intelligent wrapper” around a LINQ query result. It
creates a view over the original list based on the query result that supports data binding. Even
better, when you add or remove items from a LinqObservableCollection, those items are
automatically added or removed from the original list.
There are several ways to create a LinqObservableCollection, but the most common
technique is to use the ToSyncList extension method provided by CSLA 4. Alter the previous query
like this:
var sorted = (from r in _customerList
orderby r.Name
select r).ToSyncList(_customerList);
The sorted field is now a LinqObservableCollection that provides a “live view” over the
original collection. You get the same basic result, which is that the original collection has been
sorted, but this result supports data binding, change notification, and when items are added or
removed from the sorted field, they are automatically added or removed from _customerList as
well (assuming _customerList is an editable list).
Another way to create a LinqObservableCollection is to explicitly create the object:
var tmp = from r in _customerList
orderby r.Name
select r;
var sorted = new LinqObservableCollection<CustomerEdit>(_customerList, tmp);
The result of this code is the same as the previous example, I’m explicitly doing by hand what the
ToSyncList extension method did in the previous example. This example probably shows more
clearly that the LinqObservableCollection combines the original source list and the query result
to create a live view of the original list based on the query results.
You can use LinqObservableCollection to filter and sort any ObservableCollection<T>,
including those created with BusinessListBase and ReadOnlyListBase from CSLA .NET.
WP7 ObservableCollection
In CSLA 4 the default collection base types inherit from ObservableCollection, including:
BusinessListBase
ReadOnlyListBase
DynamicListBase
NameValueListBase
BusinessBindingListBase
ReadOnlyBindingListBase
DynamicBindingListBase
It is not ideal that a business layer developer must choose a collection type based on the UI
technology that will be using the collection. Unfortunately, Microsoft’s shift from BindingList to
ObservableCollection leaves us with no realistic alternative.
BusinessBindingListBase
The BusinessBindingListBase type supports the editable list stereotype in exactly the same way
as the BindingListBase class. Other than using a different base class in your business collection
code, your collection code will be the same.
Any code that interacts with a BusinessBindingListBase subclass will find some differences in
terms of supported events and data binding behaviors, because this is ultimately a subclass of
BindingList, which supports Windows Forms data binding.
DynamicBindingListBase
The DynamicBindingListBase type supports the editable list stereotype in exactly the same way as
the DynamicListBase class. Other than using a different base class in your business collection code,
your collection code will be the same.
Any code that interacts with a DynamicBindingListBase subclass will find some differences in
terms of supported events and data binding behaviors, because this is ultimately a subclass of
BindingList, which supports Windows Forms data binding.
ReadOnlyBindingListBase
The ReadOnlyBindingListBase type supports the editable list stereotype in exactly the same way
as the ReadOnlyListBase class. Other than using a different base class in your business collection
code, your collection code will be the same.
Any code that interacts with a ReadOnlyBindingListBase subclass will find some differences in
terms of supported events and data binding behaviors, because this is ultimately a subclass of
BindingList, which supports Windows Forms data binding.
At this point, in the ebook you should understand the stereotypes supported by CSLA 4, along
with the base classes you will use to implement business classes for each stereotype. The code in
your business classes relies on the property implementation, metastate, serialization and other
concepts discussed in Chapters 1 and 2.
I’ll now conclude the ebook by discussing how you can implement and use business rules in
editable objects, and authorization business rules in editable and read-only objects.
Business and validation rules can interact with other business objects if necessary.
For example, you might implement a validation rule that determines whether an object’s id
value already exists in the database. To do this your rule will use a command object to interact with
the server, and if the value exists will probably return a warning or error message to indicate that
the property value already exists.
Another example would be a business rule that uses a read-only object to retrieve some values
from a massive database table, so the rule can use those values as part of its algorithmic processing.
Using CSLA 4: Creating Business Objects Page 83
Rev 1.1
Because rules might use other objects, some rules will be asynchronous. Remember that
Silverlight requires that all server interaction be asynchronous, and so any rule that uses an object
which must execute code on the server must support that asynchronous operation. The way rules
are implemented in CSLA 4 allows you to use the same basic coding structure for synchronous and
asynchronous rules, though there are certain limitations on asynchronous rules to help you avoid all
the potential complexity that comes with asynchrous and parallel processing.
The Required attribute is a standard attribute from the DataAnnotations namespace, and
indicates that this is a required property.
None of the standard DataAnnotations validation attributes are designed to apply to a business
class, but you might create your own validation attributes that are designed for that purpose. In
such a case, you’ll apply the attribute to your class declaration.
These attributes are included in the list of validation rules for the object by CSLA .NET by the
implementation of the AddBusinessRules method found in the BusinessBase class. If you override
AddBusinessRules you should make sure to call the base implementation to ensure validation
attributes are used properly by CSLA .NET.
Using AddBusinessRules
If your rule is a CSLA .NET rule it will implement IBusinessRule or be a subclass of BusinessRule,
both of which are found in the Csla.Rules namespace. I’ll discuss how to create such rules later in
this chapter.
You associate these rules with your properties or business class by overriding the
AddBusinessRule method in your editable root or child business class. For example:
This example adds a Required rule from the Csla.Rules.CommonRules namespace, and
associates the rule with the Name property. Notice the use of the static metadata field
NameProperty.
Also notice that a rule is an object, and this code creates an instance of that rule object. This one
rule instance is shared across all instances of the business type. This code creates a single Required
rule instance, and that instance is reused by every business object created for this specific business
class.
Every rule can have a primary property to which the rule applies or is associated. Rules that
require a primary property should require that property be provided to the rule’s constructor. The
Required rule follows this recommendation, requiring the primary property be specified as the rule
is created.
The example also adds a MyClassRule rule to the business class itself. Notice that the
MyClassRule doesn’t require that a primary property be provided to the constructor, so the rule
isn’t associated with any particular property. This tells CSLA .NET to associate the rule with the
business type itself.
Rule Priorities
By default rules are all added at the same priority and you can’t predict the order in which the rules
will be executed. This isn’t always ideal, because you might need certain rules to run before other
rules.
As you add rules to your properties or business type in your AddBusinessRules override you can
specify priority values for each rule. For example:
protected override void AddBusinessRules()
{
base.AddBusinessRules();
BusinessRules.AddRule(new Csla.Rules.CommonRules.Required(NameProperty) { Priority = 0 });
BusinessRules.AddRule(new ToUpper(NameProperty) { Priority = 1 });
}
In this example I’m associating two rules with the Name property. The Required rule is at priority
0, which is the default. The ToUpper rule is at priority 1, and so it will run after the Required rule.
Priority values are an int, and rules are executed from smallest to largest value, with the default
being 0.
Multiple rules can have the same priority, and by default all rules are at priority 0. Rules within
each priority will run in an indeterminate order. This means you can’t predict the order in which the
rules will be run. If you need to ensure that one rule runs before another rule you should explicitly
set the rule priorities.
Short-Circuiting Rules
Closely related to the idea of rule priority is short-circuiting. The idea here is that you might want to
run your inexpensive rules first, and only run more expensive rules if the inexpensive ones don’t
mark the property as invalid.
For example, a Required rule is quite inexpensive because it only checks to see if a string value
has a non-zero length. But that same property might have a rule that runs code on the application
server to talk to the database to verify the property value. That’s clearly more expensive because it
requires interacting with servers and the database. There’s probably no value in verifying an empty
value against the database, so if the Required rule fails you don’t want to run the more expensive
rule.
By default, CSLA .NET will execute all rules with priority 0 or less (so all rules with negative
priorities and priority 0). Rules at priority 1 and higher will only execute if all validation rules at
priority 0 or smaller pass. If the property has been marked as invalid by the time priority 1 rules
would run, they won’t be executed.
The priority at which automatic short-circuiting starts is controlled by the
ProcessThroughPriority value, and you can change that value in the AddBusinessRules override:
protected override void AddBusinessRules()
{
BusinessRules.ProcessThroughPriority = 5;
base.AddBusinessRules();
}
In this example I’ve changed the value to 5, so in instances of this particular business class rules
at priority 5 or less will always execute, and those at priority 6 and higher will only run if no
validation rule has failed.
One common use of short-circuiting is to prevent rules from executing if the user isn’t even
allowed to write to the property. I’ll discuss authorization rules later in this chapter, but for this
discussion it is enough to understand that it is possible to prevent a user from writing to a property.
The following rule uses the CanWriteProperty method on the Target object to determine
whether the user is authorized to write to the specified property:
public class StopIfNotCanWrite : Csla.Rules.BusinessRule
{
public StopIfNotCanWrite(Csla.Core.IPropertyInfo property)
If the user isn’t authorized, the AddSuccessResult method is invoked, passing a parameter value
of true to trigger explicit short-circuiting. In that case, no more rules will be executed for this
property.
Adding this rule to a property at a priority of -1 will cause it to run before all the rules added at
the default priority of 0 or higher:
protected override void AddBusinessRules()
{
base.AddBusinessRules();
BusinessRules.AddRule(new StopIfNotCanWrite(OrderDateProperty) { Priority = -1 });
}
At this point, you should understand how to associate rules with properties or business classes,
as well as how to control the order of rule execution using priorities and short-circuiting.
Rule Sets
Some applications are designed for use in shared hosting environments. Such an application runs on
a server, and it is used by users who don’t work for the same organization. This model is quite
common in software as a service scenarios, where the application is centrally hosted, but is made
available to numerous unrelated customers.
In such a case it is possible that different customers will have different business rule
requirements. A given business object might have one set of rules for one customer, and a different
set of rules for another customer.
To accommodate this type of situation, CSLA .NET has a concept called rule sets. In my examples
so far, all the calls to the AddRule method in the AddBusinessRules override have added rules to
the default rule set. Because most applications will have only one set of rules, this is a good default
behavior.
If your application has multiple rule sets, you’ll need to specify the rule set before calling the
AddRule method. And you’ll need to add all the rules for each rule set individually. For example:
protected override void AddBusinessRules()
{
base.AddBusinessRules();
While this code is setting the same rules into each rule set, a real application would load only
appropriate rules into each rule set based on your business requirements.
The first two rules are added to the default rule set, because the RuleSet property hasn’t been
specified. Then I change the RuleSet property to “RuleSetA” and add a couple rules to that rule set.
The same is done for “RuleSetB”. Finally the RuleSet property is set to “default” so the application
will use the default rule set.
The RuleSet property controls the rule set used by this specific business object, allowing you to
change the rule set for each specific business object. You will typically do this based on the state of
the business object. For example, business objects created or retrieved for Customer A will use the
rule set for that customer, while business objects created or retrieved for Customer B will use a
different rule set. You’ll normally set the RuleSet property for an object as part of its data access
code when the object is created or retrieved.
Executing Rules
Business and validation rules are associated with either a property or to a business object. Most
rules are associated with properties. These rules only apply to the editable object stereotype, and
so are only available to objects that subclass BusinessBase.
Per-Property Rules
Rules that are associated with properties are automatically executed by the SetProperty and
SetPropertyConvert methods. If you follow the property implementation guidelines from Chapter
1, this means your rules will run automatically as properties are changed.
The LoadProperty and LoadPropertyConvert methods do not execute rules.
It is possible to suppress rules so they aren’t automatically executed by SetProperty or
SetPropertyConvert. I’ll discuss how to suppress rule execution later in this chapter.
If you are using one of the DataPortal_XYZ data access models (covered in the Using CSLA 4:
Data Access ebook) the rules are also automatically invoked when the business object is created.
The base implementation of DataPortal_Create runs all rules associated with all properties and the
business type as the object is created.
Dependent Properties
The SetProperty and SetPropertyConvert methods automatically execute business and validation
rules when a property’s setter is called. It is possible to tell CSLA .NET that a relationship exists
between properties in your object, indicating that some properties are dependent on other
properties. After rules for a property are executed, any rules associated with dependent properties
are also executed.
This CalculateTotal rule requires that three properties be provided in its constructor. Let’s
assume it adds Value1 and Value2 and puts the result in Value3. This means Value3 is affected by
this rule, so when rules are executed for the Value1 property, all the rules for the Value3 property
will also be executed.
You should understand that all rules for the primary property are executed first, in priority order.
Then rules are run for each dependent property, one property at a time. The rules for each
dependent property are also executed in priority order.
Any asynchronous rules for each property are started after all synchronous rules for that
property are complete. Because asynchronous rules are asynchronous, their executions will likely
overlap, and you need to take that into consideration when implementing any asynchronous rules.
CSLA .NET provides a rule designed specifically to set up dependency relationships between
properties. In many cases, dependencies are automatically detected because properties affected by
a rule become dependent properties. But sometimes you’ll want to explicitly designate a
dependency relationship by using the Dependency rule:
protected override void AddBusinessRules()
{
base.AddBusinessRules();
BusinessRules.AddRule(
new Csla.Rules.CommonRules.Dependency(CreditLimitOverrideProperty, ConfirmOverrideProperty));
}
Per-Type Rules
Rules associated with a business type are only automatically executed when you use one of the
DataPortal_XYZ data access models (covered in the Using CSLA 4: Data Access ebook). In this case
the rules are automatically invoked when the business object is created. The base implementation
of DataPortal_Create runs all rules associated with all properties and the business type as the
object is created.
Other than this one scenario, you always need to manually cause the execution of per-type rules
by calling either CheckRules or CheckObjectRules on the BusinessRules object as discussed in the
next section of this chapter.
After loading the object with data from the database, when you don’t trust the data from
the database
When a data portal request from a client arrives at your web or application server and you
want to rerun rules because you are concerned the client intetrigty has been compromised
On a ChildChanged event when a parent object needs to run rules based on changes to a
child object
As I’ve mentioned, the BusinessBase class has a protected property named BusinessRules.
This BusinessRules object includes methods you can use to invoke rules as described in Table 18.
Method Description
CheckRules Executes all rules for the object and for all properties of the
object
CheckRules(property) Executes rules for the specified property, followed by rules for
any dependent properties
CheckObjectRules Executes per-type rules for the object
The OnChildChanged method (and corresponding ChildChanged event) execute each time a child
object is changed within the object graph. You can use the ChildChangedEventArgs parameter to
get specifics about the change, which can be useful when you only want to call CheckRules when
certain child objects are changed.
In this example, when OnChildChanged is invoked the code calls CheckRules to run all rules
associated with the LineItems property, ensuring that those rules are executed each time a child
object is changed.
This technique is designed for use within data access code and I’ll use this
technique in the Using CSLA 4: Data Access ebook. If you are using what
are called DataPortal_XYZ methods you’ll write code like I’m showing
here. If you are using the ObjectFactory data access technique the
ObjectFactory base class from the Csla.Server namespace also has a
BypassPropertyChecks method to provide similar functionality.
ICheckRules The BusinessBase class implements the ICheckRules interface from
the Csla.Core namespace. This interface defines methods that allow
code to suppress rule execution, resume rule execution, and to force
execution of all business and validation rules.
((Csla.Core.ICheckRules)_customer).SuppressRuleChecking();
try
{
// set properties here without executing
// any rules
}
finally
{
((Csla.Core.ICheckRules)_customer).ResumeRuleChecking();
((Csla.Core.ICheckRules)_customer).CheckRules();
}
Structure of a Rule
A business or validation rule is implemented as a class that implements the IBusinessRule
interface or inherits from the BusinessRule base class defined in the Csla.Rules namespace. While
there are many ways you can implement rules and a lot of advanced features at your disposal, the
basic structure of a rule class is pretty consistent.
For example, here’s a rule that must be associated with a business object property:
public class MyRule : Csla.Rules.BusinessRule
{
public MyRule(Csla.Core.IPropertyInfo primaryProperty)
: base(primaryProperty)
{
InputProperties = new List<Csla.Core.IPropertyInfo> { PrimaryProperty };
}
Here is a similar rule that changes the value of the primary property associated with the rule:
public class MyRule : Csla.Rules.BusinessRule
{
public MyRule(Csla.Core.IPropertyInfo primaryProperty)
: base(primaryProperty)
{
Using CSLA 4: Creating Business Objects Page 93
Rev 1.1
InputProperties = new List<Csla.Core.IPropertyInfo> { PrimaryProperty };
}
You can use the AddOutValue method shown here to have the rule change the primary
property’s value when the rule completes. The AddOutValue method can also be used to change
other property values. In that case you must add those properties to the AffectedProperties list in
the rule’s constructor. I’ll discuss the AffectedProperties list later in this chapter.
While most rules are associated with a property, that’s not true of all rules. Here’s another
example, of a rule that doesn’t require that it be associated with a property:
public class MyRule : Csla.Rules.BusinessRule
{
protected override void Execute(Csla.Rules.RuleContext context)
{
// implement rule here
}
}
Because no primary property is required by this rule’s constructor, the rule may or may not be
associated with a specific property. That decision is deferred to your code in the AddBusinessRules
override of the business class.
The rule classes inherit from the BusinessRule base class. You could choose to implement the
IBusinessRule interface manually, though this is an advanced scenario that should be extremely
uncommon.
When a rule requires an associated property, or other input values, it will implement a
constructor to require those values. Rules that don’t require such input won’t have an explicit
constructor.
The implementation of the rule is always in the Execute method, which is provided with a
RuleContext parameter. This parameter contains input values and provides mechanisms for rules
to provide output results.
RuleContext Parameter
Central to any business or validation rule implementation is the RuleContext parameter that is
provided to the Execute method. The RuleContext parameter value contains the members listed in
Table 20.
Member Description
Rule Gets a reference to the business rule object
Target Gets a reference to the business object; defaults to null
for async rules unless you set
ProvideTargetWhenAsync to true in the rule’s
constructor
InputPropertyValues
AddOutValue
Complete (async only)
When creating validation rules you’ll typically use the following members:
InputPropertyValues
AddErrorResult
AddWarningResult
AddInformationResult
AddSuccessResult
Complete (async only)
IBusinessRule Interface
All business rule types must implement the IBusinessRule interface. This interface is used by the
CSLA .NET business rules subsystem to interact with all business rules. You can implement this
interface directly if you choose, but I recommend using the BusinessRule base class for most rules.
The IBusinessRule interface defines the members listed in Table 21.
Member Description
PrimaryProperty Defines the primary property to which the rule is associated; if
null then the rule is associated with a business type.
RuleName Gets the unique name of the rule as a rule:// URI.
Priority Gets the priority of the rule.
IsAsync Gets a value indicating whether the Execute method will run
asynchronous code.
ProvideTargetWhenAsync Gets a value indicating whether the RuleContext should include
a Target value for an async rule. The default is false, because
use of the Target value in async code will cause serious
problems that are hard to identify and debug.
Execute The method that is invoked when the rule is executed. This is the
method that implements the rule.
InputProperties Gets a list of IPropertyInfo fields defining the property values
that should be provided to the Execute method through the
RuleContext parameter.
AffectedProperties Gets a list of properties that are affected by this rule. These are
considered to be dependent properties, and their rules are run
after the synchronous rules for the primary property are
complete. If your rule sets output values with the AddOutVaue
method, the output properties must be added to the
AffectedProperties list.
RuleName Property
Perhaps the most important behavior is that the BusinessRule base class automatically creates a
valid RuleName value for each rule object. The RuleName property must contain a rule:// URI that
uniquely identifies each specific rule object. Normally this URI will look something like those listed
in Table 22.
URI Description
rule://ruleType/null Rule associated with a business type
rule://ruleType/null?p1=v1 Rule associated with a business type, where the rule has
additional property values
rule://ruleType/primaryProperty Rule associated with a specific property
rule://ruleType/primaryProperty?p1=v1 Rule associated with a specific property, where the rule
has additional property values
This won’t actually work, however. It is important to remember that the property getter and
setter code in a normal editable object uses GetProperty and SetProperty, and so all
authorization, business, and validation rules are executed automatically. Your rule is almost
certainly executing because the primary property was changed. In this case, if your code directly
sets the primary property, (in this example the Name property) you’ll end up in a recursive loop that
will ultimately cause a stack overflow exception.
To avoid this issue you must not directly use the property getter or setter to get or set property
values from the business object.
The purpose of the ReadProperty method provided by the BusinessRule class is to allow you to
get property values of the business object without triggering authorization rules. The purpose of the
LoadProperty method is to allow you to set property values of the business object without
triggering authorization, business, or validation rules.
The correct implementation to directly interact with the business object’s properties is this:
protected override void Execute(Csla.Rules.RuleContext context)
{
var target = (ProductEdit)context.Target;
var name = (string)ReadProperty(target, ProductEdit.NameProperty);
LoadProperty(target, ProductEdit.NameProperty, name.ToUpper());
}
Notice how the ReadProperty method is used to get the property value from the target object,
and then the LoadProperty method is used to set the property with a new value.
If you are implementing a rule that is tightly coupled to a specific business class, this is a good
technique to efficiently get and set properties from that object. You should make sure that no code
on any background thread ever tries to interact with the Target value or its properties.
For most rules you should use the InputProperties and AddOutValue technique to avoid tight
coupling and to provide consistent coding for both synchronous and asynchronous rules.
Rule State
Your rule might require that extra parameter values be provided to the rule as it is created. For
example, here’s a rule that adds some value to a numeric property:
public class AddValue : Csla.Rules.BusinessRule
{
public int ValueToAdd { get; private set; }
In this rule, I have a ValueToAdd property that is set through the constructor, and that property
is used by the rule as it executes.
It is critical that you understand that instance properties or fields in a rule object can not be
changed after the rule object has been created.
You must initialize instance properties and fields as the object is created, and never
change them from that point forward.
This restriction exists because each rule object is shared by all instances of the business type
with which the rule is associated. If you did change a property or field in a rule, you’d instantly
affect all business objects using that rule, and the result would almost certainly be inconsistent
behavior that would be difficult to identify, debug and fix.
Earlier in this chapter I discussed the RuleName property and how it must be unique for each
rule. If your rule requires extra parameter values, you must ensure that those values are included in
the rule:// URI that defines the RuleName property, and you do this by adding your parameter
values to the RuleUri property of the BusinessRule base class.
Keep in mind that you could associate more than one instance of the AddValue rule to any
property, so to ensure that the rule name is unique, you must include this parameter value as part
of the RuleName, which means it must be part of the RuleUri value. The constructor adds this value
to the RuleUri:
Using CSLA 4: Creating Business Objects Page 99
Rev 1.1
RuleUri.AddQueryParameter("ValueToAdd", valueToAdd.ToString());
If you forget to add your parameters to the RuleUri, you run the risk of having more than one
rule with the same name associated with a property in your business object. That will lead to
inconsistent behaviors as rules are executed. Such inconsistencies will typically only be discovered if
you implement comprehensive unit testing for your properties and their rules.
It is technically still possible to have two rules with the same name associated with a
property if both rules have exactly the same parameter values. This is considered to
be an extreme edge case, and if you encounter such a scenario you will need to
devise your own way to identify each rule separately.
In summary, the two things you must remember when implementing instance level properties or
fields in a rule is that the property or field value must be added to the RuleUri, and that the
property or field value must not be changed once the object has been initialized.
Now I’ll switch gears and talk about a couple more advanced features of rules: rule chaining and
asynchronous rules.
Rule Chaining
Rule chaining enables one rule to invoke another rule. There are various reasons why you might use
rule chaining, including:
Of these, the simplest and most common is the idea of a gateway rule. A gateway rule is a rule
that checks a condition to decide whether it should invoke the “real rule” or inner rule. I’ll use the
gateway rule as an example of rule chaining because this is the most common scenario.
For example, your business object might have a property that is required for existing objects, but
isn’t required for a new object. The rule is a simple required rule such as
Csla.Rules.CommonRules.Required, but it should only be executed if the business object’s IsNew
property is false. You can use a gateway rule to check IsNew, and to invoke the Required rule only
when appropriate:
public class IsNotNew : Csla.Rules.BusinessRule
{
public Csla.Rules.IBusinessRule InnerRule { get; private set; }
It is important to understand that the gateway rule must ensure that its InputProperties list
includes all property values that will be required by the rule it invokes. The chained RuleContext
generated by the GetChainedContext method includes the property values specified by the outer
rule’s InputProperties list. One way to automate this process is by replacing the code in the
constructor with this variation:
public IsNotNew(Csla.Core.IPropertyInfo primaryProperty, Csla.Rules.IBusinessRule innerRule)
: base(primaryProperty)
{
InputProperties = new List<Csla.Core.IPropertyInfo> { PrimaryProperty };
InnerRule = innerRule;
RuleUri.AddQueryParameter("rule", System.Uri.EscapeUriString(InnerRule.RuleName));
Notice how the InputProperties list (if any) from the InnerRule object is merged into the
InputProperties list of the IsNotNew gateway rule.
The business class will associate this IsNotNew rule with a property in its AddBusinessRules
override like this:
protected override void AddBusinessRules()
{
base.AddBusinessRules();
BusinessRules.AddRule(
new IsNotNew(CityProperty, new Csla.Rules.CommonRules.Required(CityProperty)));
}
In this example, the IsNotNew rule is associated with the CityProperty, and the inner rule is also
provided. The inner rule is the Required rule from Csla.Rules.CommonRules. Based on the
implementation of the Execute method in the IsNotNew rule, you can see that the Required rule
will only execute if the business object’s IsNew property is false.
You can use this same concept to build outer rules that invoke one or more inner rules. The
important thing is to ensure that you create a unqiue chained context for each inner rule you
invoke, and to ensure that the outer rule’s InputProperties list contains any properties required
by the inner rules. This capability for one rule to invoke other rules can be used to create gateway
rules as I’ve shown here, but also to create rules that select which other rules to run, thus allowing
you to create your own rule execution model when necessary.
Asynchronous Rules
Business and validation rules can be synchronous or asynchronous. Generally speaking, all rules
follow the same code structure, but there are some important differences between synchronous
and asynchronous rules.
Using CSLA 4: Creating Business Objects Page 101
Rev 1.1
Asynchronous, parallel, or multi-threaded coding is complex. You should use
caution, and make sure you completely understand all the consequences before
creating an asynchronous rule.
Asynchronous rules aren’t automatically asynchronous. CSLA .NET doesn’t run the rule on a
background thread for you. Instead, an asyncrhronous rule is a rule that is allowed to execute
asynchronous, parallel, or multi-threaded operations within the rule implementation. It is your code
in the rule implementation that will call an asynchronous service, or will run some code on a
background thread (usually using the BackgroundWorker component). And it is your code that is
responsible for ensuring that the completion notification runs on the original calling thread
(typically the UI thread).
In other words, “asynchronous rules” are potentially asynchronous, and it is up to you whether
the rule is asynchronous or not. It is important to note that CSLA .NET treats asynchronous rules
differently from synchronous rules, because the framework assumes the rule will be asynchronous.
You indicate that a rule is asynchronous by setting the IsAsync property to true in the rule’s
constructor:
public BusinessRuleClass(IPropertyInfo primaryProperty)
: base(primaryProperty)
{
IsAsync = true;
}
If you set IsAsync to true as shown here, you are allowed to invoke asynchronous operations in
your Execute method implementation. One of the most common scenarios is to invoke an async
factory method on a business class. Here’s a rule that checks to see if a product number already
exists in the database:
public class ProjectExists : Csla.Rules.BusinessRule
{
public ProjectExists(Csla.Core.IPropertyInfo primaryProperty)
: base(primaryProperty)
{
IsAsync = true;
InputProperties =
new System.Collections.Generic.List<Csla.Core.IPropertyInfo> { PrimaryProperty };
}
The Project.Exists method is an asynchronous factory method that invokes the data portal to
make an asynchronous call to the application server to see if the project id already exists in the
database. Notice how the callback handler is a lambda expression that checks the result value and
adds a warning result if the value is true.
You must call Complete on the RuleContext when the asynchronous operation is
complete. If you don’t call Complete, CSLA .NET will never know that your rule has
completed.
The Complete method must be called in cases of success or failure. When the asynchronous
operation is complete, call the Complete method.
I’ve already discussed the difference in execution times between synchronous and asynchronous
rules. Synchronous rules are invoked according to priority order and are subject to short-circuiting.
Asynchronous rules are started after all synchronous rules for a property have been executed, and
they run in an indeterminate order. If you have multiple asynchronous rules, they will run in parallel
and will complete in an indeterminate order based on how long each rule takes to complete.
Synchronous rules have access to the business object instance, and can directly interact with the
object and its properties. By default asynchronous rules do not have access to the business object
instance, and must rely on CSLA .NET to provide the rule with copies of any property values
required by the rule.
Similarly, asynchronous rules can provide a dictionary of property values to be changed, and
CSLA .NET changes those property values after the rule completes. An asynchronous rule with a list
of AffectedProperties will cause rules for those properties to be executed when Complete is
called on the RuleContext, and after any output values have been updated on the target object.
The reason for these restrictions is that CSLA .NET is not threadsafe, which means you can’t have
multiple threads interacting with an object at the same time. Some or all code in an asynchronous
rule may be running on a background thread, so it is important that such code not interact directly
with the business object or its properties.
Using BackgroundWorker
The most common reason to create an asynchronous rule is because the rule needs to call an
asynchronous factory method or the asynchronous data portal. Another common scenario is where
a rule needs to implement some algorithm that will take a substantial amount of time (seconds or
minutes) to complete.
In this case, you’ll explicitly execute the long-running code on a background thread. The .NET 4
framework includes some nice features for implementing tasks on background threads in the
System.Threading.Tasks namespace. Unfortunately these features are not available in Silverlight
or WP7, so if you are writing code for all current platforms you’ll need to avoid using the Task
features of .NET 4.
I recommend using the BackgroundWorker component for several reasons:
As with any rule, you can use the InputProperties list and InputPropertyValues dictionary to
safely provide copies of business object property values to the Execute method and code running
on the background thread. The code in the rule should use the AddOutValue method to return any
output values, or the various validation methods on the RuleContext object to return validation
results. Those methods can be called on the background or UI thread.
If you use AddOutValue to return an output value for any property other than the primary
property, you must remember to add those properties to the AffectedProperties list in the rule’s
constructor.
The Complete method of RuleContext must be called on the UI thread, which means it is called
in the RunWorkerCompleted event handler.
I’ve pulled the rule implementation and the processing of results out into separate private
methods, and then those methods are invoked through a BackgroundWorker or directly, depending
on the value of the IsAsync property.
This all depends on the constructor containing some code (not shown) that determines whether
this particular instance of the rule should be synchronous or asynchronous.
Asynchronous rules complicate ASP.NET code (Web Forms, MVC, or services). You might use this
technique to implement rules that are asynchronous on a smart client, but synchronous when
running on the server. In that case, the constructor would look like this:
public LongRunningRule()
{
#if SILVERLIGHT
IsAsync = true;
#else
if (HttpContext.Current != null)
IsAsync = false;
else
IsAsync = true;
#endif
}
When you set this property your rule implementation will be provided with a reference to the
business object. It is up to you to ensure that no code running on a background thread interacts
with the object or its properties. If you violate this restriction you may introduce bugs that are very
difficult to find, troubleshoot, or resolve.
The reason this is acceptable, is that I’m only using the Target value on the UI thread. I don’t use
the Target value in the callback lambda code, which might be running on a background thread
(though when using the data portal even that code does run on the UI thread).
You should implement most rules as synchronous rules, because they are generally simpler and
more efficient. When you need to make asynchronous calls to services or through the data portal,
or if you have a rule that implements a long-running algorithm that can run on a background thread
you will implement asynchronous rules.
For this simple rule, the Execute method gets the input value from the InputPropertyValues
dictionary in the context parameter. This value is available because the rule’s constructor added
the primary property to the InputProperties list as the rule was created.
If the input value contains a string value, the AddOutValue method is used to provide an output
value for the primary property. The property value will be set to this output value after the rule
completes. Notice that the output value is the uppercased input value.
The result is a rule that takes a string property value as input and sets that property to the
same string, but uppercased.
Notice how the Target property is cast to a specific business type, and then the ReadPropery
method from the BusinessRule base class is used to read the property value without triggering
authorization rules. Similarly, the LoadProperty method is used to update the property value.
While this implementation is somewhat more direct than the previous examples, you can easily
see how the code in the Execute method is tightly coupled to the ProductEdit business type, so
this rule isn’t generally useful for other business types.
Because this code has direct access to the Target property, it can use the business object’s
Parent property to access its parent. Given access to the parent object, that object’s properties can
be read and loaded with values as shown in the example.
You can use the same concept to access child objects or any other objects in the object graph.
At this point, you should understand how to create business rules that get and set properties of
the business object or other objects in the object graph.
This rule has a constructor that requires a primary property, and a parameter with the prefix
required for the property value. As with business rules, notice that the parameter value is added to
the RuleUri to help ensure this rule has a unique RuleName value.
Unique RuleName values are more important for validation rules than business rules,
because this is the name used to identify the rule within the broken rules collection.
The Execute method checks to see if the input value starts with the prefix. If it doesn’t, the
AddErrorResult method of the RuleContext object is used to add an error result to the output of
the rule.
Once the rule completes, any output results, such as this error, are added to the broken rules
collection. If the rule doesn’t return any result, it is assumed that the rule was successful and any
existing broken rules entries for this rule are removed from the broken rules list.
Rule Severity
Rules can return results with different severity:
Error
Using CSLA 4: Creating Business Objects Page 111
Rev 1.1
Warning
Information
Success
Error severity indicates that the broken rule should prevent the object from being saved. Broken
rules of this severity appear as validation rule violations in all data binding technologies, and
seamlessly integrate into any standard .NET or Silverlight validation schemes. For example, Error
severity rules are automatically displayed by the Windows Forms ErrorProvider control, the
ASP.NET MVC validation behaviors, and the WPF and Silverlight validation mechanisms.
This automatic display of validation errors is only true for Error severity rules. Microsoft’s data
binding technologies have no concept of validation severity, and so they won’t automatically display
information for any other severities.
CSLA .NET includes UI helper components for several of the UI technologies to make it easy to
display Warning and Information severity rules to the user. For example, the PropertyInfo control
for Silverlight, WPF, and WP7 and the PropertyStatus control for Silverlight and WPF make it easy
to display rules of any severity to the user.
Warning severity indicates that the broken rule is merely a warning. The business object can still
be saved, but the user should be notified that there is some concern about the property value or
the state of the object.
Information severity indicates that the broken rule is purely an informational message. The
business object can be saved and the user should be shown the message.
Success severity is special, in that all it does is indicate success with no message for display to the
user. Earlier I mentioned that the default is success, so in most cases there’s no need to explicitly
indicate success by calling AddSuccessResult. This is one example of our discussion about short-
circuiting and rule priorities earlier in this chapter.
It is possible for a rule to explicitly indicate that no subsequent rules should execute. A rule can
explicitly trigger short-circuiting. All the RuleContext methods that add validation rules for error,
warning, information, and success have overloads that allow you to specify a Boolean value
indicating that rule processing should be short-circuited.
In the case that a rule is silently successful, but still needs to cause short-circuiting, your rule will
call AddSuccessResult with a parameter of true to prevent any subsequent rules from executing.
DataAnnotations Attributes
While most validation rules will be implemented as subclasses of the BusinessRule base class, you
can also implement validation rules as validation attributes by subclassing the
ValidationAttribute base class in the System.ComponentModel.DataAnnotations namespace.
Rules implemented this way aren’t as powerful or flexible as CSLA .NET rules, because they can’t
specify priorities, trigger short-circuiting, run asynchronously, or return anything but Error severity
results. On the other hand, applying validation rules as an attribute on a business class property is
very convenient and results in readable code. For simple, synchronous validation rules I’ll often
implement the rules as validation attributes.
Using CSLA 4: Creating Business Objects Page 112
Rev 1.1
Remember that any validation attributes are treated as normal validation rules by CSLA .NET, so
they run along with all other priority 0 rules when CheckRules is called. The primary difference is
one of implementation. Here’s an example of a simple rule implemented as a validation attribute:
[AttributeUsage(AttributeTargets.Property)]
public class ValidPrefix : System.ComponentModel.DataAnnotations.ValidationAttribute
{
public string Prefix { get; private set; }
This rule is implemented as a .NET attribute, and it inherits from ValidationAttribute so it can
participate in the normal DataAnnotations behaviors as supported by ASP.NET MVC and the
Silverlight DataForm control.
The rule defines a constructor to require the prefix it will require for the property value. It is
applied to a property in a business class like this:
public static readonly PropertyInfo<string> MyNameProperty = RegisterProperty<string>(c => c.Name);
[ValidPrefix("SOP")]
public string Name
{
get { return GetProperty(MyTextProperty); }
set { SetProperty(MyTextProperty, value); }
}
The ValidationAttribute base class defines a protected method named IsValid that the rule
overrides to provide its implementation. This IsValid method takes two parameters, the property
value to be validated and a ValidationContext parameter with extra information.
For this simple rule the value parameter is checked to see if it starts with the required prefix. If
not, a ValidationResult object containing the error message is returned. To indicate success,
return a null value.
You should be aware that the ValidationContext parameter includes an ObjectInstance
property, which is similar to the Target property of the RuleContext parameter in standard CSLA
.NET rules. You can use this ObjectInstance property to access other properties of the business
object, though doing so will couple your rule to the business type and will reduce the ability to
reuse your rule.
GetRuleDescriptions Method
The GetRuleDescriptions method on the BusinessRules property returns an array of string
values. Each value is in URI format, with a rule:// URI prefix. The method is called within an
editable business class like this:
var rules = BusinessRules.GetRuleDescriptions();
The result is a string array containing rule:// URI values. Each URI contains several fields of
information, including:
It is very important that all argument values be added to the rule description. The
rule description must be unique, and without the argument values, the rule
description may not be unique.
The RuleUri type from the Csla.Rules namespace can be used to parse each of the elements of
the string array returned as a result of the GetRuleDescriptions method.
RuleUri Type
The RuleUri type is similar to the Uri type provided by the .NET Framework. It accepts a rule://
URI, and parses that value so you can easily access the various parts of the URI.
For example, the following code gets the list of rules for an object, and filters the values to get
the list of rules for the Name property:
var rules = BusinessRules.GetRuleDescriptions();
var ruleUriList = rules.Select(r => new RuleUri(r));
var nameRules = ruleUriList.Where(r => r.PropertyName == NameProperty.Name);
This code uses a LINQ expression to convert the string array into a list of RuleUri objects. It
then uses another LINQ expression to filter the list of RuleUri objects by the PropertyName
property.
IDataErrorInfo
INotifyDataErrorInfo
It is also possible to manually access the validation rule results by accessing the list of “broken
rules” associated with an editable business object.
As validation rules are executed, their results are maintained in a list of broken validation rules.
Every editable business object maintains a list of the broken rules associated with the object and its
properties.
BrokenRulesCollection Property
The BusinessBase base class in the Csla namespace exposes a public property named
BrokenRulesCollection. This property provides access to a read-only snapshot of the complete
broken rules collection for the business object.
Using CSLA 4: Creating Business Objects Page 115
Rev 1.1
The result is a BrokenRulesCollection object, which is a collection of BrokenRule objects. The
BrokenRulesCollection object is a subclass of the ObservableCollection<T> type defined by the
.NET Framework. This means that the collection is bindable in all UI technologies with the exception
of Windows Forms. If you want to display the list of broken rules to the user, you may be able to
bind this collection directly to your UI.
You can also use LINQ queries to interact with the collection. For example, this code filters the
list of broken rules by property name:
var nameRules =
customer.BrokenRulesCollection.Where(r => r.Property == CustomerEdit.NameProperty.Name);
This code assumes the customer field references a CustomerEdit business object. It accesses the
BrokenRulesCollection property and applies a LINQ Where clause to filter the results to get the
broken rules for the Name property.
The BrokenRule type exposes the properties listed in Table 23.
Property Description
Property Name of the property to which the rule is attached; may be null for a per-object
rule
RuleName Name of the rule as a rule:// URI
Description Friendly description of the rule, for display to the user
Severity RuleSeverity value of the rule (Error, Warning, or Information)
GetBrokenRules Method
The BusinessRules object for a business object exposes a GetBrokenRules method. This method
returns the same BrokenRulesCollection object as the BrokenRulesCollection property of the
BusinessBase class.
In fact, the implementation of the BrokenRulesCollection property in the BusinessBase class
uses the GetBrokenRules method of the BusinessRules object to get its result.
GetAllBrokenRules Method
The BusinessRules type also exposes a GetAllBrokenRules method. This is a static method that
accepts a business object as a parameter. The purpose of this method is to combine the broken
rules collections for all business objects in an entire object graph into a single result.
For example, you might have an object graph with an OrderEdit editable root. Assuming that
OrderEdit object contains a collection of LineItemEdit objects, you might want to get a
consolidated list of all broken rules for the order and its line items. This can be done using the
GetAllBrokenRules method:
var allRules = BusinessRules.GetAllBrokenRules(order);
Property Description
Object Reference to the business object associated with this node
BrokenRules Reference to the BrokenRulesCollection for the business object associated with
this node
Parent Reference to the parent BrokenRulesNode object; null if the current object is the
root, otherwise the parent node corresponds to the parent business object of the
current business object
Node Node key value (for internal use)
The GetAllBrokenRules method is typically used to get a list of all broken rules for an object
graph for the purpose of populating some display in the UI to show the user a consolidated view of
all broken rules associated with their current task.
At this point, you should understand how to create business and validation rules, how to
associate them with properties or business types, and how they are executed automatically or
manually as your business objects are used by the application.
You’ll see more examples of these concepts in subsequent ebooks in the series. In those ebooks
I’ll also demonstrate how validation rules integrate with the various data binding technologies and
CSLA .NET helper controls for each type of UI.
Authorization Rules
Authorization rules are slightly different from business and validation rules, though they are as
similar as possible. As I discuss how to use and implement authorization rules I will assume that you
already understand how business and validation rules are used and implemented.
Authorization is the process of determining whether the current user is allowed to perform
various actions. CSLA .NET allows you to apply authorization rules to the following actions:
Read a property
Set a property
Execute a method
Create a business object
Using CSLA 4: Creating Business Objects Page 117
Rev 1.1
Retrieve a business object
Edit (save) a business object
Delete a business object
Some of these rules apply to members of a specific business object instance, and so are per-
property or per-method rules, while other rules apply to the type of object rather than any specific
instance.
For example, the rules that control whether the current user can create or retrieve a
CustomerEdit object must apply to the business type because the rules are applied before any
object instance exists. On the other hand, a rule controlling whether the current user can read a
property is applied as the user tries to read a property from a specific object instance and so that
rule runs within the context of that object instance.
The per-property and per-method actions are:
Read a property
Set a property
Execute a method
The most important thing to remember is that authorization rules are business logic, not
security. Authorization rules control whether the current user is allowed to perform certain actions
based on the business rules surrounding those actions.
Sometimes this decision is as simple as determining whether the user is or isn’t in a certain
group or role. Other times the decision must take into account the state of the business object, the
state of the application as a whole, or other information from the user’s profile or claims.
CSLA .NET provides two pre-built rules that work with the standard .NET role-based
authorization model. These rules are IsInRole and IsNotInRole and are found in the
Csla.Rules.CommonRules namespace. You may find these rules to be sufficient for your
authorization requirements, or you may need to implement your own authorization rules to meet
your application requriements.
For example, your application might not use roles at all, but instead might use other information
from the user’s profile to determine what actions the user can and can’t perform. I’ll discuss
authentication and loading user identity information in the Using CSLA 4: Security ebook, but in
most cases you can assume that your authorization rules will have access to various user profile or
claims information as necessary.
Using AddBusinessRules
Per-property and per-method authorization rules are associated with the properties and methods
of your business type by overriding the AddBusinessRules method and calling the AddRule method
of the BusinessRules object. This process is essentially the same as associating business and
validation rules with your properties.
To associate rules to properties and methods you’ll write code like this in your business class:
protected override void AddBusinessRules()
{
base.AddBusinessRules();
BusinessRules.AddRule(new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.ReadProperty, CityProperty, "User", "Supervisor"));
BusinessRules.AddRule(new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.WriteProperty, CityProperty, "Supervisor"));
BusinessRules.AddRule(new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.ExecuteMethod, TestMethod, "Supervisor"));
}
In this example, I’m using the IsInRole rule to indicate that the User and Supervisor roles are
allowed to read the City property, but only the Supervisor role is allowed to write to that property.
Similarly, only the Supervisor role is allowed to execute the Test method.
Your AddBusinessRules override will typically contain a mix of business, validation, and
authorization rule associations. I normally try to either organize the AddRule calls by property or by
rule type, you should determine an organizational approach that works for you and standardize on
that coding pattern.
You should never call this method explicitly. CSLA .NET will call this method
automatically to initialize your authorization rules one time during the life of each
AppDomain.
To associate rules to your business type you’ll write code like this in your business class:
public static void AddObjectAuthorizationRules()
{
Csla.Rules.BusinessRules.AddRule(typeof(ProductEdit),
new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.CreateObject, "Supervisor"));
Csla.Rules.BusinessRules.AddRule(typeof(ProductEdit),
new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.GetObject, "User", "Supervisor"));
Csla.Rules.BusinessRules.AddRule(typeof(ProductEdit),
new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.EditObject, "Supervisor"));
Csla.Rules.BusinessRules.AddRule(typeof(ProductEdit),
new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.DeleteObject, "Supervisor"));
}
I’m using the IsInRole rule, and associating it with the create, get, edit, and delete actions for
the ProductEdit business type. In this example, the Supervisor role is allowed to perform all four
actions, but the User role is only allowed to get (retrieve) objects of type ProductEdit.
Because AddObjectAuthorizationRules is a static method, the AddRule method I’m calling is a
static method on the BusinessRules type in the Csla.Rules namespace.
These per-type authorization rules are enforced by the data portal, so it is important that users
avoid the use of the new keyword to create business objects, and instead invoke factory methods
(which use the data portal) to create or retrieve instances of business objects. If you do use the new
keyword to create instances of your business objects, you shouldn’t be surprised when the
authorization rules aren’t applied.
In this example, the default rule set uses the User and Supervisor roles, while RuleSetA has
different roles defined for its users; and so the roles supplied to the rule are different.
Similar code is used in the AddObjectAuthorizationRules method:
public static void AddObjectAuthorizationRules()
{
// associate rules for default rule set
Csla.Rules.BusinessRules.AddRule(typeof(EditableProperties),
new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.CreateObject, "Supervisor"));
Notice that in this case, the current rule set is controlled by the RuleSet property on the
Csla.ApplicationContext object. This property controls which rule set is used for per-type rules
for the current user application-wide. For per-type rules, you don’t control the rule set for each
business object or type; you control it for the entire application by changing this global property
value.
The ApplicationContext object is user-specific, so even in a multi-user server scenario the
RuleSet property only affects the current user. That way, each user can be using a different rule
set.
Executing Rules
Like business and validation rules, authorization rules are normally executed automatically.
The GetProperty, GetPropertyConvert, SetProperty, and SetPropertyConvert methods
automatically check authorization rules before doing any other work. The data portal automatically
checks authorization rules before any create, fetch, save, or delete operations.
Using CSLA 4: Creating Business Objects Page 121
Rev 1.1
The one exception is the ExecuteMethod action, which you must explicitly invoke at the top of
any method you implement. I discussed this in Chapter 1, and here’s the code example from that
chapter:
public static readonly MethodInfo TestMethod = RegisterMethod(typeof(EditableProperties), "Test");
public void Test()
{
CanExecuteMethod(TestMethod);
// do some work here
}
The first line of code in the Test method is a call to CanExecuteMethod, which executes any
authorization rule associated with the Test method to find out if the user is authorized to perform
this action.
Notice that this interface uses string literal values for the names of properties and methods.
This is because most UI code is driving off data binding information, and so won’t have access to the
static metadata fields describing each property or method.
The BusinessBase and ReadOnlyBase base classes also expose public methods you can use
directly. These methods have overloads that accept either an IPropertyInfo metadata field or a
string literal:
ProductEdit obj = _obj;
bool canExecute = obj.CanExecuteMethod(ProductEdit.TestMethod);
You can use the interface or the public methods as appropriate for your application needs.
Per-Type Rules
The per-type rules can be executed through the BusinessRules class in the Csla.Rules namespace.
This class exposes a set of HasPermission methods that are static and public, so any code in your
application can check the per-type rules.
You can use these static methods like this:
bool canCreate = Csla.Rules.BusinessRules.HasPermission(
Csla.Rules.AuthorizationActions.CreateObject, typeof(ProductEdit));
bool canGet = Csla.Rules.BusinessRules.HasPermission(
Csla.Rules.AuthorizationActions.GetObject, typeof(ProductEdit));
bool canEdit = Csla.Rules.BusinessRules.HasPermission(
Csla.Rules.AuthorizationActions.EditObject, typeof(ProductEdit));
bool canDelete = Csla.Rules.BusinessRules.HasPermission(
Csla.Rules.AuthorizationActions.DeleteObject, typeof(ProductEdit));
As you can see from the example code, you can use this technique to execute the per-type rules
for any of the four per-type actions on a business type.
You can also use an overload of these methods to specify the rule set to use when checking the
rule:
bool canCreate = Csla.Rules.BusinessRules.HasPermission(
Csla.Rules.AuthorizationActions.CreateObject, typeof(ProductEdit), "RuleSetA");
Finally, for the edit and delete actions you might have an object instance you can supply to the
rule:
bool canEdit = Csla.Rules.BusinessRules.HasPermission(
Csla.Rules.AuthorizationActions.EditObject, obj);
When I discuss how you can implement per-type authorization rules, you’ll see how this object
instance is made available to the rule’s code. Obviously, you’ll never have an object instance to
provide to a create or get action, but you’ll often have an instance for edit and delete actions.
BypassPropertyChecks property
ICheckRules interface
SuppressRuleChecking property
The scenarios where each technique should be used for authorization rules are the same as
those for business and validation rules. Please refer to Table 19 for more information.
At this point, you should understand how to associate authorization rules with properties,
methods, and business types; as well as how these rules are executed, and how you can suppress
rule execution. I’ll move on to discuss how to create custom authorization rules.
Using CSLA 4: Creating Business Objects Page 123
Rev 1.1
Implementing Authorization Rules
The role-based authorization supported by the CSLA .NET IsInRole and IsNotInRole rules is built
directly on the support for role-based authorization provided by the .NET framework. Many
applications can use this role-based model without the need for custom rules.
There are cases where simple role-based rules aren’t sufficient. For example:
Remember that authorization rules are business rules, not security rules. So it is quite common
to need a custom rule to control whether the current user can read or write a property value based
on the state of other properties in the object. For example, you might have a property that can only
be changed if the object is new, so your custom rule needs to take the object’s IsNew property into
account as part of its behavior.
Structure of a Rule
Authorization rules follow a consistent structure. They must implement the IAuthorizationRule
interface from the Csla.Rules namespace, but they’ll usually subclass the AuthorizationRule class
to make the process simpler. Here’s the basic structure of a rule:
public class MyAuthorizationRule : Csla.Rules.AuthorizationRule
{
public string AllowedRole { get; private set; }
public MyAuthorizationRule(
Csla.Rules.AuthorizationActions action, Csla.Core.IMemberInfo element, string allowedRole)
: base(action, element)
{
AllowedRole = allowedRole;
}
Authorization rules are implemented as a class, and they normally inherit from the
AuthorizationRule base class. They also must have a constructor, because every rule must at least
be associated with an action from the AuthorizationActions type, and most rules are also
associated with a property or method. The IMemberInfo interface from the Csla.Core namespace
allows this rule to be associated with either a property (IPropertyInfo) or a method
(IMethodInfo).
In this example, the rule also requires an allowedRole parameter; which is the one role that is
allowed to perform the action. That value is stored in an instance-level property or field of the
object.
Using CSLA 4: Creating Business Objects Page 124
Rev 1.1
The implementation of the rule itself goes in the Execute method; which is passed an
AuthorizationContext parameter containing information about the action, member, and business
object for which this rule is running. The AuthorizationContext is also used to return the results of
the rule through its HasPermission property.
This simple rule checks to see if the current user is in the correct role, and the HasPermission
property of the AuthorizationContext parameter is set accordingly.
AuthorizationContext Parameter
The AuthorizationContext parameter passed to the Execute method of the rule is at the heart of
the rule implementation. Table 25 lists the members of the AuthorizationContext type.
Member Description
Rule Provides a reference to the authorization rule
Target Provides a reference to the business object; this value will be
null if there is no object instance (such as for create and retrieve
actions)
TargetType Gets the type of the business object
HasPermission Set this to the result of the rule: true indicates the user should
be allowed to perform the action, false means the user doesn’t
have permission to perform the action
Rule implementations can also make use of the Target and TargetType properties to apply
behaviors that are specific to a business object or business type.
The TargetType value is always available, but it is important to recognize that the Target
property might be null. While per-property and per-method rules always have a business object to
populate the Target property, not all per-type actions will have a business object. For certain, you
know that the CreateObject and GetObject actions will not have a business object, because these
rules run before an object is created to determine whether the user is allowed to create or get the
object.
Any rule implementation that uses the Target property must check the value to see
if it is null before proceeding.
Here’s an example where I’m using the Target property in an Execute method:
protected override void Execute(Csla.Rules.AuthorizationContext context)
{
var target = context.Target as ProductEdit;
bool isNew = false;
if (target != null)
isNew = target.IsNew;
if (isNew && Csla.ApplicationContext.User.IsInRole(AllowedRole))
context.HasPermission = true;
Using CSLA 4: Creating Business Objects Page 125
Rev 1.1
else
context.HasPermission = false;
}
I cast the Target property to my business type, then I check to see if the value is null, and only
interact with it if it contains a valid reference.
You can combine the information from the AuthorizationContext parameter with the
properties available from the AuthorizationRule base class and the current user’s identity from
the User property of the Csla.ApplicationContext object to implement powerful and flexible
authorization rules.
IAuthorizationRule Interface
All authorization rules must implement the IAuthorizationRule interface from the Csla.Rules
namespace. Typically, rules will subclass the AuthorizationRule base class that already implements
this interface, but in some advanced scenarios you may choose to implement the interface directly.
The members of the interface are listed in Table 26.
Member Description
Action Gets the AuthorizationActions value specifying the action
this rule is authorizing
Element Gets the IMemberInfo metadata field for the property or
method with which this rule is associated; this value is null if the
rule is associated with a business type
CacheResult Gets a Boolean value indicating whether the result of this rule can
be cached by the calling code
Execute This is the method that is invoked when the rule is executed
The BusinessBase and ReadOnlyBase classes implement caching of per-property and per-
method authorization results as a performance optimization. For role-based rules this is fine,
because the cache is automatically discarded any time the identity of the current user is changed.
But for some custom rules, especially those that are sensitive to the state of the business object,
the result must not be cached.
You’ve seen how the Execute method contains the implementation of the rule. The result of the
Execute method is provided through the HasPermission property of the AuthorizationRules
parameter.
Rule State
In my example rule class, I included an instance-level property:
public string AllowedRole { get; private set; }
The restrictions on instance-level properties and fields in authorization rules are the same as for
business and validation rules. Once the object has been initialized, you must never change the
values of any instance-level properties or fields.
Remember that each authorization rule instance is shared by all instances of the business type to
which the rule is associated. If you change the value of any instance-level properties or fields in an
authorization rule, you will instantly affect all the business objects to which that rule is associated.
This can lead to bugs that are very difficult to locate and fix.
Authorization rules are generally much simpler than business or validation rules. They return a
Boolean result indicating whether the current user is allowed to perform the specified action, so
they don’t have all the options and complexity of rule priorities, severities, or asynchronous
behaviors.
At this point, you should understand how to associate authorization rules with properties,
methods, and business types, as well as how the rules are executed, and how you can create your
own custom rules.