Thursday, October 13, 2005
« A CSLA .NET 2.0 style class | Main | My PodcastStudio.net interview is online... »

ASP.NET 2.0 has bi-directional data binding, which is a big step forward. This means you can bind the UI to a data source (DataTable, object, etc.) and not only display the data, but allow the user to do “in-place” editing that updates the data source when the page is posted back.

 

The end result is very cool, since it radically reduces the amount of code required for many common data-oriented web pages.

 

Unfortunately the data binding implementation isn’t very flexible when it comes to objects. The base assumption is that “objects” aren’t intelligent. In fact, the assumption is that you are binding to “data objects” – commonly known as Data Transfer Objects or DTOs. They have properties, but no logic.

 

In my case I’m working with CSLA .NET 2.0 objects – and they do have logic. Lots of it, validation, authorization and so forth. They are “real” objects in that they are behavior-based, not data-based. And this causes a bit of an issue.

 

There are two key constraints that are problematic.

 

First, ASP.NET insists on creating instances of your objects at will – using a default constructor. CSLA .NET follows a factory method model where objects are always created through a factory method, providing for more control, abstraction and flexibility in object design.

 

Second, when updating data (the user has edited existing data and clicked Update), ASP.NET creates an instance of your object, sets its properties and calls an Update method. CSLA .NET objects are aware of whether they are new or old – whether they contain a primary key value that matches a value in the database or not. This means that the object knows whether to do an INSERT or UPDATE automatically. But when a CSLA .NET object is created out of thin air it obviously thinks it is new – yet in the ASP.NET case the object is actually old, but has no way of knowing that.

 

The easiest way to overcome the first problem is to make business objects have a public default constructor. Then they play nicely with ASP.NET data binding. The drawback to this is that anyone can then bypass the factory methods and incorrectly create the objects with the New keyword. That is very sad, since it means your object design can’t count on being created the correct way, and a developer consuming the object might use the New keyword rather than the factory method and really mess things up. Yet at present this is how I’m solving issue number one.

 

I am currently solving issue number two through an overloaded Save method in BusinessBase: Save(forceUpdate) where forceUpdate is a Boolean. Set it to True and the business object forces its IsNew flag to False, thus ensuring that an update operation occurs as desired. This solution works wonderfully for the web scenario, but again opens up the door to abuse in other settings. Yet again a consumer of the object could introduce bugs into their app by calling this overload when it isn’t appropriate.

 

The only way out of this mess that I can see is to create my own ASP.NET data control that understands how CSLA .NET objects work. I haven’t really researched that yet, so I don’t know how complex it is to write such a control. I did try to subclass the current Object control, but they don’t provide extensibility points like I need, so that doesn’t work. The only answer is probably to subclass the base data control class itself…

Thursday, October 13, 2005 10:16:13 PM (Central Standard Time, UTC-06:00)
Rocky,
I have used Rick Strahl's 2-way databinding controls in ASP.Net 1.1 using CSLA BOs. They subclass the asp controls and add properties for the BO data source and BO Property to set. They use reflection to accomplish this bit of magic.

They can be found in his web store app at:
http://www.west-wind.com/westwindwebstore/

Joe



Joe Fallon
Thursday, October 13, 2005 11:47:26 PM (Central Standard Time, UTC-06:00)
Hi. I was reading the section in chapter 2 only last night in which you cover the factory calls. I was interested to see that is such a strong emphasis on these factory calls; the reason for which I have not yet come across but I think it has something to do with the nature of distributed business objects.

I have previously worked with a fairly mature inhouse .NET ORM/Framework. Rather then having the CRUD (CFUD - in your case) factory methods they had three constructors for each object; a default constructor; a constructor that would accept all of the attributes/properties of the object except the Primary key (or in your case the Criteria) which would represent a new object; and a constructor that would accept all of the attributes/properties of the object and also the primary key (Criteria) which would represent an existing object. The Save() and Delete() methods were non-static methods defined as abstract in the equivalent of your BusinessBase class. The objects would also provide a static delete too that would accept a primary key (Criteria). An object could be created either through its constructor by passing in the relevant arguments or by using the default constructor and then accessing the public properties. The former method was ideal when another tier/object was subclassing the object in question since in the subclassed object's constructor you could flick pass the arguments to the constructor of the parent object and the later was ideal for user interfacing plumbing and business logic processing.

To quote your post "...objects are always created through a factory method, providing for more control, abstraction and flexibility in object design." In your book I have not seen where this provides any benefit over the technique that I described above. Maybe I have not found it yet. Maybe this justification could be fleshed out a bit in the next book?

