State Sanity Using Smart Clients


Chris Sells

May 20, 2002

I'd like to welcome you to the inaugural article of my new MSDN Online column. From the title of this column, you can probably tell two things right off. It's about Windows Forms, and it's a technology I like quite a bit. Of course, as with any technology, Windows Forms has its good points and its "opportunities for improvement." In this column, I'll explore the various ins and outs of Microsoft .NET as it relates to building stand-alone applications, as well as the client side of client-server and n-tier applications, including forms, controls, applications, multi-threading, data-binding, deployment, security, drawing, scripting, and whatever else I think of, all in the age of distributed systems over the Internet and the intranet. If you've got specific issues you'd like to see covered, or questions you'd like answered, feel free to send them along to me at

Before we get started with the first topic, you may wonder why I care so much about Windows Forms. I mean, what's there to say about yet another Windows Forms package? As you'll see, there's a lot to say, but very few are saying it. Everyone seems to be fixated on Web applications. Web applications are a great way to get the largest reach, but for more than occasional use, Web applications are a poor imitation of what's available in a richer client that Windows Forms enables. Consider the user experience of a Web version of an e-mail client and the corresponding Microsoft Windows® version. Which is easier to use? Which provides more features? Which is faster? Which do you rely upon day-in and day-out? Of course, Web applications provide reach across multiple browsers on multiple platforms (assuming you can provide a working mix of HTML, DHTML, CSS, JScript®, plug-ins, and ActiveX®), but if you've got .NET on your target client platform, Windows Forms deserves serious consideration. In addition, Windows Forms applications tend to be much easier to develop, as we'll see in our first foray into the Wonders of Windows Forms.

Thin Clients and State

As browser usage became more stable and there was some semblance of HTML DOM that could be programmed to produce clients that were functional, it became clear that while HTML was fabulous for building graphical user interfaces (GUIs), it was good at little else. The application-framework style features needed to build the fabled "single-page Web application" were found to be lacking. Even simple things like keeping user preferences from one run of an application to another relied on oft-disabled features like cookies or JScript on the client side and complicated HTML generation on the server-side, both of which were difficult enough to drive most Web sites to the lowest common denominator. Things like menu bars, toolbars, standardized interfaces, or keyboard shortcuts were often dropped for pretty but unfamiliar GUIs that prominently displayed hand-crafted graphics, color schemes, and advertisements, but whose functionality boiled down to what could reliably work across browsers and platforms.

Hence the thin client was born. It could be deployed, one piece at a time, to any machine that wished to surf to it, with an instant-install model that was to be envied. This was achieved with a programming model that put as little as possible on the client-side and relegated all of the interesting functionality to the server-side. Third generation technologies like ASP.NET are the latest waypoint on this journey. As an example, consider the simple unit conversion application shown in Figure 1.

Figure 1. ASP.NET unit converter Web application

This Web application provides a number of categories of unit conversion. For example, it includes temperature and volume, as well as a number of units in each category, such as Celsius, Kelvin, and Fahrenheit. The categories and units themselves come from a Web service that provides the list of conversions it can do, as well as providing the actual conversion on demand. Each time the user selects a different category, they get a correspondingly different set of units from the category to convert among. The reconfiguring of the UI can be implemented in two ways:

  1. I could send all of the conversion categories and units to the thin client and use JScript to change the units as the user switched the category.
  2. I could go back to the server every time the user changes the category, regenerating the UI on the server-side to match their choice.

While the former is clearly the best in terms of user responsiveness, it also provides a more difficult programming task in terms of getting cross-browser JScript working reliably. This is further compounded by the lack of a good set of tools to handle this kind of client-side scripting model. Instead, Visual Studio .NET encourages the use of Web Forms, which places the burden of HTML generation and UI event handling firmly on the server-side. On the server-side, more smarts can be brought to bear on generating truly cross-browser HTML, as well as letting the developer implement this application in C# or Visual Basic® .NET. The code snippet below shows how to implement this Web application using the server-side UI model of ASP.NET.

Let's take a look at some code from a Web Form:

