Creating DataModule-like components in .NET

Delphi’s DataModules were a useful programming tool because they provided a centralized place to define data schema and business logic which could then be referenced from multiple locations. Visual Studio .NET, however, encourages the programmer to place DataSets and Adapters on each individual page, resulting in decentralized and possibly redundant business logic. However, it is possible to roll your own DataModule-like components in .NET. Here’s how:

  1. Decide whether you want to have your custom DataSet component in the same project or in a class library. Keeping it in the same project is a little simpler, while putting it in a separate class library will result in a separate assembly that contains only data logic, making it more suitable to deploy as a business tier.
  2. Add a new Component to the target project 
  3. Add a Connection and DataAdapters to the Component, and generate a DataSet. The visibility of the Connection and DataAdapters will default to private, so make sure to change them as appropriate for your design.
  4. Once the DataSet has been generated, create a new class that descends from the DataSet subclass. The DataSet subclass name is the same as the name of the .xsd schema file.
  5. Add the following attributes to your DataSet subclass:
    1. [ Serializable() ]
    2. [ System.ComponentModel.ToolboxItem( true ) ]
  6. Add a property to the DataSet subclass that references the Component containing all the DataAdapters. Include logic either in the DataSet subclass constructor or in the property accessor to create a new instance of the DataAdapter container if needed.
  7. Optionally, to hide the base DataSet class, open the base .cs file with the same name as the schema .xsd file and change the ToolboxItem attribute from true to false. Changes made to this file will disappear every time the .xsd it is based on changes, so make the decision whether or not this step is worthwhile accordingly.
  8. Build the project
  9. You can now add the custom DataSet class to the Toolbar. When dragged into another project, the Visual Studio IDE will treat the DataSet subclass as if it is a DataSet; it will appear as a top-level item in the DataBinding dialog box and have the DataSet property editor. Additionally, all the custom business logic methods you added to the class will also be available in code. The DataSet schema will only be editable in the project containing the DataSet subclass, which is a natural result of centralizing your schema and logic. Be forewarned that adding such a custom DataSet to the Toolbar while it is still in development might cause more frustration than it’s worth, since Visual Studio will not be easily persuaded to detect changes to the DataSet schema, particularly in the designer.

Sample Code

using System;

namespace MyNamespace.MyDataModules
{

  [ Serializable() ]
  [ System.ComponentModel.ToolboxItem( true ) ]
// MyStronglyTypedDataSet is the name of the DataSet class
// automatically generated by Visual Studio .NET
public class CustomDataSet : MyStronglyTypedDataSet
  {

// CustomDataSetAdapters is the name of the Component class

// containing all the DataAdapters used to generate, fill,

// and update the DataSet.

private CustomDataSetAdapters _Adapters;
private System.ComponentModel.Container components = null;
public CustomDataSet( System.ComponentModel.IContainer container )
    {
      container.Add( this );
      InitializeComponent();
// Initialize DataSet properties here

_Adapters = new CustomDataSetAdapters( container );
    }
public CustomDataSet()
    {
// Initialize DataSet properties here

­_Adapters = new CustomDataSetAdapters();
    }
protected override void Dispose( bool disposing )
    {
if ( disposing )
      {
if ( components != null )
        {
          components.Dispose();
        }
      }
base.Dispose( disposing );
    }

// This property exposes the component class containing

// all the DataAdapters used to generate, fill, and update

// the DataSet

public CustomDataSetAdapters Adapters

{

get

{

return _Adapters;

}

}
public void BusinessLogicMethod1()
    {
// Custom business logic here
    }
  }
}

Struts: J2EE Design Strategies

Struts is a web application framework created as part of the Jakarta project at Apache. As such, it handles 35 – 40% of the plumbing code required to create clean Model2 web applications. Because it is an open source project, you can download it and start using it from http://jakarta.apache.org/struts/. For this session, I am covering the Struts setup, the controller servlet, form handling, custom tags, and internationalization, which only scrapes the top of the Struts iceberg.

To set up Struts, you must download Struts and place the struts.jar file in a location where it can be loaded by the servlet engine (in other words, it must be on the classpath for the servlet engine). As an alternative, you can place the JAR file in the web application’s lib directory, where the servlet engine will automatically load it. Next, if you plan to use any of the Struts custom tags, the .TLD files for the libraries you are using should be placed in your application’s WEB-INF directory (more about what the custom tag libraries do for you later). Next, you need to make some modifications to the WEB.XML file for your application. The changes required are shown in this listing.

Listing 5: Web.xml entries for Struts

