I've been working on a server monitoring Windows service recently - it's meant to keep an eye on our servers for various types of failures and, if possible, automatically recover from them. One of the failures our website experiences once in a while has to do with our forums. I integrated a third party forum package into our site so our stores have a place to post messages and talk with one another. Occasionally (and I have yet to reproduce the failure steps) it will fail, complaining that it can't find some configuration file. The quick fix is to reset IIS; usually I'll just remote into the server and do an IISRESET from the command prompt. I wanted my service to keep an eye out for this type of failure and automatically recycle IIS. Long term I'd love to track down this failure and fix it the proper way but in the meantime I just want to be able to recover gracefully.

I found the ServiceController class after a bit of digging and wrapped it up into two static methods I could call to reset IIS. I just had to figure out the name of the service I needed to refer to. The easiest way I found of finding this was to just cycle through the services and display their names. You could write a quick console app. to do this, but I just used LINQPad, switched it to C# Statements, added a reference to the System.ServiceProcess.dll (hit F4), then added the namespace System.ServiceProcess and ran the code.

As an aside: I can't say enough nice things about LINQPad - it makes it so nice to be able to test out new classes and ideas. Its name would lead you to believe it's only good for testing LINQ queries, but you can test out almost any .NET code you want. I spent the whopping $19 to upgrade to the full version, which adds Intellisense (the free version doesn't include that). I've added LINQPad to my "must have" .NET toolkit.

image

You might be wondering what the Dump() method does, since it's not part of the ServiceController class. LINQPad has a nice extension method named Dump() that makes it trivial to dump out the response from almost anything. My sample doesn't show it, but it even handles nested classes nicely. OK, enough fawning...

I ran this code which made it really easy to find the service names I was interested in. Once I had them I wrapped up a few of the services I wanted to be able to cycle in their own methods. I ended up wrapping the Start/Stop calls in a try/catch; it would throw an exception if I tried starting a service which was already running or stopping a service which had already stopped.

private void ResetIIS()

{

    StopService("W3SVC", 10);

    StartService("W3SVC", 15);

}

 

private void ResetStateServer()

{

    StopService("aspnet_state", 15);

    StartService("aspnet_state", 15);

}

 

public static void StopService(string serviceName, int timeoutSeconds)

{

    using (ServiceController controller = new ServiceController(serviceName))

    {

        try

        {

            controller.Stop();

            controller.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(timeoutSeconds));

        }

        catch (InvalidOperationException ex)

        {

            // Service may already be stopped

        }

    }           

}

 

public static void StartService(string serviceName, int timeoutSeconds)

{

    using (ServiceController controller = new ServiceController(serviceName))

    {

        try

        {

            controller.Start();

            controller.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(timeoutSeconds));

        }

        catch (InvalidOperationException ex)

        {

            // Service may already be running

        }   

    }           

}

 

private void ListServices()

{

    ServiceController[] services = ServiceController.GetServices();

    foreach (ServiceController service in services)

    {

        string name = service.DisplayName + " : " + service.ServiceName;

        Console.WriteLine(name);

        //name.Dump();

    }

}


Links:

http://www.linqpad.net


 
Categories: .NET | C#

July 25, 2009
@ 09:00 PM

Last year (two years maybe? Time flies...) I built a web-based "e-mail" system that provided internal-only e-mail on our web portal. That might seem a bit weird, but we needed a system where we could be sure when an e-mail was sent, to who, when it was read, ability to recall a message, control who can send messages to who, etc. Basically we needed to control the content end-to-end. Unfortunately standard e-mail doesn't give you that level of control, so hence the need for building it.

I wanted the e-mail to function very similar to Outlook to minimize the learning curve and help adoption (the old system another provider was hosting was really clunky). It uses a lot of AJAX technology and had what I thought was a fair amount of the standard e-mail features: You can create custom folders, move messages, forward messages, reply to messages, add attachments, it automatically refreshes the e-mail list periodically, you can view who has read your e-mail (and when), group messages by date or sender, sort messages, resize the windows, double-click on a message to view it in a larger window, plus a lot of other smaller features.

 WebEmail

Web Email Move Folder

Web Email New Message

I thought it turned out nicely but an interesting thing happened; Some users were unhappy with the level of functionality provided: you couldn't flag messages, drag and drop a message from the inbox into a folder, the e-mail list didn't have intellisense, etc.

Wow - I totally wasn't expecting that reaction (mind you, it was from a fairly small minority, but it was interesting getting that feedback).

Of course it doesn't compare to the functionality of Outlook, I thought! They had 100+ developers and a few years of development time. I had, well, me and a few months (and not just on this particular module)!

I didn't know what to make of it. I had spent a lot of time adding features, polishing the UI so it wasn't clunky looking, etc. and they weren't happy with the functionality? Where did I go wrong? It didn't occur to me until later that, by mirroring the look and feel of Outlook that I was setting my web-based e-mail client to be compared directly against Outlook. They weren't comparing it to the clunky old system at all. I had inadvertently set their expectations much higher than I could deliver because of this. Ouch.

In retrospect, I might have been better off delivering a system which functioned and looked better than the existing system but didn't attempt to look and/or operate like Outlook at all. For example, if I was able to do this over I'd probably drop the folders option and simplify the e-mail list to just a nice looking grid list w/sorting (removing the grouping altogether) and reduced some of the AJAX functionality (ex. when you click on a message the e-mail icon "opens" and changes from bold text to normal text), among other things. I would have spent less time on it and had less chance for bugs to boot.

I know all about setting a customer's expectations so that there aren't any surprises, but I completely forgot about some of the implicit expectations that can arise in a project (and managing those as well).


 
Categories: Software Development