Jul 12 2010

Creating a Windows Service in VB.NET

Mohammed Al-Atari

What is Windows Service

Previously called an NT service, the core function of a Windows aervice is to run an application in the background. There are few things that make them different from a Windows application. A Windows service starts much before any user logs in to the system (if it has been setup to start at boot up process). A Windows service can also be setup in such a way that it requires a user to start it manually – the ultimate customization!

Windows services have their own processes, and hence run very efficiently. Normally a Windows service will not have a user interface for the simple reason that it can be run even if no one is logged into the system, but this is not a rule — you can still have a Windows service with a user interface.

In windows 2000 you can view a list of services currently running on your computer by opening Control Panel -> Administrative Tools -> Services

Creating A Windows Service in VB.NET

Prior to VB.NET, creating a Windows service was a lot of work, and was left to the C++ guru’s, as you had to use some system level procedures, which were extremely difficult. Thanks to VB.NET, however, this is becoming very easy and we shall now learn how to create a Windows Service in VB.NET.

There are a few things that you should know before we dive in, however. Windows services are not available under Windows 95, 98 or ME — you need to have Windows NT or Windows 2000 to run services.

The advantage to use .NET is that the framework incorporates all of the classes, which shall help us to create, install and control a Windows Service. Open Visual Studio .NET and create a new Windows service project, which we shall call “MyService”. Click OK.

Add a timer control from the toolbar in the Components tab (not the Windows Forms tab!). In the properties window of Timer1, change the interval property to 10000, which is 10 seconds.

Examining The Source Code

Double click the timer1 control to open up the code window for Timer1_Elapsed. Type in the following code:

Dim MyLog As New EventLog() ' create a new event log
' Check if the the Event Log Exists
If Not MyLog.SourceExists("MyService") Then
    MyLog.CreateEventSource("MyService", "Myservice Log") ' Create Log
End If
MyLog.Source = "MyService"
' Write to the Log
MyLog.WriteEntry("MyService Log", "This is log on " & _
CStr(TimeOfDay), EventLogEntryType.Information)

Type in the following code for the OnStart procedure:

Timer1.Enabled = True

Type in the following code in the OnStop procedure:

Timer1.Enabled = False

Our application is now ready, but there are a few things that we need to do before we move ahead when we build this application. The executable created is not a Windows application, and hence you can’t just click and run it — it needs to be installed as a service, but don’t worry, we don’t have to do it manually — VB.Net has a facility where we can add an installer to our program and then use a utility to install the service.

Adding an Installer to the Project

Open the service1.vb design window, right click on it and select Add Installer option, which will add an installer project (called ProjectInstaller.vb) with two controls — ServiceProcessInstaller1 and ServiceInstaller1 — to our existing project.

Select the ServiceInstaller1 control and open the property window. Change the ServiceName property and DisplayName property to MyService (this is the name you want to appear in the list of services in the services window). Select the ServiceProcessInstaller1 control and open the property window. Change the Account property to LocalSystem (this needs to be specified as we need to run the service on our local machine).

Now it’s time for us to build the application and create an executable. Select Build Solution from the Build menu to create an executable with installation instructions for the service.

Installing the Service

To install our service we need to use the InstallUtil program, which is a .NET utility to install Windows services. You can find it in C:\WINNT\Microsoft.NET\Framework\v1.0.3705

Note: This directory might be different on your computer, depending upon the version of the .NET framework you are working with Alternatively, you could run a .NET Command Window by selecting Start –> Programs -> Microsoft Visual Studio .NET -> Visual Studio .NET Tools >- Visual Studio .NET Command Prompt, which sets all of the required paths for you.

Type the following command in the command window:

InstallUtil "d:\My documents\development\applications\MyService\bin\Myservice.exe"

This is the path for the executable of the service we just created. Remember that VB.NET created the executable in the Bin folder under the project folder, so make sure you change this to your executable path.

Starting the service

Running a service and starting a service are two different things — when you install the service with InstallUtil you are running the service, but have yet have to start it.

To view and start the service, open Control Panel -> Administrative Tools. Now click Services, locate MyService, right click on it and select Start to start it:

Our service is now started. Open the Event Viewer from Administrative Tools and click Application Log to see the logs created by the Service (MyService) every 10 seconds. If you don’t see any logs click refresh (F5). You will have to keep refreshing to see the latest event logs:

Stopping the Service

This procedure is similar to installing the service but now we shall run the InstallUtil with the /U parameter, which will uninstall the service:

InstallUtil /U "d:\My documents\development\applications\MyService\bin\Myservice.exe"

(or the executable path on your computer).

Take note of the message to confirm that the service was uninstalled properly.