<servlet>
      <servlet-name>action</servlet-name>
      <servlet-class>
        org.apache.struts.action.ActionServlet
      </servlet-class>
      <init-param>
        <param-name>config</param-name>
        <param-value>
          /WEB-INF/struts-config.xml
        </param-value>
      </init-param>
      <init-param>
        <param-name>debug</param-name>
        <param-value>2</param-value>
      </init-param>
      <init-param>
        <param-name>mapping</param-name>
        <param-value>
      org.apache.struts.action.RequestActionMapping
        </param-value>
      </init-param>
      <load-on-startup>2</load-on-startup>
    </servlet>
 
    <servlet-mapping>
     <servlet-name>action</servlet-name>
     <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    <taglib>
      <taglib-uri>
        /WEB-INF/struts-bean.tld
      </taglib-uri>
      <taglib-location>
        /WEB-INF/struts-bean.tld
      </taglib-location>
    </taglib>
    <taglib>
      <taglib-uri>
        /WEB-INF/struts-html.tld
      </taglib-uri>
      <taglib-location>
        /WEB-INF/struts-html.tld
      </taglib-location>
    </taglib>
    <taglib>
      <taglib-uri>
        /WEB-INF/struts-logic.tld
      </taglib-uri>
      <taglib-location>
        /WEB-INF/struts-logic.tld
      </taglib-location>
    </taglib>
    <taglib>
      <taglib-uri>
        /WEB-INF/struts-template.tld
      </taglib-uri>
      <taglib-location>
        /WEB-INF/struts-template.tld
      </taglib-location>
    </taglib>

The first entry registers the Struts ActionServlet. This is the single point of entry for the application. Basically, the Struts developers have already written the only controller you will need. More about exactly what it does in a moment. Several initialization parameters are passed to the controller servlet. The first specifies where to find the struts-config.xml document. This is the mapping document used by the controller. The second parameter specifies the debug level – the higher the number, the more debugging information is sent to the servlet engine log file. The third parameter is the mapping value. This points to the class responsible for handling RequestActionMapping (more about this later as well). Last, the load-on-startup tag ensures that the servlet engine loads the Struts controller as it starts up. This saves time on the first invocation of the servlet by pre-loading it in memory. The number passed here isn’t particularly important (unless you have some dependent startup classes that depend on the controller being in memory – if so, make sure the controller servlet has a lower number).

The next entry in the WEB.XML file specifies how you want to let the servlet engine know that a Struts resource has been requested (as opposed to some other content from the web site). There are two ways to handle this: prefix mapping or extension mapping. With prefix mapping, every resource that appears after a certain prefix will be sent to the Struts controller. This is the way that servlet engines specify that a servlet has been requested (the servlet resource always appears after a "/servlet" prefix). The other alternative (which we are using here) maps all resource with a particular extension to the Struts controller. This works fine as long as you pick an extension that doesn’t interfere with any other registered file type. In this case, we are mapping all requests that end with "Do" to the Struts controller. The "Do" extension is arbitrary (it implies that a resource will "do" something), but is the one used by all the Struts examples so it is a bit of a Struts standard. The remaining additions to the WEB.XML file specify the locations of the .TLD files for the custom Struts tags. Obviously, you only have to list the tag libraries you are using for this application (although it doesn’t hurt to list all six).

The next configuration item needed for the web application is the struts-config.xml document. A sample version of this document is shown here.

Listing 6: A simple struts.config XML document

<struts-config>
    <form-beans>
        <form-bean
            name="addItem"
            type="schedule.ScheduleItem" />
    </form-beans>
    <action-mappings>
        <action
            path="/sched"
            type="schedule.ViewScheduleAction" />
        <action
            path="/schedEntry"
            type="schedule.ScheduleEntryAction" />
        <action
            path="/add"
            type="schedule.AddToScheduleAction"
            name="addItem"
            input="/ScheduleEntryView.jsp"
            validate="true" />
    </action-mappings>
</struts-config>

It contains all the mappings for the controller servlet. In other words, these are the names of the resources you can request from the web application. To understand these mappings, a discussion of Struts actions is in order.

A classic problem in software engineering is how to handle a large number of mutually exclusive choices gracefully. This same problem popped up above, when we were talking about how to create a single point of entry controller. The naïve approach creates a huge switch statement or a long cascading series of if…else statements. However, a design pattern called Command exists to solve this problem nicely. The command design pattern uses inheritance instead of decisions to handle the various possibilities. Typically, the developer creates an abstract class with a method called "execute()", which has no code. Then, all the different possible actions subclass the abstract class and add concrete code to the execute() method. The mapping then becomes the name of the class to instantiate. This pattern makes it easy to keep a list of all the commands (because they all have a common ancestor) and iterate through it. This is the pattern used by Struts to handle the request mappings.