I fear that you maybe painting yourself into a corner with the factory methods. Would it be such a problem to have two ways of creating an object? You could argue that it is a 'form' of overloading (?!)

The factory methods also 'feel' a bit out of place .Net. When dealing with most objects in the .Net Framework they do not offer factory methods. I understand that these objects are not being saved to a database but novice programmers are used to the new method to get an object. While doing training I would find it uncomfortable to be asked "why don't we use the 'new' keyword to create an Invoice object like we do for other objects?". The answer would have to be "... because this object is being saved the database" (?) A trainee would be justified to then ask "why should we make a distinction between whether the object is stored in the database or not. I want to interface with the object in syntax like we were taught to interface with ArrayList() or System.Net.Socket()."

I am really excited about the bi-directional data binding in ASP.NET 2.0. I did not know that it existing prior to your post. This should make things a lot simpler. Good luck with the book too.

Regards
Dave A
Dave A
Friday, October 14, 2005 2:30:13 AM (Central Standard Time, UTC-06:00)
I'm going through the same misery with llblgen pro v2.0 development. :/

Especially the change tracking issue is huge. Not only that, design time databinding is a pain as well. In .NET 1.x, you at least had the oppertunity to drag a collection onto a webform, design the grid and be done with it. Now you need to write your own objectdatasource class, with 4 CRUD methods.

For the dataset users, it's ok, but for people who think out of the box, it's a pain. What frustrates me the most is that after all those years, Microsoft still plays the same databinding trick-card and it's getting old: use our tech and you're fine, use someone else's tech, and you're in for a lot of trouble.

Why don't they take a step back, THINK for once into generic constructs and design a system which is extensible easily and works the same, with the same ease, with normal objects as well...

And then I haven't even started about the stupidity in .NET 2.0 where you have to support two completely distinct methods of databinding: one for winforms, and one for webforms.
Friday, October 14, 2005 2:45:26 AM (Central Standard Time, UTC-06:00)
Rocky, this link (and the other articles there) might help you implement the datasource control, it seems to look like the proper way.
http://www.nikhilk.net/DataSourceControlsDesignTime.aspx
Friday, October 14, 2005 8:12:05 AM (Central Standard Time, UTC-06:00)
Thank you Frans, I appreciate the link.