Tips

  • Stop the service and close the service window before you install/uninstall the service.
  • Always uninstall/install if you make any changes to the service application.
  • Try avoiding a user interface, inputs and message boxes in the service application.
  • Open ProjectInstaller.vb, select the ServiceInstaller1 control, and open the property window. Change the StartType property to automatic if you want to start the service automatically.
  • If you want to debug your windows service, it isn’t quite as straight forward as usual. Start your service, then go to Debug|Processes in the Visual Studio IDE. Find MyService.exe (you may need to check a box to display system processes), and attach the debugger. Then you’ll be able to set breakpoints as usual – but not in the Start procedure

Conclusion

Windows services are often overlooked. You should use a Windows service instead of a standard application when you need to monitor or administer something in the background. The only disadvantage of using a service is the installation procedure, but I bet that there are more positive aspects then negative when selecting a Windows service over an application running with Windows Scheduler!

Share This: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Facebook
  • Live-MSN
  • TwitThis
  • LinkedIn
  • MySpace
  • email

Jul 12 2010

Software Development Life Cycles: Waterfall Model, V-Model (YouTube)

Mohammed Al-Atari

 

YouTube – Software Development Life Cycles: Waterfall Model, V-Model
  

Share This: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Facebook
  • Live-MSN
  • TwitThis
  • LinkedIn
  • MySpace
  • email

Jul 12 2010

Running a .net application on a server (Shared Folder)

Mohammed Al-Atari
 

The question comes up all the time across hundreds of .net forums.  Here it goes: “I just created a vb.net application that works perfectly fine on my local machine, however I need to run this one application on a server so other users can use it.  When I try to run it on the server I get a TON of errors.” The error generally looks like this (warning: It’s pretty long and ugly):

41163180ad8 

  

So the question is why does this happen now in .net, how can I get around it, and how do I stop it from happening in the future.  Before I get right down to the answers I would like to explain this (so you fully understand why this happens).

  

 

VB6 Gone Are The Days 

Gone are the days where you could write a VB6 application, compile it, throw it on a UNC shared path and apply some security rights to your end users.  That was too simple…but in reality it was a pretty poor method of doing things.  You would have to constantly be modifying the rights on network folders, your admins hated you with a passion.

CLR and CAS 

With the .net framework programs that run on the CLR use CAS (code access security).  What this means is you no longer assign rights to users / groups on a network.  Instead you assign trust to actual code that the programmer has developed.  Basically your applications assembly file is compared with the security policy of the machine.  When you run your application on your local machine and it works just brilliantly fine it’s due to the fact that you are running your code in the MyComputer zone.  By default the MyComputer zone has FullTrust (unrestricted permissions) to do virtually anything.  This is why the application works on your local pc just fine…now why is it not working on the server.

It Just Wont Work On That Server 

Your application bails on the server because the server is more restrictive given its zone is the LocalIntranet zone which does not have full trust to run an executable by just anyone from any machine.  In addition, it is a lot more secure (and that’s the whole idea behind microsoft security from now on, make it more secure).  It also makes a lot more sense since now not anyone can just throw executables in a server shared and run them.

Lets Discuss a Complete Example 

Pictures are worth 1000s of words..ya…so it’s best to stop yapping and to start showing.  Let’s go through a full blown example of an application that works fine on my local pc and bails on the server.  First and foremost it’s worthwhile to note that on most occassions applications bail on things that access other network structures, SQL data retrieval (working with the database), etc.  The reason why I have placed a bold item on the second item is because that is what we will work on as well as in most cases this is what most people run into problems tapping into a database.

So first and foremost the application.  We are going to write a useless application that simply pulls EmployeeID numbers from the Northwind database (The sample database given to us by MS on SQL Server).  The application has no use nor will we be writing pure beautiful code that takes advantage of stored procedures, triggers, yada yada yada.  The point of this post is not how to write clean code that taps into a database, it is simply to demonstrate how to avoid the security policy error in .net.

So lets start by creating a VB winform application.

I’m using VS 2005 so you may have to work around if you are using 2003..the code and the methodology is the same in both.

Click file->project

Select Visual Basic and highlight Windows

Select Windows Application