In Struts, you never need to create a controller servlet – the Struts developers have already created it for you. Instead, you create subclasses of the Struts Action class (org.apache.struts.action.Action). These action subclasses map to a particular resource, and this is one of the items in the struts-config document. When a request comes into the controller servlet, it matches the name of the request (notice that the mapping name in the config file does not include the struts specific extension, in our case "Do) and instantiates an instance of the appropriate action class. This means that the controller servlet never has to change to add new actions to the web application. All that is required is the new action classes and an updated config file. Your action class takes on the role of the controller in the traditional Model2 architecture. In other words, it creates the bean (or beans) necessary to do work, calls methods on them, adds them to a collection, then forwards them to the appropriate display resource (typically a JSP). The following listing shows a typical small Action subclass.

Listing 7: A small Action subclass

package com.nealford.art.schedstruts.action;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import com.nealford.art.schedstruts.boundary.ScheduleDb;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class ViewScheduleAction extends Action {
    private static final String ERR_POPULATE = "SQL error: can't populate dataset";
    public ActionForward execute(ActionMapping mapping,
                                 ActionForm form,
                                 HttpServletRequest request,
                                 HttpServletResponse response) throws
            IOException,
            ServletException {
        DataSource dataSource = getDataSource(request);
        ScheduleDb sb = new ScheduleDb();
        sb.setDataSource(dataSource);
        try {
            sb.populate();
        } catch (SQLException sqlx) {
            System.out.println(sqlx);
            getServlet().getServletContext().log(ERR_POPULATE, sqlx);
        }
        request.setAttribute("scheduleBean", sb);
        return mapping.findForward("success");
    }
}

As the listing shows, the first step is to create a model bean. In this application, the ScheduleBean encapsulates a connection to the database to get scheduling information. The Action creates an instance of the schedule bean, populates it, and passes it to the display JSP through the ActionForward class in Struts. This class is a convenience class created to make it easy to forward to other resources. Notice in the config document that the "sched" action is mapped to this action class. Thus, when the user requests "sched.do", the controller servlet instantiates the ViewScheduleAction class and calls its perform() method, which does the actual work. The JSP is shown here.

Listing 8: The View JSP

<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html>
<head>
<title>
<bean:message key="title.view" />
</title></head>
<body>
<h2><bean:message key="prompt.listTitle" /></h2></p>
<table border="2">
<tr bgcolor="yellow">
<th><bean:message key="prompt.start" /></th>
<th><bean:message key="prompt.duration" /></th>
<th><bean:message key="prompt.text" /></th>
<th><bean:message key="prompt.eventType" /></th>
</tr>
<logic:iterate id="schedItem"
type="com.nealford.art.schedstruts.entity.ScheduleItem"
name="scheduleBean" property="list" >
<tr>
<td><bean:write name="schedItem" property="start" />
<td><bean:write name="schedItem"
 property="duration" />
 <td><bean:write name="schedItem" property="text" />
<td><bean:write name="schedItem"
property="eventType" />
</tr>
</logic:iterate>
</table>
<p>
<a href="schedEntry.do"> Add New Schedule Item</a>
</body>
</html>

The JSP pulls the scheduleBean from the request collection (where the action class placed it) and also creates another object of page scope. The main thrust of this page is to show the schedule items from the database in an HTML table. To that end, the scheduleBean has a method that returns a java.util.List of ScheduleItem objects, which encapsulate the details of a single record. It would be easy enough here to create scriptlet code in the JSP to iterate over that collection. However, one of the stated goals of using this architecture is to remove Java code from the display. This is easily facilitated via one of the custom tags created by Struts. The ScheduleView JSP uses the Struts iterate tag. This is a powerful custom tag that can iterate over any array or collection. The "id" specifies what the local name of the object pulled from the collection will be. The "type" specifies what class the object pulled from the collection will be cast as, and the "collection" is a JSP expression specifying the collection itself. Within the body of the tag, you can use the "id" field to access any of the items from the collection without worrying about type casting – the tag has already done that for you. To summarize, the iterate tag iterates over the collection, pulling each object out one at a time, casting it to the type specified and assigning it to the variable name specified in "id". The user can use this variable to call any of the methods of the objects in the collection. Obviously, this is meant to be used on homogeneous collections (or at least collections that contain objects with a common super class).

As you can see, Struts makes is quite easy to build well designed web applications. It also leverages several well-known design patterns (such as the Command pattern).

.NET on Linux: C# Development with Mono and Glade, Part II

Now that you have a window you need to ensure that it will close properly. This involves making a single call to the Gnome API function named Application.Quit when the window is closed. If you don’t respond to the closing of the window, then the application will not exit properly. In particular, the application will remain in memory, even though the main window is closed. This might seem strange at first. However, if you think about it for one second, it makes sense. The window is being closed, but the act of closing a window is not really the same thing as exiting the application. So we need to respond to the closing of the main window in an application by also quitting or exiting the application itself. This section and the next explain how this process works.

The trick, of course, is knowing when the window is being closed. Fortunately GTK can send you something called a delete_event signal when the window is being closed. If you are Delphi programmer, you are probably used to thinking in terms of events, rather than signals. This is just a matter of terminology. A signal is the same thing as an event. A delete_event is associated only with windows; there is no delete_event sent when controls are destroyed. Instead, controls emit destroy events.

As mentioned above, in GTK terminology, an event is called a signal. Turn to the signals page in the property inspector, click on the Signal ellipses button and hunt for the delete_event. After selecting it, type in the name of its handler. This name, which you can make up, will be the name of the corresponding routine in your source code that will handle this event. In this case, the handler will be called MyWindowDeleteEvent.

After selecting the delete_event from the Signal ellipses button, I have typed in the name of the event handler, which in this case is called MyWindowDeleteEvent.

Let’s take a moment to make sure you understand what is going on here. The control we are working with, which happens to be a window called myWindow, automatically emits an event when it is closed. For instance, if the user selects the X in the upper right hand corner of this window at run time, then the delete_event will be fired. The developer then needs to trap this event and respond to it. One typically traps an event by writing a method that will be called automatically when the event is fired. In this case, we are making a contract, promising that we will create a method called MyWindowDeleteEvent, that will have the right signature, that is, it will accept the parameters that the delete event passes when it is fired. If we fulfill our half of the contract, then the method will be called automatically.

After setting up your event handler in Glade, you should press the Add button. This will add the event to the window.

The event, or signal, has been added to the window by filling out the dialog  and then pressing the Add button.

You can now choose the Save button in the main Glade window to write your project to disk. Give your project an appropriate name, such as GtkStart05. After saving the project, and assuming you use the proposed naming scheme, you will find two files on disk generated by Glade: GtkStart05.glade and GtkStart05.gladed. The first file uses XML syntax to describe the window and signals you created. In the next section of this article you will learn how to automatically parse this file and then automatically create the controls and signals you defined. This entire process can be done with two, short, simple, lines of code. The second generated file, the one that ends in gladed, is a project file. The Glade development environment uses this XML file to manage your project.

Writing Version 0.5 Of Our Program

We have now used Glade to create a main window, and have ensured that it will fire off an event when the window is closed. The next step is to write source code that will create an application, create the main window, display the window, and respond properly when the user closes the main window. In our case, the proper response to closing the main window is to close the application itself.

If we were working in C, C++ or Ada, then Glade could create the source code we need automatically. This is similar, though not identical, to the process in Delphi or Visual Studio, where the code for the application is not only created, but integrated into the same tool set as the visual designer. In particular, you can choose Project | Options from the Glade main window, and select whether you want to generate C, C++ or Ada code. After making your choice, you can press the Build button on the Glade main window to generate the actual source code. Note that the Build button does not compile or link your source, it only generates the files you need to compile your program. If you are creating a C program, you can then go to the command line, run the script called autogen.sh, and the make files for your system will be created automatically. Then type make at the shell prompt and your project will be automatically compiled. I should add that there are tools in other languages, such as Python, Perl and Ruby, that will read a file like GtkStart05.glade and then automatically generate the needed source code to create the windows described in it.

But in this case we are not working in C, C++, Python or Ada, and so we need to write code by hand in a text editor. Fortunately, that process is simple, since the required code is brief and easy to understand. It is shown in Listing 1. The code to compile and link the project is shown in Listing 2. To run the project, type mono gtkstart05.exe. If all has gone well, you should compile cleanly with no errors or warnings. When you run the project, a plain window should appear, as shown in Figure 7. When you close the main window, you should be taken back to your shell prompt. If the window disappears, but you are not taken back to the prompt, then something is wrong with your signal handler. You can, however, still press Ctrl-C or Ctrl-D to end the application and return to the shell prompt.

The simple, empty window that is created after we compile our source to create gtkstart05.exe, and then run that binary file from the command line by typing mono gtkstart05.exe.

Listing 1: The source code for version 0.5 of our simple introductory application.

namespace GtkStart
{
        using System;
        using Gtk;
        using Gnome;
        using Glade;
        using GtkSharp;
        public class GtkStart05
        {
                public static void Main (string[] args)
                {
                        new GtkStart05(args);
                }
                public GtkStart05(string[] args) 
                {
                        Application.Init();
                        /* Load the Glade xml file */
                        Glade.XML gxml = new Glade.XML ("gtkstart05.glade", "myWindow", null);
                        gxml.Autoconnect (this);
                        Application.Run();
                }
                /* Fulfill the contract we made in Glade to create a signal handler */
                public void MyWindowDeleteEvent (object o, DeleteEventArgs args) 
                {
                        Application.Quit ();
                        args.RetVal = true;
                }
        }
}

Listing 2: Code to compile the project. Note that a path is temporarily defined pointing to the default location for the gtk-sharp libraries.

export MONO_PATH=/usr/lib/mono/gtk-sharp/
mcs /unsafe -r gtk-sharp.dll -r glade-sharp.dll -r gnome-sharp.dll gtkstart05.cs
export MONO_PATH=

The code shown in Listing 1 has a Main method that creates an instance of the GtkStart05 class, just as you would in any normal C# or Java application. The constructor begins by calling the predefined Application.Init routine from the GTK API. Needless to say, the purpose of this routine is to initialize your GTK based application.

The next line of code loads in the XML file that you created in Glade. Note that we have optionally chosen to pass in the name of a specific object, namely myWindow. The Glade API uses this window name to know which part of the XML file it is going to parse. If you don’t pass in any name, then it parses the whole file.

Note that Application.Init is part of GTK#, while Glade.XML is part of the Glade API, or more particularly, it is part of libglade. It is worth taking a moment to think about libglade. It is possible to create GTK widgets by hand. In other words, you don’t have to parse an XML file in order to create a window or a button when using GTK. Instead, you can create these controls by hand by writing code. Code of this type, that is code not based on XML, is generated when you push the Build button in the Glade main window. What libglade does is provide routines that parse the XML and automatically create the controls you want to access. The great advantage of this system is that it at least partially separates your user interface code, which is defined in XML, from the rest of your source code, which is written in C#. Of course, the separation is not complete, since some of your user interface code, such as event handlers, are in your hand written source code. But this system will allow you to regenerate the interface with Glade without overwriting any of the code in your source.

The libglade API’s and its related programming philosophy are described in depth at this URL:

http://developer.gnome.org/doc/API/libglade/libglade-notes.html

After creating an instance of type Glade.XML, the next step is to call Autoconnect.

 Glade.XML gxml = new Glade.XML ("gtkstart05.glade", "myWindow", null);
 gxml.Autoconnect (this);

The call to Autoconnect hooks up the signals defined in the XML file to the event handler you have defined in your file. In other words, it focuses on this bit of XML from gtkstart05.glade:

<signal name="delete_event" 
 handler="MyWindowDeleteEvent" 
 last_modification_time="Thu, 18 Nov 2004 17:42:01 GMT"/>

It then hooks that XML encoded signal up to this signal handler from Listing 1:

public void MyWindowDeleteEvent (object o, DeleteEventArgs args) 
{
  Application.Quit ();
  args.RetVal = true;
}

In this code, note the call to Application.Quit. Needless to say, this call closes the application. It ends the application process and takes the user back to the shell prompt, or the GUI desktop. The signal handler is written in order to provide a place to make this call. In other words, the program responds to the delete_event so that it can make this call, and thereby smoothly end the program.

For the purposes of review, let’s take a second look at the constructor:

public GtkStart05(string[] args) 
{
  Application.Init();
  Glade.XML gxml = new Glade.XML ("gtkstart05.glade", "myWindow", null);
  gxml.Autoconnect (this);
  Application.Run();
}

By this time we have examined all but the last call. As you can see, the sequence of calls in the constructor is completed by calling Application.Run, which is part of the GTK# toolkit. This call hands the control of the program over to the GTK. Your program never fully gets control back again until you call Application.Quit. Instead, your code simply processes signals of various types, such as those that are generated when buttons are pushed or data is entered in various types of controls. Your program continues to respond to events until such time as you call Application.Quit. At that point, your program exits.

Summary

That is enough for this article. In the next installment we will begin populating our window with controls, and responding to events generated by those controls.

In this article you learned how to create a simple window using the Glade development environment. You also saw how to create a simple signal, or event, that would fire when the window was closed. After creating the window and the signal, the article described how to save the information about your window to an XML file. The article explained how to load and parse the XML file, and how to connect the signal defined in the XML file to an event handler defined in your code. Finally, you saw how to respond to an event by closing the application itself.