Tuesday 12 May 2009

CSLA.NET introduction - First business object

I have decided to learn about CSLA.NET framework and write down couple of articles which can help to understand the purpose of the framework and what it can do for you. I have learned basics but the framework has very nice features so it forces me to learn more.

What CSLA.NET is and what it can do?

CSLA.NET is framework which helps you to use business objects to build efficiently various types of application and enables to use object-oriented design in a distributed computing environment.

CSLA.NET framework helps developer to:
  • support for databinding in Windows and Web Forms
  • support for many types of UIs based on the same business objects
  • management of validation rules
  • management of authorization rules
  • N-level undo on a per-object basis (edit, cancel, apply)
  • interaction with distributed transaction technologies

Example

There will be created simple application which will show basics of the framework. In the first part the goal will be to create Customer class which will support databinding, contain validation rules, support undo functionality and use LINQ for access to database. Later I will continue with the example, add autorization, other classes and relation between them etc.

Business objects in CSLA.NET needs to be serializable objects and their properties, methods are usually divided into following categories:
  • Business methods
  • Factory methods
  • Validation rules
  • Authorization rules
  • Data access
The definition of the Customer class will looks like:
[Serializable]
public class Customer : BusinessBase<Customer>
As I have said before, business object are marked as serializable and are usually derived from some CSLA.NET base class (in our case BusinessBase).

Business methods

#region Business Methods

private byte[] timestamp = new byte[8];

private static PropertyInfo IdProperty = RegisterProperty(p=>p.Id, "Customer Id");
///
/// Read only property - primary key and unique
///

[System.ComponentModel.DataObjectField(true, true)]
public int Id
{
get { return GetProperty(IdProperty); }
}

private static PropertyInfo FirstNameProperty = RegisterProperty(p=>p.FirstName, "First Name");
///
/// Read write property
///

public string FirstName
{
get { return GetProperty(FirstNameProperty); }
set { SetProperty(FirstNameProperty, value); }
}

private static PropertyInfo LastNameProperty = RegisterProperty(p=>p.LastName, "Last Name");
public string LastName
{
get { return GetProperty(LastNameProperty); }
set { SetProperty(LastNameProperty, value); }
}

#endregion
Customer class has three public properties. It contains Id as unique identifier and you can see it is read-only property. It is decorated with DataObjectField attribute which shows the field as unique primary key. The attribute can help during databinding but it is not mandatory.
RegisterProperty method indicates that the field belongs to the business object type. GetProperty method retrieve value of the property but at first it check access rights.
Customer class contains also FirstName and LastName property, which are read-write properties. I will only mention SetProperty method which at first check access rights and after that sets new value. It throws an exception when user is not allowed to change the value.
Timestamp property holds database timestamp and is used for optimistic concurrency.

Factory methods

#region Factory Methods

public static Customer NewCustomer()
{
return DataPortal.Create();
}

public static Customer GetCustomer(int id)
{
return DataPortal.Fetch(new SingleCriteria(id));
}

public static void DeleteCustomer(int id)
{
DataPortal.Delete(new SingleCriteria(id));
}

private Customer()
{ /* Require use of factory methods */ }

#endregion
There is not usually used constructor to create instances of object in CSLA.NET. Instead of that there are used factory methods to create (NewCustomer method), retrieve (GetCustomer method) or delete (DeleteCustomer method). You can see above that there is actually called DataPortal object which abstracts you from the actual data layer. There is used direct access to database in this first article about CSLA.NET but you can use easily e.g. WCF, web services, .NET remoting etc. just by configuring your application.

Validation rules

#region Validation Rules

protected override void AddBusinessRules()
{
ValidationRules.AddRule(CommonRules.StringRequired, FirstNameProperty);
ValidationRules.AddRule(CommonRules.StringMaxLength,
new CommonRules.MaxLengthRuleArgs(FirstNameProperty, 50));

ValidationRules.AddRule(CommonRules.StringRequired, LastNameProperty);
ValidationRules.AddRule(CommonRules.StringMaxLength,
new CommonRules.MaxLengthRuleArgs(LastNameProperty, 50));
}
The big advantage of CSLA.NET is that object holds its own validation rules. In our case you can see that e.g. FirstName property is required and at maximum 50 characters long. You can specify any validation rules you need. Validation rules are check when the property is changed or by calling ValidationRules.CheckRules() manually.