For the name you can call it AvoidSecurityException and store it anywhere (I usually use C:\Temp for temporary projects, and you can call it whatever you want.

57048411nv1 

 

Now we are going to work on our project.  Drag and drop a Button onto your form, it doesnt matter where.

Double Click the button so that it takes you to the code behind page.  Since we will be dealing with databases you need to import the System.Data.SQLClient namespace.  So above the public class Form1 add the text Imports System.Data.SQLClient.

 

25460115vb1

 

Now we have the SQLClient namespace we can start writing our code in the Button1_Click event.   

52681258dg2

 

We are pretty much done, told you it was a worthless application, just to show you what happens when placing this app on a server as opposed to your local machine.  Now go ahead and build your application:

From the menu at the top select Build->Build AvoidSecurityException (the name might be different here).

Once you build this application you can run it on your local machine.  Either run it within Visual Studio, or double click the executable found in your projects bin/debug directory.  You will notice a simple loop that message boxes the employee id numbers, hopefully there isn’t alot, if there is you will need to end the program (ctrl alt delete).

Great your program works, now you need to deploy it to a server so that all your other users on your network can use this program.  So you copy and paste your .exe file (the one that was in your bin/debug directory) to a network server share folder \\servername\folder.  Now you double click the exe from that shared network folder and you get that same message about an unhandled exception all the way down to System.Data.SqlClient.SqlClientPermission.

How To Avoid This 

There’s a couple of ways to avoid this.  You can do it the right way which takes a bit longer and seems to be a bit more complex, or you can do it the other way which is much quicker but is poor practice and a security vulnerability.

The 2 ways are:

  • Create a strong name key and use it in your applications AssemblyInfo.vb file
  • Modify the security policy to fully trust the LocalIntranet zone

The 2nd method (bad way of doing things) 

(From the .net security blog: http://blogs.msdn.com/shawnfa/default.aspx)

The easiest way to modify your security policy is by using the Microsoft .NET Framework Configuration utility from the control panel.  You can also run this tool from the command line by running mscorcfg.msc.

  1. Expand the Runtime Security Policy folder
  2. Expand the Machine policy level
  3. Expand the Code Groups folder

To modify the polcy to trust a specific strong name:

  1. Right click on All_Code, and select New
  2. Create a new code group for your strong name, and hit next
  3. Select a strong name membership condition from the drop down box
  4. Hit the import button, and select your assembly.  The configuration tool will import your public key.  If you want to trust everything you sign with this key, leave the name and version boxes unchecked
  5. Select the FullTrust permission set

To modify the policy to allow full trust for all Intranet assemblies:

  1. Expand the All_Code code group
  2. Right click the LocalIntranet_Zone code group, and select properties
  3. Switch to the Permission Set tab, and select FullTrust

Reference: .net security blog 

The Right Way of doing it 

The correct and more preferred method is to create a strong name using the sn.exe tool and using that key in your application’s AssemblyInfo file to get around these horrendous errors.  So point to your visual studio 2005 program group from the start menu.  Select Visual Studio Tools then select Visual Studio Command Line

The command line will open.  Type in:

sn -k mykey.snk 

You can change mykey to any value you want such as myappskey.snk the main thing you want to make sure is you run it with the -k option.

sn -k myappskey.snk 

In my apps example I will stick with mykey.snk.  Result should look much like this

 

48112545li8

Notice how the key has generated and written as mykey.snk within the active directory.  Simply take and move this key to where you would like to store it.  Make sure you place it somewhere visible to the application, in addition do not store it in a local protected folder while the application is sitting on some shared server.  It needs to be able to see it (does not mean it has to physically see it within the same directory, just means it should be able to call it or have visibility to it).  Let us say you stored the key on some shared network drive.  Fine and dandy, now we need to modify our applications AssemblyInfo file to accept this key.

So go back to your project and look in the Solution Explorer for the AssemblyInfo.vb file.  If you do not see it click the “Show All Files” icon (second small icon on the solution explorer).  Then drill down into “My Project” and you will see it:

25608602se8

 

Double click this file, and you will be presented with something like so:

  

50915245je3 

  

 

You will need to add the AssemblyKeyFile attribute to this so that your assembly is aware of your key.  So you can add it anywhere in this file.  I have added it under the AssemblyTrademark:

10gw5

 

Notice it as:

<Assembly: AssemblyKeyFile(“\\networkserver\sharedfolder\mykey.snk”)> 

You will need to modify the path to point to where you have stored your .snk file.  Now rebuild your project.

Copy over your newly generated exe file to the shared network path so that all the other users can now run your application.  Run your application from that shared folder on that server and Voila you no longer get the security exception error.  The application message boxes the records from the database.

If You Still Get The Error 

Strange, you shouldn’t.  But if you did make sure your key (.snk) file is visible on some shared network folder.  Make sure your AssemblyInfo.vb file has an AssemblyVersion attribute (the line right before the last line in the image posted of the AssemblyInfo file).  Make certain you got the latest .exe compiled and that you’ve copied that file over to the server.

Finally last thing you can do is to select Build->Publish Project from VS 2005 and tell it to publish the .exe file to a shared (UNC) server.  Go through the wizard and get it to copy it automatically.  Sometimes you will need to install the latest .net framework on the server that hosts the exe file. 

 

 

 

 

Share This: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Facebook
  • Live-MSN
  • TwitThis
  • LinkedIn
  • MySpace
  • email