I should point out too, that Windows Forms data binding works great with CSLA .NET. The Windows Forms team really worked hard to make sure that their binding scheme was flexible and accomodated a wide range of object designs. Too bad the ASP.NET team didn't follow suit...
Friday, October 14, 2005 8:49:58 AM (Central Standard Time, UTC-06:00)
Yeah winforms binding went along fine, after I removed ICustomTypeDescriptor from the objects, which I had put there for ASP.NET 1.x databinding... An object with ICustomTypeDescriptor won't work at design time when you chose it for a binding source...
Friday, October 14, 2005 9:09:13 PM (Central Standard Time, UTC-06:00)
I had similar issues with hierarchical datasets (http://weblogs.asp.net/aaguiar/archive/2005/09/19/425518.aspx). Writing a new DataSource is the way to go.

I built one to bind to a DataSet that needs to be stored somewhere after reading it, to be able to apply the changes to the instance that was loaded and use the DataSet change-tracking features. In the datasource you can decide to keep the instance in the session or in the viewstate (or wherever you want).

My implementation is now coupled with the business logic components that we generate but I'll decouple them and post my 'DatasetDataSource' source code in a couple of weeks...



Tuesday, October 18, 2005 7:29:25 AM (Central Standard Time, UTC-06:00)
I applaud your energy and committment to bringing the empty promised land of databinding to Microsoft's attention.

I have wasted more time and energy looking at databinding than any other technology in the last 15 years. Each time it looks great until you are about 3/4's of the way through a project and BOOM it falls flat on it's face. I don't know if I have the energy to do it again...

It still seems to me that when all is said and done that the quickest way is to do it by hand.
Jay Pondy
Friday, October 28, 2005 5:31:52 PM (Central Standard Time, UTC-06:00)
Hey Rocky,

The new and improved databinding in ASP.NET doesn't seem like much of an improvement to me. Yeah sure you can do two way binding but it's so non-deterministic and as you point out for using business objects that don't follow the ObjectDataSource rules (which seem silly - building bus objects just so it can work with a UI component???).

I think the best way to deal with this is still by creating custom UI controls that support databinding properly or take a similar approach that WinForms is using with a binding manager object. That doesn't help you much for a generic framework but then again a bus framework really shouldn't dabble with the UI anyway...

I'm pretty happy with the control based databinding approach I've been using:

http://www.west-wind.com/presentations/aspnetdatabinding/aspnetdatabinding.asp

mainly because it works with most common data structures and more importantly is very easy to set up when you configure your controls. Databinding more than anything needs to be easy to use and ASP.NET's control databinding mechansim is not... Even more important, ASP.NET doesn't give you any useful control on when databinding occurs - in many cases the binding will occur at the wrong time and if it does there's nothing you can do but write manual update code.



Saturday, October 29, 2005 6:28:05 PM (Central Standard Time, UTC-06:00)
some more databinding approaches - that avoid having to sub class all your controls...
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/aspformbinding.asp
http://www.codeproject.com/aspnet/ASPNetTwoWayDataBinding.asp
http://www.codeproject.com/aspnet/manubindingmanager.asp

cheers JB
JB
Saturday, October 29, 2005 11:56:39 PM (Central Standard Time, UTC-06:00)
...and another view point that basically slams ASP.NET Databinding fairly succinctly:
http://weblogs.asp.net/aaguiar/archive/2005/09/19/425518.aspx
JB
JB
Friday, November 11, 2005 5:32:49 PM (Central Standard Time, UTC-06:00)
Ok, here is my opinion on this. Let's say you want to use new Microsoft controls and let's say you don't want to change your objects, right? Sounds a little bit crazy, BUT....

What about creating a Controller class that will accomodate the new binding paradigm and will interact with your business library. I'm creating a sample on this, and so far is promising. Now, the first thing I'm going to hear is that, it's is more code, and I agree, but I'm hoping to get to the point to be able to generate this controller class with CodeSmith (or any other), the key will be to understand very well the paradigm behind the new databinding controls and some how generate that, because I'm sure is going to be a lot of repetitive code.

Here is a little code, againg this is a quick test a made to bind a Customer object to a Form View and still control the instance of my object....

public class CustomerProfileController
{
private const string CURRENT_PROFILE = "CurrentProfile";
public CustomerProfileController()
{
}
public static void EditCustomer(decimal customerNumber)
{
HttpContext.Current.Session[CURRENT_PROFILE] = Customer.GetCustomer(customerNumber);
HttpContext.Current.Response.Redirect("Customer_Edit.aspx");
}
public static Customer GetCustomer()
{
return HttpContext.Current.Session[CURRENT_PROFILE] as Customer;
}
}

I'm actually storing a Customer object instance in session state, but if you don't like that, that's fine, that's not my point.


This controller class is used by another page named Customer_List.aspx which calls the controller to load the customer profile, then Customer_Edit.aspx is using an ObjectDataSource bind to the controller, and it's using the GetCustomer() method ....


asp:ObjectDataSource ID="CustomerDataSource" runat="server" SelectMethod="GetCustomer"
TypeName="CustomerProfileController"


Comments?
Mr.Underhill
Sunday, December 04, 2005 10:51:13 AM (Central Standard Time, UTC-06:00)
For what it is worth, I do now have a working CslaDataSource control. This makes Web Forms data binding work quite reasonably with CSLA .NET business objects. Compared to ASP.NET 1.1, there is substantial code savings and the code you write is simpler and more standardized.
Wednesday, December 07, 2005 7:58:35 AM (Central Standard Time, UTC-06:00)
On a related problem/question, I have been trying to figure out how to bind complex objects to a GridView. For example, a Company object that contains a PostalAddres object which has properties for Address1, City, State, etc. Are your business objects all "flat" or are they complex? If they are complex how are you binding the child object properties?
Chris Pels
Friday, February 10, 2006 6:32:35 AM (Central Standard Time, UTC-06:00)
DaveA asked a valid question a while ago which I just stumpled upon. I feel it is very important for new developers (or new to patterns and practices) to understand the 'why'.

DaveA, the factory approach is explained here:
http://www.dofactory.com/Patterns/PatternFactory.aspx

In fact there are several other development patterns explained very well there. The factory methodology is not necessarily the correct implementation for your scenario. It depends on your team dynamic and your development process. There are many camps for design patterns and they are equally represented on dofactory.com, please be sure to understand several design patterns before choosing one for your team.
DS
Thursday, March 23, 2006 10:42:21 AM (Central Standard Time, UTC-06:00)
What about using this approach
protected void ObjectDataSource1_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
e.ObjectInstance = // call to factory method here;
}
Mike Hay
Comments are closed.