![]() |
Platforms, Frameworks & Libraries »
.NET Framework »
How To
Intermediate
License: The Code Project Open License (CPOL)
C# Generic Dynamic Windows Service using .NET ReflectionBy AHA technique to create Windows Service apps that's configurable and dynamic by using the .NET Reflection. |
C#, .NET (.NET3.5), Visual-Studio (VS2008), Architect, Dev, Design
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
This article shows a technique to design Windows Service apps with the following goals:
The sample code I presented here is the basic framework and has been tested with Visual Studio 2008 and .NET 3.5 Framework. But the concept should be applicable to other versions as well.
If you have never created a Windows Service application, there is a "walkthrough" article on the MSDN library site. Obviously, there're many useful articles on The Code Project as well.
By using the presented technique, to create a Windows Service app will just require you to create a new "Console" project using the Visual Studio.
The sample Visual Studio solution consists of 4 projects. They are:
GDWS.Common - That's where the generic reusable code for the Windows Service sits. GDWS.ExampleService - This is an example "server" logic that's aimed to be built as a .NET assembly. GDWS.ExampleServiceProgram - This is an example "Console" app that actually invokes the server logic. SetupExampleService - This is a typical "Setup & Deployment" project to demonstrate that this technique also works seamlessly with the standard setup mechanism. In a nutshell, the Main() program is as simple as this:
namespace GDWS.ExampleServiceProgram
{
class Program
{
static void Main(string[] args)
{
ServiceMainProgram.ServiceMain(args);
}
}
[RunInstaller(true)]
public class ExampleServiceInstaller : CustomServiceInstaller
{
}
}
This class mainly reads the ServiceInstall.xml file in order to tell Windows Installer the "Service Name", the "Service Display Name", and the "Service Descriptions".
In order to load the "server logic" dynamically, .NET Reflection is used to load the DLL that encapsulates the server logic. The two constructors are private, and you use the two static methods to invoke the process.
public class ServiceMainProgram
{
...
...
public static void Service(string[] args, Type type)...
public static void Service(string[] args)...
...
}
The static method that takes two arguments requires you to submit a Type, so that during creation of an object internally it can use Reflection to find out that the two required static methods StartThreadProc and StopThreadProc are present.
The second static method that takes only one argument reads the name of the Type from the ServiceConfig.xml file, which also tells it where to find the server logic assembly DLL. Once the path of the DLL is located, the assembly is loaded by using Reflection.
private Type LoadAssemby(string configFileName)
{
...
...
Assembly asm = Assembly.LoadFile(Path.GetFullPath(assemblyFullPath));
...
Type type = asm.GetType(typeName);
...
}
Once the Type is found and checked, the following code can utilize the reflected methods:
private void Run()
{
if (debugMode) RunDebug();
else
{
ServiceBase[] servicesToRun = new ServiceBase[]
{ new GenericService(threadProcType) };
ServiceBase.Run(servicesToRun);
}
}
private void RunDebug()
{
...
...
MethodInfo mStart = threadProcType.GetMethod(START_THREAD_PROC);
// assuming static method, hence no need to pass any instantiated object
mStart.Invoke(null, null);
bool stop = false;
while (!stop)
{
...
if (k.KeyChar == 'q' || k.KeyChar == 'Q')
{
...
MethodInfo mStop = threadProcType.GetMethod(STOP_THREAD_PROC);
// assuming static method, hence no need to pass any instantiated object
mStop.Invoke(null, null);
stop = true;
}
...
}
}
For debugging purposes, define a command line argument debug or under the Command Prompt, just type yourservice.exe debug to invoke the program into debug mode.
You can install the sample service app using the bundled Setup project.
To quickly test the app as a Windows Service, you can use the installutil.exe and uninstall it by calling installutil.exe /u.
<?xml version="1.0" encoding="utf-8" ?>
<ConfigService>
<ServiceName value="ExampleService"/>
<ServiceDisplayName value="An Example Service"/>
<ServiceDescription value="An example service
that demonstrates a generic and dynamic technique."/>
</ConfigService>
<?xml version="1.0" encoding="utf-8" ?>
<InstallService>
<ServiceAssemblyFullPath value=
"..\..\..\GDWS.ExampleService\bin\Debug\GDWS.ExampleService.dll"/>
<TypeName value="GDWS.ExampleService.ThreadProcExample"/>
</InstallService>
Please note that, although the ServiceAssemblyFullPath is specified as a relative path, the code will try to locate it locally if it cannot find it at the first instance.
General
News
Question
Answer
Joke
Rant
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 31 Jan 2008 Editor: Deeksha Shenoy |
Copyright 2008 by AH Everything else Copyright © CodeProject, 1999-2010 Web21 | Advertise on the Code Project |