25 Sample Web Application for .NET Clients

This chapter provides step-by-step instructions that explain how to create a simple Windows ASP.NET Web application that uses the Coherence for .NET library.

The following sections are included in this chapter:

25.1 Create an ASP.NET Project

To create an ASP.NET web application, follow these steps:

  1. Choose File->New->Web site in Visual Studio 2005.

  2. Under the "Templates", select "ASP.NET Web Site".

  3. Select the language that you are most familiar with.

  4. Select the location (type and full path) where you want to store your application.

Click the OK button to generate a new solution and empty ASP.NET application.

25.2 Add a Reference to the Coherence for .NET Library

To use the Coherence for .NET library in your .NET application, add a reference to the Coherence.dll library:

  1. In your project go to Project->Add Reference... or right click References in the Solution Explorer and choose Add Reference....

  2. In the Add Reference window that appears, choose the Browse tab and find the Coherence.dll library on your file system.

    Figure 25-1 Coherence.dll File in the Add Reference Window

    This figure is illustrated in the text.
  3. Click OK.

25.3 Configure the Web.config File

To correctly configure the Coherence for .NET library, you must configure the Web.config XML file with the appropriate file names for each configuration file used by the Coherence for .NET library. Example 25-1 illustrates a valid Web.config configuration file:

Example 25-1 Sample Web.config Configuration File

<?xml version="1.0"?>
      <section name="coherence" type="Tangosol.Config.CoherenceConfigHandler,
         Coherence, Version=, Culture=neutral,
      <globalization culture="en-US" uiCulture="en-US"/>
      <sessionState mode="Custom" customProvider="CoherenceSessionProvider"
            <add name="CoherenceSessionProvider"
               type="Tangosol.Web.CoherenceSessionStore, Coherence,
               Version=, Culture=neutral,
      <compilation debug="false" defaultLanguage="c#">
            <add assembly="System.Windows.Forms, Version=, Culture=neutral,
            <add assembly="Coherence, Version=, Culture=neutral,
      <authentication mode="Windows"/>
      <customErrors mode="Off"/>

In the <configSections> you must specify a class that handles access to the Coherence for .NET configuration section.

Elements within the Coherence for .NET configuration section are:

  • cache-factory-config—contains the path to a configuration descriptor used by the CacheFactory to configure the (IConfigurableCacheFactory and Logger) used by the CacheFactory.

  • cache-config—contains the path to a cache configuration descriptor which contains the cache configuration described earlier (see "Configuring Coherence*Extend on the Client"). This cache configuration descriptor is used by the DefaultConfigurableCacheFactory.

  • pof-config—contains the path to a configuration descriptor used by the ConfigurablePofContext to register custom types used by the application.

25.4 Create Coherence for .NET Configuration Files

Example 25-2 illustrates a sample coherence.xml configuration file:

Example 25-2 Sample coherence.xml Configuration File

<?xml version="1.0"?>

<coherence xmlns="http://schemas.tangosol.com/coherence"
      <message-format>{date} &lt;{level}&gt; (thread={thread}): {text}

Example 25-3 illustrates a sample cache-config.xml configuration file:

Example 25-3 Sample cache-config.xml Configuration File

<?xml version="1.0"?>

<cache-config xmlns="http://schemas.tangosol.com/cache"

Example 25-4illustrates a sample pof-config.xml configuration file:

Example 25-4 Sample pof-config.xml Configuration File

<?xml version="1.0"?>

<pof-config xmlns="http://schemas.tangosol.com/pof"
   <!-- include all "standard" Coherence POF user types -->
   <!-- include all application POF user types -->

Having creating these configuration files, everything is now in place to connect to a Coherence cluster and perform all operations supported by Coherence for .NET.

25.5 Create the Web Form

Switch to the Design tab for the Default.aspx page and from the Toolbox pane add the appropriate controls by dragging and dropping them on the page. You need TextBox controls for the Name, Street, City, State, and Zip fields and corresponding label controls for each. This is illustrated in Figure 25-2.

Figure 25-2 Adding Controls for the .aspx Page

This figure is illustrated in the text.

After placing them on the page, you should change the ID and Text property for each control. Labels are not used in the code; therefore, leave their ID property values as generated and put appropriate labels in the Text property. You should name the ID and TextBox controls txtName, txtStreet, and so on. Add one button and rename its ID to btnSave and Text property to Save. This is illustrated in Figure 25-3.

Figure 25-3 Changing IDs and Properties for Data Controls

This figure is illustrated in the text.

Add one button and rename its ID to btnClear and Text property to Clear. This is illustrated in Figure 25-4

Figure 25-4 Adding a "Clear" Button to the Application

This figure is illustrated in the text.

