Programming Windows Services with Microsoft Visual Basic 2008 : Administration of Services

11/27/2012 6:45:11 PM
Services usually require some sort of configuration to make them do what you have coded them to do, which will vary from service to service. You will seldom see—and you should never create—services that require recoding each time you want to modify something that should have been configurable.

You can configure a service in several ways. You are only limited by being able to expose that administrative capability to external users. Imagine you wrote a service that downloaded files from different sources and placed them in a different location. This type of activity is quite common, especially between the extranet and the intranet.

When writing such a service, you should take into account whether it should be single-threaded and only able to download one file from one source at a time, or multithreaded and able to download one or more files from one or more sources at a time. With either service, you would need to know the following information to make the service perform. Although this is not an exhaustive list, it demonstrates that you should always consider some important information when deciding how to best administer and configure your service.

  • Uri of the remote server

  • Port to connect on

  • File or files to download

  • Location to copy files to after downloading

  • Logon information

Types of Configuration Data

I always consider two main types of configuration data when I write a service: configuration information about how the service should run, and the configuration data used by the service to perform the tasks it was written to do. Let’s take a closer look at the difference between these two types of data.

Service Configuration Data

The difference between service and user configuration data is that the service relies upon its data to determine how it will run, not what it will do. Although this may seem like a fine distinction, a few items, which I’ll cover in the next sections, are specific to the service itself.

Number of Active Threads

Imagine that your service can create multiple instances of a particular class and have that class perform some work. Now imagine that the service itself starts each class instance on its own thread. The number of threads that the service is allowed to create would be specific to the service and how it runs, not to how it does the work.

Global Configuration Data

In many cases your service will need to do things such as send e-mail notifications or raise alerts to a central location. Because this information can be user-specific or globally used by the service, you should determine the granularity of the data itself. If appropriate, you should then place the data in the configuration file that is automatically associated to your application.

Location of User Configuration Data

The user-specific data location is another example of service-specific information. It would do no good for the class instances in our previous example to know where the data is if the service can’t first retrieve it to even start the class instances.

Storing Service-Specific Configuration Data

When you use the Microsoft .NET Framework, any application that you write has a default location for service-specific data in a file that follows this format: applicationname.exe.config. You can store all of your information in this one place, but usually it is better to separate application data from user data.

This file is available directly from your code at run time and design time; you should use it to store information that your service needs to run.

Creating Application Settings

Creating application settings is quite simple in Microsoft Visual Studio 2008. Create a sample project or open a project that you have already created. I have created a sample project called AppConfigSample and configured it to be a console application.

Right-click the project name and choose Properties. In the Properties window, click the Settings tab.

You need to configure the following four pieces of data for each setting:

  • Name This setting represents the name used by your application to retrieve the value that you assign to this setting.

  • Type This setting represents the type of information that you are storing. You are able to store any type of information that can be represented by a value in the configuration file.

  • Scope This setting represents whether this is a user- or application-level setting. User settings are updatable by the user during run time; application-level settings are not modifiable.

  • Value This setting represents the data that you want to retrieve while your application is running. This data should represent the internal .NET Framework object type you have associated to the setting so that it can be easily recast into that type when used by your application.

Accessing Application Settings

In my sample application I created a user-level setting called testsetting, of type string, and assigned it the value of teststring. The following graphic demonstrates what the setting looks like after I add it to my AppConfigSample console application.

When the application user setting is in place, we can write the code to access the value and use it in our code. Currently the value is not very useful—we’re using it for demonstration purposes only.

In my sample application, I use the Main method to read the value from the configuration file appconfigsample.exe.config and write it to the console. Listing 1 shows this code.

