torstai 11. maaliskuuta 2010

ASP.NET and data binding done right

I remember myself earlier having lot's of trouble with ASP.NET and databinding. Especially with events when there was post backs involved. That's because I did it all wrong. Most of people do it all wrong, even guys at Microsoft are writing terrible samples. For example at this years TechEd 2010 at Helsinki I saw many ASP.NET demos done with shortcut way.

But how to do it right? Keep the aspx-page clean. If you need to display some alternative stuff for user add it all to aspx page and then bind the visibility of those controls to your business data. From the other way around don't put presentation code to codebehind. With that I mean don't for example toggle visibility of controls from codebehind. Bind the visibilities at aspx side and let data binding do it's job.

In this post I'll give you an example how to create very simple web application with data binding done right. In the beginning you need empty ASP.NET Web Application. I named it BindingDemo.

First thing is to add properties holding your data to codebehind class.
public partial class _Default : Page
{
    protected string LabelText { get; set; }
    ...
}

Second thing is to add some controls to aspx page. Here's the ASPX-page with label, textbox and button. Nothing special there. Note the data binding of Text property of label.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="BindingDemo._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Binding Demo</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:Label runat="server" Text='<%# LabelText %>' />
                <br />
                <asp:TextBox runat="server" ID="SourceText" />
                <asp:Button ID="ChangeTextButton" runat="server" 
                            Text="Change text" onclick="OnChangeText" />
            </div>
        </form>
    </body>
</html>
Third thing you need to do is to override OnDataBinding. It is called just before data binding occurs. That is the place where you get your latest data. In this example I just get stuff from session but you should propably get your data from database or something.
protected override void OnDataBinding(EventArgs e)
{
    LabelText = (string)Session[“Data”];
    base.OnDataBinding(e);
}
Last thing we want to do is to add some functionality to button. Here we are just going to store stuff to session for the sake of simplicity but in the real world you should propably store it to database.
protected void OnChangeText(object sender, EventArgs e) 
{
    Session[“Data”] = SourceText.Text;
    DataBind();
}
And that's it. Here you have very simple ASP.NET application with data binding done right. Just remember that to keep things simple you don't want to set any of controls' properties directly from code behind. Let the data binding do that always for you.

torstai 4. maaliskuuta 2010

When not to implement GetHashCode() or Equals()

This question raises time to time and there seems to be no clear answer. But after working with NHibernate for five years the simple answer is don't. Of course that answer is over simplification and doesn't take account all the scenarios. In this post I'm going through one scenario.


When objects are not shared between sessions do not implement

When you only have objects living during life-cycle of session let the session's first level cache handle instances. NHibernate's first level cache will make sure that there is only one instance of your entity for each identifier.

Let's first consider why we have identifier for entities anyway? This is because databases require some kind of unique identifier to separate rows from each other. The identifier is not required at your domain model because every instance of object has it's own internal identity that separates it from other instances. The requirement of identifiers comes from the fact that databases are not planned to store objects. My tip would be that if you ever require to access identifier property from your model you are doing something wrong. Identifier only exists because it is required by your database.

If you do implement GetHashCode or Equals you will get trouble when creating new unsaved entities. The most obvious way to implement GetHashCode or Equals would be by associating them with identifier. But what happens when you create two new instances? If you use automatic identity generation provided by database those entities will have uninitialized identifiers until you save them for first time.

When you don't implement GetHashCode and Equals everything will work just fine as long as entities are not share between sessions. From the point of view of your model the identifiers don't exists. Actually I wonder why NHibernate don't just generate identifier properties on-fly when it generate proxies.