Add label and rename its ID to lblTotal. This label is used to display the cache size. Add a RequiredFieldValidator from the Validation list of controls on the Toolbox pane and set its properties. This is illustrated in Figure 25-5:

Figure 25-5 Adding a Field Validator and Setting its Properties

This figure is illustrated in the text.

Please note that ControlToValidate property is set to the txtName control.

From the Data list of controls on the Toolbox pane, add a GridView control and an ObjectDataSource (named dsContact). This is illustrated in Figure 25-6.

Figure 25-6 Adding a GridView Control and an ObjectDataSource

This figure is illustrated in the text.

Example 25-5 illustrates code for the GridView control source:

Example 25-5 Code for the GridView Data Control

<asp:GridView ID="gridCache" runat="server" DataSourceID="dsContact"
   AutoGenerateColumns="False" Font-Names="Verdana">
         <ItemStyle Font-Size="Small"/>
            <asp:HyperLink Text="[Remove]" ID="HyperLink1" runat="server"
               NavigateUrl='<%# "?removeKey=" + 
               DataBinder.Eval(Container.DataItem, "Name").ToString() %>'/>
      <asp:TemplateField HeaderText="Name">
         <HeaderStyle BackColor="#DCE7F7"/>
            <asp:HyperLink runat="server" NavigateUrl='<%# "?getKey=" + 
               DataBinder.Eval(Container.DataItem, "Name").ToString() %>'>
               <%# DataBinder.Eval(Container.DataItem, "Name") %>
      <asp:BoundField DataField="Street" HeaderText="Street">
         <HeaderStyle BackColor="#DCE7F7"/>
      <asp:BoundField DataField="City" HeaderText="City">
         <HeaderStyle BackColor="#DCE7F7"/>
      <asp:BoundField DataField="State" HeaderText="State">
         <HeaderStyle BackColor="#DCE7F7"/>
      <asp:BoundField DataField="Zip" HeaderText="Zip">
         <HeaderStyle BackColor="#DCE7F7"/>

Example 25-6 illustrates the ObjectDataSource code.

Example 25-6 ObjectDataSource Code

<asp:ObjectDataSource ID="dsContact" runat="server" SelectMethod="GetData"

Add a Search pane by dragging and dropping a few labels, one DropDownList for a filter column, and a TextBox for filter criteria. This is illustrated in Figure 25-7.

Figure 25-7 Search Pane

This figure is illustrated in the text.

25.6 Implement the Web Application

The following topics are included in this section:

25.6.1 Global.asax File

To free up resources in the cluster when your ASP.NET application terminates, you must call CacheFactory.Shutdown() within the Application_End event handler in Global.asax. Example 25-7 illustrates a Global.asax file and shows you how to do that, and also adds the call which redirects the user to an error page if an exception occurs.

Example 25-7 Redirecting a User to an Error Page

<%@ Application Language="C#" %>

<script runat="server">
    void Application_Start(object sender, EventArgs e)
        Application["contactCache"] = CacheFactory.GetCache("dist-contact-cache");

    void Application_End(object sender, EventArgs e)
        CacheFactory.Log("Application terminated.", CacheFactory.LogLevel.Info);
        INamedCache contactCache = Application["contactCache"] as INamedCache;
        if (contactCache != null)


    void Application_Error(object sender, EventArgs e)

25.6.2 Business Object Definition

Example 25-8 illustrates the definition of the ContactInfo business object.

Example 25-8 Sample Business Object Definition File

public class ContactInfo : IPortableObject
    private string name;
    private string street;
    private string city;
    private string state;
    private string zip;

    public ContactInfo()
    { }

    public ContactInfo(string name, string street, string city, string state, string zip)
        this.name   = name;
        this.street = street;
        this.city   = city;
        this.state  = state;
        this.zip    = zip;

    public void ReadExternal(IPofReader reader)
        name   = reader.ReadString(0);
        street = reader.ReadString(1);
        city   = reader.ReadString(2);
        state  = reader.ReadString(3);
        zip    = reader.ReadString(4);

    public void WriteExternal(IPofWriter writer)
        writer.WriteString(0, name);
        writer.WriteString(1, street);
        writer.WriteString(2, city);
        writer.WriteString(3, state);
        writer.WriteString(4, zip);

25.6.3 Service Layer Implementation

Example 25-9 illustrates a class that provides data to the data bind control. It must have a public GetData() method that returns an ICollection of data to the data bind control:

Example 25-9 Providing Data to the Data Bind Control

