Team LiB
Previous Section Next Section

When Asserts Can't Be Easily Used

Marvelous as asserts are, there are cases where it's difficult or impossible to use them. The basic issue is that asserts halt the execution of the program—that way you have plenty of time to analyze the assert and decide whether or not to deal with it. But in some situations the standard assert can never be acknowledged. Sometimes these situations can be worked around, and sometimes not.

Fortunately, though, the.NET architecture is flexible enough to cope with almost any situation. Can't use a standard assert? When push comes to shove, you can write your own. First, we'll discuss the situations where standard asserts are problematic. Then, we'll write a customized assert that will handle these cases the way we want.

The standard asserts can't be used easily in the following types of programs:

Asserts with Windows Services

The first place where standard asserts can't be easily used is in Windows services.

Note 

Don't confuse Windows services with Web Services—they are entirely different things. Web Services are new to.NET and allow distributed components to communicate through XML. Windows services have been around since Windows NT and are a way of making a special "background" process that has a few differences from a normal process.

Windows services normally don't have user interfaces. There are exceptions, but in general, services sit unnoticed in the background. There is a good reason for this. Many services such as Microsoft Exchange or SQL Server run on heavy-duty computers locked in a company's server lab. Generally, no one looks at those machines on an average day, so if those services ever displayed a message box and waited for acknowledgment by the user, then it might be a long while before anyone noticed.

So when you write a service to display a "Hello World" message box, that message box will open up on a hidden window station that no one will ever see. The program will be blocked forever, waiting on someone to acknowledge that hidden message box. A similar thing happens when a service displays an assert. Your service would freeze up if it tried to display the assert, so.NET services will normally avoid the problem by ignoring the assert and not displaying anything. It's as if you never wrote the assert at all.

Tip 

Actually, the preceding paragraph isn't entirely accurate. The MessageBox class allows you to specify some flags called MessageBoxOptions, and one of those flags is called ServiceNotification. If you go through the extra trouble of setting this flag, your services can display message boxes. We'll use this trick later on to write our own custom assert.

Asserts with ASP.NET Pages and Web Services

The problems with asserts in Windows services also applies to ASP.NET web pages and Web Services. But that should come as no surprise, especially when you realize the ASP.NET engine is a service itself. If a web page fired an assert, then who would see it? It may be that no one is logged on to the web server machine, so no one would be able to acknowledge the assert and then the process would be hung. To avoid this problem, ASP.NET pages and Web Services normally ignore asserts.

There's nothing we can do to fix this in the standard assert. Luckily, though, we can work around the problem by writing our own customized assert. How would we want this to work? Well, if the web page is being accessed by a user on a different machine, then we probably don't want to display any assert, since that user probably doesn't have access to the web server. On the other hand, we would want to display an assert if the web page request came from the local machine, because that user is obviously in a position where the assert could do some good. We'll discuss writing this customized assert shortly.

Multi-Tiered Services

There's another option that allows the use of asserts in services. This option also results in cleaner code, and simplifies debugging service startup code, a notoriously difficult task. Consider: It's good software practice to separate code into tiers, and it's not very hard to separate the "service" infrastructure code from the "stuff you care about" logic code. If you did that, you could write two versions of your program that use the same logic code—one is a service and the other is an application.

What does that gain? There are no restrictions on asserts in an application. When testing the code during development, run the application version to see all the asserts. Once your code has stabilized, switch to running the service version that will eventually be shipped. This gives you the best of both worlds—run the same code as either a service or an application, whichever is more convenient.

Accomplishing this is easy. Your Windows Service exposes only a few methods: OnStart, OnStop, OnPause, etc. Rather than writing your logic code inside these methods of the ServiceBase class, define a standalone helper class that does all the work. Then your ServiceBase class can merely delegate to the helper class. Or, you could write a standard app to do the same thing:

//Service version
    public class MyServiceClass : System.ServiceProcess.ServiceBase {
    ...
    private MyServiceLogic logic = new MyServiceLogic();
    protected override void OnStart(string[] args) {
        logic.OnStart(args);
    }
}
//Application version
public class MyApplicationClass : System.Windows.Forms.Form {
    ...
    private MyServiceLogic logic = new MyServiceLogic();
    private void startButton_Click(object sender, System.EventArgs e) {
        string[] args = ...;
        logic.OnStart(args);
    }
}
//The class that actually does the work
public class MyServiceLogic {
    public void OnStart(string[] args) {
        ...
    }
    ...
}

As an added bonus, this approach makes it easier to debug the service startup code, too. Traditional services can only be started via the Service Control Manager or the net start command, and both of those prohibit starting code through the debugger. You can always attach the debugger to an already running service—but suppose you're debugging a problem with the service startup itself? Visual Studio.NET doesn't support that very well. But architecting your service in this tiered approach can greatly simply that task.


Team LiB
Previous Section Next Section