public class WebForm1  {
    protected System.Web.UI.WebControls.DropDownList _categoryList;
    protected System.Web.UI.WebControls.DropDownList _fromList;
    protected System.Web.UI.WebControls.DropDownList _toList;
    protected System.Web.UI.WebControls.TextBox _from;
    protected System.Web.UI.WebControls.TextBox _to;
    protected System.Web.UI.WebControls.Button _convert;
    void FillCategories() {
        foreach( Conversion conversion in GetConversions() ) {
            if( _categoryList.Items.FindByText(conversion.Category)
                  != null ) continue;

    void FillMeasures() {
        // Update the From and To lists when the category changes
        string  category = _categoryList.SelectedItem.Text;

        foreach( Conversion conversion in GetConversions() ) {
            if( String.Compare(conversion.Category, category, true)
                  != 0 ) continue;

        _fromList.SelectedIndex = 0;
        _toList.SelectedIndex = 1;

    void Page_Load(object sender, EventArgs e) {
        if( !IsPostBack ) {
            _to.Text = "";

    void _convert_Click(object sender, EventArgs e) {
        Converter converter = new Converter();
        _to.Text = converter.Convert(_categoryList.SelectedItem.Text,
            _fromList.SelectedItem.Text, double.Parse(_from.Text),

    void _categoryList_SelectedIndexChanged(object sender,
                                            EventArgs e) {
        _to.Text = "";

As long as you're willing to close your eyes and forget the round-trips on each change of the drop-down list, this code shows how much client-side technologies like Windows Forms have influenced Web Forms. Even if none of the pages in your Web application need to be dynamically re-generated as the unit conversion program requires, each new piece of the UI that is brought in from the server as requested by the user will need to be generated on the server side. Certainly the client-side browser cache can help to reduce the round-trips, but not if the contents are dynamically generated based on current data, user preferences, and/or the current session state. Of course, the current data—the list of available conversion units in our example—is why you're going back to the server in the first place. Providing a centralized, up-to-date repository of data is why your Web application isn't just copied to the user hard drive lock, stock, and barrel.

In contrast, user preferences—like what a user's favorite units are so that UI can default to them, and the current state of the session, like who the user is or where they are in a multi-part form—seem like things that could be pushed to the client-side and kept there. Unfortunately, since this data is also used to generate the UI, it must be kept on the server-side. This doesn't leave the client off the hook, however. Since HTTP is a connectionless protocol in which the client has a new connection to the server for each page it requests, there is no way for the server to associate a single connection with each client, and therefore that client's session state. This requires a client to send a unique identifier with each request to the server through such mechanisms as hidden form fields, cookies, and session-specific URLs (think's long, digit-laden addresses). This unique ID is then used to pull the session state out of memory or from a database. And while this works well and is used by countless Web applications the world over, there's still the issue of how long to keep the data cached on the server-side. The server will get no notification that the user has navigated to another URL or closed down the browser so that it may clear its cache. Instead, it must assign timeouts to cached data so that as rude clients drop off without so much as a wave goodbye and the server can reclaim resources to serve other clients.

Unfortunately, all of this focus on state is needed for all but the most trivial Web application, even if the major functionality is provided by a Web service, as Web services don't handle UI duties. A good Web service represents completely stateless access to atomic functionality. The need to split the UI generation from the actual interaction with the user yields a typical 4-tier Web application architecture like the one shown in Figure 2.

Figure 2. Typical Web application architecture

Thick Clients and State

On the other hand, thick clients, stand-alone applications completely installed on a user's machine, handle user preferences and session state with aplomb. In fact, in a Windows Forms application, dealing with state happens almost automatically as part of implementing the functionality, in contrast to being the central preoccupation it is with thin clients. There're no roundtrips anywhere to build the UI because all of the logic and data are right there on the client itself. Also, there's no issue of timing out session state. A client knows exactly when it's been turned off, which gives it the opportunity to cache state for the next sessions as well as letting the client machine reclaim resources as soon as they're no longer required to serve the user. Of course, a thick client has all of the operating system-specific advantages that Web applications lack, as shown in Figure 3.

Figure 3. Unit conversion Windows Forms application

The Windows Forms implementation is nearly identical to the ASP.NET implementation except that there is no need to worry about post-backs or application state or round-trips to the server to generate UI. A stand-alone thick client has the obvious downside, of course, of not having ready access to centralized, up-to-date data from a server as seen with a Web application. Instead it relies on updated version installations to provide updated data. This is where Windows Forms and Web services become the perfect pair.

Smart Clients and State

Combining the advantages of Windows Forms thick applications—like rich UI and simplified state management—with the advantages of Web thin applications—like deployment over the Web and access to the server for data and services—gives us what the .NET community has come to call a smart client. Smart clients are characterized by their reliance on Windows Forms for their client-side implementation (optionally downloaded on demand over the Web), combined with back-end Web services for their server-side implementation. Since good Web services are inherently stateless and leave all of the UI and state management duties to the client, there's no hybrid layer that generates UI and manages state as required in typical Web applications. Our smart client architecture has morphed from the Web application architecture into a 3-tier layer that's far simpler, as shown in Figure 4.

Figure 4. Typical smart client architecture

Of course, one other advantage that Web applications have over thick clients is that as a consequence of generating the UI on the server side, user preferences often float between machines with a simple log on, giving the user the same customized UI regardless of what machine is being used. However, there's no reason that a smart client needs to cache user preferences on the machine on which it's being run. MSN® Instant Messenger is an excellent example of this technique. Contacts are stored on the MSN Instant Messenger server, not on a particular user machine, which means as the user logs into the service, the user's preferences are downloaded on the fly, sparing the user the pain and anguish of reconfiguring Instant Messenger on every machine they choose to use. Sharing user preferences between machines is an excellent use of a Web service.


Truly stand-alone applications are a dying breed. Users want the combination of the best of Web applications and the best of the UI conventions supported by their operating system. Web services, which provide only functionality and not UI, when married with Windows Forms clients to handle the UI and session state, are the perfect hybrid for your .NET-enabled users.


Chris Sells is an independent consultant, specializing in distributed applications in .NET and COM, as well as an instructor for DevelopMentor. He's written several books, including ATL Internals, which is in the process of being updated for ATL7. He's also working on Essential Windows Forms for Addison-Wesley and Mastering Visual Studio .NET for O'Reilly. In his free time, Chris hosts the Web Services DevCon and directs the Genghis source-available project. More information about Chris, and his various projects, is available at