public class ContactInfoDataSource
    public ICollection Data
        set { m_col = value; }

    public ICollection GetData()
        return m_col;

    public ContactInfoDataSource()

    public ContactInfoDataSource(ICollection col)
        ArrayList results = new ArrayList();
        if (col is INamedCache)
            INamedCache cache = col as INamedCache;

            foreach (ContactInfo contactInfo in cache.Values)
        else if (col is ArrayList)
            foreach (DictionaryEntry entry in col)
        Data = results;

    private ICollection m_col = null;

25.6.4 Code-behind the ASP.NET Page

Add an event handler that creates an inner object that provide data to the data bind control. This is illustrated in Example 25-10.

Example 25-10 Event Handler to Provide Data to the Data Bind Control

protected void dsContact_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
    ContactInfoDataSource cds = new ContactInfoDataSource(Contacts == null ? ContactCache : Contacts);
    e.ObjectInstance = cds;

The method illustrated in Example 25-11 refreshes the GridView displayed on the page, refreshes the total label lblTotal, and makes the btnClear and all buttons visible if there are objects in the cache:

Example 25-11 Method to Refresh the Grid View

private void RefreshDataGridAndRenderPage()

    int totalObjects = (Contacts == null ? ContactCache.Count : Contacts.Count);
    lblTotal.Text = "Total objects: " + totalObjects;

    if (ContactCache.Count > 0)
        lblTotal.Visible = btnClear.Visible = true;
        lblSearch.Visible = listColumnNames.Visible = lblFor.Visible = txtFilterCriteria.Visible = btnSearch.Visible = true;
        lblTotal.Visible = btnClear.Visible = false;
        lblSearch.Visible = listColumnNames.Visible = lblFor.Visible = txtFilterCriteria.Visible = btnSearch.Visible = false;

    btnClearFilter.Visible = (Contacts != null);

The method illustrated in Example 25-12 handles page load events. If there is a getKey value in the Request, then the value mapped to the specified key in the cache is retrieved and the appropriate fields populated with its properties. If there is a removeKey value in the Request, the value mapped to the specified key is removed from the cache.

Example 25-12 Method to Handle Page Load Events

protected void Page_Load(object sender, EventArgs e)
    if (Request["getKey"] != null)
    else if (Request["removeKey"] != null)
        CacheFactory.Log("Object with key [" + Request["removeKey"] + "] has been removed from cache.", CacheFactory.LogLevel.Info);


The helper method illustrated in Example 25-13 retrieves an ContactInfo object from the cache by a specified key:

Example 25-13 Retrieving a Business Object from the Cache through a Specified Key

private void FindObjectInCache(object key)
    ContactInfo contactInfo = (ContactInfo)ContactCache[key];

    if (contactInfo == null)
        contactInfo = new ContactInfo();

    txtName.Text = key as String;
    txtStreet.Text = contactInfo.Street;
    txtCity.Text = contactInfo.City;
    txtState.Text = contactInfo.State;
    txtZip.Text = contactInfo.Zip;

Example 25-14 illustrates an the event handler for the btnSave button:

Example 25-14 Event Handler for a "Save" Button

protected void btnSave_Click(object sender, EventArgs e)
    String name = txtName.Text;

    if (name != null && name != "")
        ContactInfo contactInfo = new ContactInfo(name,
        ContactCache.Insert(name, contactInfo);

        CacheFactory.Log("Object with key [" + name + "] has been inserted into cache.", CacheFactory.LogLevel.Info);

Example 25-15 illustrates the event handler for the btnClear button:

Example 25-15 Event Handler for a :Clear" Button

protected void btnClear_Click(object sender, EventArgs e)
    NameValidator.Enabled = false;


    NameValidator.Enabled = true;

Example 25-16 illustrates the event handler for the btnSearch button:

Example 25-16 Event Handler for a "Search" Button

protected void btnSearch_Click(object sender, EventArgs e)
    NameValidator.Enabled = false;

    String filterBy = listColumnNames.Items[listColumnNames.SelectedIndex].Text;
    String filterCriteria = txtFilterCriteria.Text.Trim();

    if (filterCriteria != "")
        IValueExtractor extractor = new ReflectionExtractor("get" + filterBy);
        IFilter filter = new LikeFilter(extractor, filterCriteria, '\\', true);

        ICollection results = ContactCache.GetEntries(filter);

        Contacts = results;
        dsContact = new ObjectDataSource();


    NameValidator.Enabled = true;

Example 25-17 illustrates the event handler for the btnClearFilter button:

Example 25-17 Event Handler for a "Clear Filter" Button

protected void btnClearFilter_Click(object sender, EventArgs e)
    NameValidator.Enabled = false;

    Contacts = null;
    dsContact = new ObjectDataSource();

    NameValidator.Enabled = true;

Lastly, add an ConnectionError.html page to the project with an appropriate error message in it.