Listing 1. Sample user setting access.
Module Module1
    Sub Main()
        Console.WriteLine( _
            "The User Setting Value is: " + _
            My.Settings.testsetting + _
    End Sub
End Module

You can see that I use the My object to access the Settings instances for this sample application and then access the testsetting setting. Any setting that you create will be accessible through this same method. When I run this code I get the following output.

The sample application demonstrates the ability to use application-level settings that can affect both the application and the user. Application settings represent changes to how the application runs, not how it does the tasks at hand, which are usually more user-level settings.

In this case, I used a user scope setting. However, from a service perspective, I do not consider this to be a good configuration model because in this scope, user-level settings are defined for how they affect the appearance or use of that specific user on a specific system, not how a single instance of an application in a central location treats the requirements of each user. Therefore, putting every possible user setting in the application-level configuration file really isn’t the best option.

Each time your application runs, it will have access to this file directly. You can update this file while in run-time mode so that in the future you can access any new attributes or settings that you define. Now let’s look at the user configuration.

User Configuration Data

Users aren’t the only ones that need to connect to services. Services could be automated and not require any user interaction.

When a service is automated with no user interaction, it still may allow users to configure for themselves how it does the work it is programmed to do on their behalf. For instance, if you create a service that downloads files from different locations, each location can be owned by a different user, or each file type that you download can be owned by a different group of users. For each of these users you need a way to configure the service to know how and what to do specifically for them.

User data is information required by a service to perform the same tasks in a different way for a different user. For that reason, user data is used to explain to the service how a particular user expects something to happen. Aside from explaining how things are done, user data explains how that user wants to be notified of specific errors or successes that occur within the service.

Going back to my previous example of a service creating instances of a class that does the work on separate threads, this definition of user data would mean that each class instance needs to receive its particular configuration data so that it can run properly.

From a service perspective, we should use a service-level, application-specific setting to tell us where the configuration data resides. From a storage perspective, we can keep this information anywhere. Let’s look at several options.

  • Microsoft SQL Server This option is used by larger services to store both user-specific and application-specific configuration data. In many cases an entry or entries in the application-specific configuration file stores the connection settings required to connect to SQL Server and gather the configuration information. When user information is stored here, it is up to the developers to create the tables and stored procedures required to store and retrieve the data.

  • Microsoft Access or FoxPro These options are used to create localized data stores that act similarly to Microsoft SQL Server but are much smaller and less scalable.

  • Flat files These files are used to store configuration data, but they require developers to create parsing, reading, and writing routines so that information can be properly read. You can use the service-level application log to store the location of this file for later retrieval.

  • XML files These files are similar to flat files except that they already have built-in classes in .NET to read from and write to them. The developer still needs to create the schema for the file, but after that, reading and writing are easy.

Advanced Service Administration

The general steps taken by a service are to start, read the application-specific file, load the user configuration data, and then begin performing the tasks it is designed to do. The problem is that in many cases you want to be able to change the behavior of your service to perform more tasks, or change how it performs the current tasks. You might change the way the service performs based on user requests or administrative requests.

Imagine that your service is running and you can configure the number of threads it can create or the number of users who connect at the same time. Imagine that you’re monitoring your service and notice that although the service is running fine, users are complaining about performance. When users connect, or their specific task begins, things run just fine, but it’s taking a while for the service to start performing its task or to get connected.

In this case it might be necessary to reconfigure the service to allow for more threads, more user connections, or new work loads because of new user configuration requests. Restarting the service each time you make a change can become an administrative burden. Not only does this require administrative interaction each time a user requests a change, but it also causes an impact to every other user when the service is stopped.

Dynamic Service Configuration

Let’s look at how to make your service dynamically configurable. Three levels of configuration change are possible:

  • Service This configuration change reflects, for example, how many threads or connections the service allows at one time. Increasing the number of threads or connections might be easy to code, but you need to take into account some maximum number so that your service doesn’t become overloaded.

  • User User preferences include pointing to a new file location or new storage location for an existing and already running process. Allowing users to change preferences on the fly requires you to have a way to map the user change request to an already existing class instance and data set. This means you must have a way to uniquely identify users and user configurations.

  • New This includes user configuration data where new threads, connections, and processing have to take place. New user configurations are usually the easiest because they only require you to validate that the new configuration won’t overload your system in advance. The steps to launch new configuration data should be nearly identical to the steps required to launch data when it was first read as the service started. Therefore it requires only small coding changes.

Each one of these changes can have a different effect on your system, and you have to take that into account when deciding on which changes to make dynamic.

Dynamic File Configurations

If you use files to do your configurations, you need a way to know when the file has been updated so that you can reflect those changes in your service. The great thing is that Microsoft Visual Studio 2008 provides this capability in the FileSystemWatcher class.

The FileSystemWatcher class allows us to monitor for new files or changes to existing files. You can use an instance of this class to monitor when your configuration file changes and then reload the file and make the changes where appropriate.


Be careful when monitoring for new or changed files. The system can report that a file has been created or changed before the locks from the system or modifying application have been released. You will need to take this into account when monitoring for a change.

You have to be able to identify a change and associate it to an already existing instance. This means you need to have code that will identify, shut down, clean up, and restart any instances that are affected by the change. Making sure that the code cleanly shuts down the processing that is already occurring for a given user is important so that you can avoid losing important data or transactions.

If you want to allow for dynamic configuration, be sure to take the following precautions:

  • Make sure that all user data is uniquely identifiable—at least at the top root of the information required to run the user request. If you use a name property, make sure that it is unique and enforced. Because you are using a flat file or XML files, you may need to validate the configuration file first by looping through the names. For any duplicates found, throw an error and then ignore that request.

  • Make sure that if you are using multiple configuration files and are monitoring for new or updated files, you take into account that the file may still be locked even though you received the event. I recommend making multiple attempts (with some delay between attempts) to access and read the file. If you are still unable to read the file after a specified amount of time and number of tries, throw a final error and then decide to shut down or send out an alert to administrators.

Microsoft Database Dynamic Configuration

Whether you are using Microsoft Access, FoxPro, or SQL Server, you can monitor the data store for any changes. Depending on the data store, you might even be able to create events—such as in Microsoft SQL 2005 stored procedures—that will notify your service when a change occurs.

Your service can use two primary types of monitoring events to create your required reactionary events: data store and code-based monitoring.

  • Data Store Data store events are one way to acknowledge changes in the underlying data. There may be requirements for complicated business logic to make sure that the data is completely written or configured properly before letting the service know it is ready to be updated. Stored procedures, Microsoft SQL Server Notification Services, Microsoft SQL Agent, and triggers are some ways to know within the data store itself that a change has occurred. How you get that change to the service depends on the service.

  • Code-based For code-based monitoring of the data store, you need a thread or set of threads within the service to monitor for any changes in the data store from the time you load the data to the time it changes. In many cases you can use state columns on the data, which would reflect whether that data is in use and its current state. Imagine that a user disables her data configuration. The state of the use of the data would be inactive even though the data itself could be up to date. Monitoring for activated data sets with states of new or updated would allow you to properly read configuration data on the fly.

Administrative UI

Previously service developers created a console application that you ran from the control panel to update or modify services. Now Microsoft gives you ways to create Microsoft Management Console (MMC) snap-ins that can provide access to your configuration data.

Whether you are using a data store or a flat file, your administration would be much easier if you created an administrative UI instead of trying to always modify the files in Notepad or directly in the tables using stored procedures that you create. Although an administrative UI is not necessary, it is something you should consider when you develop your service.

Administrative UIs should allow users to view the status of their service and make changes or add new configuration options. This ties in directly with the ability to make dynamic content changes; however, the UI itself is independent from the code that looks for changes, because it merely makes those changes.

If you are using a data store, you may want to consider using a Web-based solution for making changes to your configuration data so that it is more flexible and requires less maintenance when it comes to software updates. Windows-based clients require you to update everyone using the application each time it is changed.

Video tutorials
- How To Install Windows 8

- How To Install Windows Server 2012

- How To Install Windows Server 2012 On VirtualBox

- How To Disable Windows 8 Metro UI

- How To Install Windows Store Apps From Windows 8 Classic Desktop

- How To Disable Windows Update in Windows 8

- How To Disable Windows 8 Metro UI

- How To Add Widgets To Windows 8 Lock Screen

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010
programming4us programming4us
Top 10
Free Mobile And Desktop Apps For Accessing Restricted Websites
TOYOTA CAMRY 2; 2.5 : Camry now more comely
KIA SORENTO 2.2CRDi : Fuel-sipping slugger
How To Setup, Password Protect & Encrypt Wireless Internet Connection
Emulate And Run iPad Apps On Windows, Mac OS X & Linux With iPadian
Backup & Restore Game Progress From Any Game With SaveGameProgress
Generate A Facebook Timeline Cover Using A Free App
New App for Women ‘Remix’ Offers Fashion Advice & Style Tips
SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th
Popular Tags
Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Exchange Server Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe Photoshop CorelDRAW X5 CorelDraw 10 windows Phone 7 windows Phone 8 Iphone