Autorization rules

They allows to say who is able to read/write class properties and also who can create/edit/delete objects of specified type. There are no authorization rules specified in this first demo. If no rules are specified then it means that everyone can do everything.

Data access

#region Data Access

[RunLocal()]
protected override void DataPortal_Create()
{
LoadProperty(IdProperty, IdProperty.DefaultValue);
LoadProperty(FirstNameProperty, string.Empty);
LoadProperty(LastNameProperty, string.Empty);

ValidationRules.CheckRules();
}

private void DataPortal_Fetch(SingleCriteria criteria)
{
using (var ctx = ContextManager.GetManager(CSLADemo.DalLinq.Database.CSLADemo))
{
// get project data
var data = (from p in ctx.DataContext.Customers
where p.Id == criteria.Value
select p).Single();

LoadProperty(IdProperty, data.Id);
LoadProperty(FirstNameProperty, data.FirstName);
LoadProperty(LastNameProperty, data.LastName);

timestamp = data.LastChanged.ToArray();
}
}

[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Insert()
{
using (var ctx = ContextManager.GetManager(CSLADemo.DalLinq.Database.CSLADemo))
{
// insert project data
System.Data.Linq.Binary lastChanged = null;
int? newId = null;
ctx.DataContext.addCustomer(
ReadProperty(FirstNameProperty),
ReadProperty(LastNameProperty),
ref newId,
ref lastChanged);

timestamp = lastChanged.ToArray();
LoadProperty(IdProperty, newId);
// update child objects
FieldManager.UpdateChildren(this);
}
}

[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Update()
{
using (var ctx = ContextManager.GetManager(CSLADemo.DalLinq.Database.CSLADemo))
{
// insert project data
System.Data.Linq.Binary lastChanged = null;

ctx.DataContext.updateCustomer(
ReadProperty(IdProperty),
ReadProperty(FirstNameProperty),
ReadProperty(LastNameProperty),
timestamp,
ref lastChanged);

timestamp = lastChanged.ToArray();
// update child objects
FieldManager.UpdateChildren(this);
}
}

protected override void DataPortal_DeleteSelf()
{
DataPortal_Delete(new SingleCriteria(GetProperty(IdProperty)));
}

private void DataPortal_Delete(SingleCriteria criteria)
{
using (var ctx = ContextManager.GetManager(CSLADemo.DalLinq.Database.CSLADemo))
{
ctx.DataContext.deleteCustomer(criteria.Value);
}
}

#endregion
There can be overriden several BusinessBase method for data access. In our case there is used LINQ and stored procedures (instead of fetch method). You can see RunLocal attribute for DataPortal_Create method which means that when the business object is created e.g. by web service then it will not call web service but creates the object locally.
The other methods are quite standard but you can see another interesting feature of CSLA.NET and that's how it handles transactions. For you as developer it is enough to decorate method with Transactional attribute and method will run as transaction.

Conclusion

There is described how to create single business object in the article but you may be interested what to do after you create it. I think the best is to download source codes of the example and study them a bit. I have choosen win forms GUI for the application but the advantage of the CSLA.NET is that you can use same business objects with any interface you like (web, WPF).

Source code

Source codes are available here source code. Zip file should contain everything you need to build the source codes (VS 2008 solution, sql express example database, rebuilt SCLA.NET binaries). You only need to have installed VS 2008 SP1 and sql express database engine on your computer.

References

Monday 4 May 2009

NUnit 2.5.0 installation problem

I was trying to install NUnit msi package on my computer but the installer told me this: "Please wait while installer finishes determining your disk space requirements.". It hanged forever so I finished intallation. I thought some other running program probably blocks intallation for some reason. I tried to kill some running processes (IE 7.0, Firefox, MS Outlook) and run the installer again with success. I am not sure what exactly happened but it helped at least in my case.