Running Windows Service Application without installing it - c#

Whem I'm writing a Windows Service and just hit F5 I get the error message that I have to install it using installutil.exe and then run it.
In practice this means everytime I change a line of code:
compile
switch to Developer Command Prompt
remove old version
install new version
start service
That is very inconvenient. Is there a better way to do it?

The best way in my opinion is to use Debug directive. Below is an example for the same.
#if(!DEBUG)
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
// Calling MyService Constructor
new MyService()
};
ServiceBase.Run(ServicesToRun);
#else
MyService serviceCall = new MyService();
serviceCall.YourMethodContainingLogic();
#endif
Hit F5 And set a Breakpoint on your YourMethodContainingLogic Method to debug it.

I usually put the bulk of the service implementation into a class library, and then create two "front-ends" for running it - one a service project, the other a console or windows forms application. I use the console/forms application for debugging.
However, you should be aware of the differences in the environment between the debug experience and when running as a genuine service - e.g. you can accidentally end up dependent on running in a session with an interactive user, or (for winforms) where a message pump is running.

You can write this code in program.cs
//if not in Debug
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
ServiceBase.Run(ServicesToRun);
//if debug mode
MyService service = new MyService();
service.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
in MyService class
public void OnDebug()
{
OnStart(null);
}

You cannot run Windows Service as say another console or WinForms application. It needs to be started by Windows itself.
If you don't have infrastructure ready to use as #Damien_The_Unbeliever suggests (which is what I recommend as well) you can install the service from the debug location. So you use installutil once and point it to executable located in /bin/debug. Then you start a service from services.msc and use Visual Studio > Debug > Attach to Process menu and attach to the Windows service.
You can also consider using Thread.Sleep(10000) as the first line in the OnStart call, or Debugger.Break() to help you out to be able to attach before the service executes any work. Don't forget to remove those before the release.

You can use Environment.UserInteractive variable. Details of implementation here

Here's an easy way I use to debug Windows service applications without installing them, starting via Windows Service Control Manager, attaching to debuggers, etc. The following is in VB but hopefully you get the idea.
In this example, TestService's main class is named svcTest.vb.
Within Shared Sub Main() inside svcTest.Designer.vb, the default code looks something like this:
Dim ServicesToRun() As System.ServiceProcess.ServiceBase
ServicesToRun = New System.ServiceProcess.ServiceBase() {New svcTest}
System.ServiceProcess.ServiceBase.Run(ServicesToRun)
Comment everything out within Main() and add the following 2 lines of code.
Dim objSvc As New svcTest()
objSvc.OnStart(Nothing)
Now just set a breakpoint where you want to start debugging, hit F11 to step into the code, and then proceed as normal as if you were working with a standard desktop application. When you're finished debugging, simply reverse the changes made within Main().
This was done using Visual Studio Enterprise 2017 on Windows Server 2012 R2.

Related

C# Windows service won't start: "Cannot start service from command line or debugger"

Even though there are similar questions, I couldn't find any that solves mine. I have a simple program that runs as a service and I want to start it programatically. It's as simple as this:
private static void StartService()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
ServiceBase.Run(ServicesToRun);
}
As expected, I can't just start my service without installing it. Windows gives me the following error message:
Cannot start service from command line or debugger. A windows service must first be installed using installutil.exe and then started with service explorer, Windows services administrative tool or NET start.
So far so good. So I went there and did just as the docs says:
installutil <my_project>.exe
The installation was successful and I can even start my service from Service Manager or net start. The only problem is: when I debug my application (via F5), Windows keeps showing me the exact same message: Cannot start service (...).
I've found a solution here that uses this:
public void onDebug()
{
OnStart(null);
}
Which allows me to run and debug my application normally, but I actually need it to run as a service and Windows refuses to start that way. Is there anything I'm missing?
It is not in your power to just start a Service like a normal programm. The Service must be registered with and started by the Service manager. That is one of the (many) rules of Windows services. And you have to repeat that for every new build.
As this and other Service related rules (no interactive sessions) can make developing them a Pain, a common approach is to develop them using a console application. I could not find my ideal example, but I found something like it:
https://alastaircrabtree.com/how-to-run-a-dotnet-windows-service-as-a-console-app/
Of course a better longterm plan might be to stop using Services alltogether and switch over to the Windows Task Scheduler. It depends heavily on what exactly you need this code to be able to do in practice.

Multiple service processes (System.ServiceProcess.ServiceBase) in one Windows Service

I've got two service processes (derived from System.ServiceProcess.ServiceBase)
MyService1 and MyService2.
I'm trying to run them both in the Main() of a Windows Service's Programm.cs.
static void Main()
{
ServiceBase[] servicesToRun = { new MyService1(), new MyService2() };
ServiceBase.Run(servicesToRun);
}
In the OnStart methods of both MyService1 and MyService2 I write to a log file so I can tell they are running.
The system builds fine and I can install the service.
But only MyService1 runs. MyService2 doesn't do a thing (i.e. no start-up log entry). When I change the order in the array:
ServiceBase[] servicesToRun = { new MyService2(), new MyService1() }
only MyService2 runs.
To try to get to the bottom of this, I'm using a little tool AndersonImes.ServiceProcess.ServicesLoader (https://windowsservicehelper.codeplex.com/) to get around the limitation that you cannot directly debug a windows service in Visual Studio. With this tool I can get both services MyService1 and MyService2 to start and run next to each other. But I still don't know why Windows is running only the first item in the ServiceBase[] servicesToRun array.
Any ideas?
I finally found the answer here: http://www.bryancook.net/2008/04/running-multiple-net-services-within.html. A well hidden resource, thanks 'bryan'! Hopefully this helps the next developer to save time...
The explanation there around ServicesDependedOn isn't quite matching what I see in my project though. It's not about starting them but making sure they are started. Check out https://msdn.microsoft.com/en-us/library/system.serviceprocess.servicecontroller.servicesdependedon%28v=vs.110%29.aspx as well. I don't need this because they do not depend on each other.

What's the recommended process for building Windows Services in .NET

I'm quite new to development of Windows Services (my background is in Web Development) and I'm a bit confused by the development process for Windows Services.
As I understand it, the service has to be installed every time you compile the code, and then run from the Services MMC snapin.
This seems like an awfully painful process to go through every time you make a change to your code.
Can someone shed some light on the 'recommended' approach for building services?
Thanks
To debug services, I generally use the following boilerplate for Main:
static void Main()
{
ServiceBase[] servicesToRun = new ServiceBase[] { new MyService(); };
#if !DEBUG
//run the service normally using ServiceBase.Run
ServiceBase.Run(servicesToRun);
#else
//debug the process as a non-service by invoking OnStart and then sleeping
foreach (ServiceBase s in servicesToRun)
{
var serviceType = s.GetType();
var onStartMethod = serviceType.GetMethod("OnStart", System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic);
onStartMethod.Invoke(s, new object[] { new string[0] });
}
Debug.WriteLine("done starting services");
while (true)
Thread.Sleep(200);
#endif
}
What this does is use reflection to get the OnStart protected method for each service, invoke it, then sit in a sleep loop to keep the process running.
This example is assuming MyService is the service class that inherits from ServiceBase, which overrides OnStart to spawn off thread(s) and do its thing.
Here I'm using the DEBUG compile-time constant as the controlling factor of whether to start normally or debug as a non-service. If DEBUG is defined it will run in-process as a non-service. Otherwise it does its normal thing calling ServiceBase.Run. Feel free to use a command-line argument or whatever works best for you.
You may need some tweaks or re-factoring most of the logic to console app for easier testing, debugging, as what comes out of the box is really painful.
Here are some resources :
http://candordeveloper.com/2012/12/27/debugging-a-windows-service-application-without-install/
Running Windows Service Application without installing it
the easiest of them might be putting
#if DEBUG
//your logic
#endif
in your logic, putting a breakpoint and hitting F5, this is what i do most of the time.
Would be interesting to know if there is even better ways :)
Answers from Bravo 11 and Ic. give some good tips and tricks. I will add some:
Be aware that running as as service has also some implications regarding login / security context:
running under SYSTEM, you cannot access network file shares normally (there is a way adding the machine account to the ACL however)
running under a (domain) user account needs "logon as service" privileges, which is IMHO the most common cause of service starting problems in enterprise environments (the GPO settings may be adjusted). In addition, you do not have access to the desktop, so if a popup will be displayed waiting for the user, the service hangs.
in the development phase, you can swap DLLs or even the EXE if the service is not currently running without uninstall / install
use Windows event log extensively.
These differences between services and "normal application" are important enough for me to let this run directly on a server as often as possible.
In my services, I use:
protected override void OnStart(string[] args)
{
// this is not just a simple message, this has to be called very early before any worker thread
// to prevent a race condition in the .NET code of registering the event source
EventLog.WriteEntry("XXXXService is starting", EventLogEntryType.Information, 1000);
....
And do not forget that OnStart() and OnStop()should not contain long running code. You normally start a worker thread in OnStart() which runs until some notification (set in OnStop) was triggered.

How do you debug a Windows Service?

I read the MSDN article on the topic. To quote:
Because a service must be run from
within the context of the Services
Control Manager rather than from
within Visual Studio, debugging a
service is not as straightforward as
debugging other Visual Studio
application types. To debug a service,
you must start the service and then
attach a debugger to the process in
which it is running. You can then
debug your application using all of
the standard debugging functionality
of Visual Studio.
Now my problem is that my service fails to start in the first place. First it crashes, and says:
An unhandled exception
(System.Runtime.InteropServices.COMException)
occurred in MyServiceName.exe[3596])
and suggests me to debug it (the debugger instance instantly crashes when I choose one). Then it says
Could not start the MyServiceName
service on Local Computer. Error
1053: The service did not respond to
the start or control request in a
timely fashion
So, how can I investigate/debug the reason that my service won't start? The thing is I created a console application that does EXACTLY what the service does and it works fine. (I mean I just copied the OnStart() method's and the main loop's contents to main).
Any help would be appreciated.
The Service is written in C# with heavy use of interop. I am using VS2008
You could use a parameter to let your application decide whether to start as service or regular app (i.e. in this case show a Form or start the service):
static void Main(string[] args)
{
if ((1 == args.Length) && ("-runAsApp" == args[0]))
{
Application.Run(new application_form());
}
else
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
}
Now if you pass the parameter "-runAsApp" you can debug the application normally - the SCM won't pass this parameter, so you can also use it as service w/o any code change (provided you derive from ServiceBase)
Edit:
The other difference with windows services is identity (this might be especially important with InterOp) - you want to make sure you are testing under the same identity in "app" mode as well as service mode.
To do so you can use impersonation (I can post a C# wrapper if it helps, but this can be easily googled) in app mode to use the same identity your windows service will be running under i.e. usually LocalService or NetworkService.
If another identity is required you can add settings to the app.config that allow you to decide whether to use credentials, and if so which user to impersonate - these settings would be active when running as app, but turned off for the windows service (since the service is already running under the desired identity):
<appSettings>
<add key="useCredentials" value="false"/>
<add key="user" value="Foo"/>
<add key="password" value="Bar"/>
</appSettings>
I usually just manually set a breakpoint, then point it to the currently open project in c#. The code to set a breakpoint is:
System.Diagnostics.Debugger.Break();
That should get you started, then you can just step through your code and see what's really happening.
I stole this from C. Lawrence Wenham, so I can't really take credit, but you can programmatically attach a debugger to a service, WITHOUT breaking execution at that point, with the following code:
System.Diagnostics.Debugger.Launch();
Put this in your service's OnStart() method, as the first line, and it will prompt you to choose an instance of VS to attach its debugger. From there, the system will stop at breakpoints you set, and on exceptions thrown out. I would put an #if DEBUG clause around the code so a Release build won't include it; or you can just strip it out after you find the problem.
You can use WinDbg/NTSD (another debugger from the "Debugging tools for windows" package) to start a debugger together with your service.
To do this open "gflags" (also available in the above mentioned package) to the "Image file" tab and set the path to debugger executable for your image file (service);
If your service is marked as interactive (only possible if it runs under the SYSTEM account) you can directly start WinDbg, just set the debugger to something like "PATH_TO_WINDBG\windbg.exe -g -G" (the -g / -G are needed so that the debugger doesn't break execution on application start or end - the default behaviour). Now when starting your service the windbg window should pop-up and will catch any unhandled exception.
If your service is not interactive you can start the NTSD debugger (a command line debugger) in remote mode and connect to it from WinDbg (that can even be running in another PC). To do this set the debugger in gflags to something like "PATH_TO_NTSD\ntsd -remote tcp:port=6666,server=localhost". Then connect to the remote debugger by starting windbg with something like "windbg -remote tcp:port=6666,server=localhost" and you should have complete control over the other debugging session.
As for finding the source of the exception itself a windbg tutorial is over the topic here but as a start try to execute the "!analyze -v" command after the exception was caught - with some luck this is all information you'll need..
Note: maybe this is overkill for your case but with this approach you can even debug services during system start-up (I had once a timing problem with a service had an issue only when starting the first time with the system)
One thing I do (which may be kind of a hack) is put a Thread.Sleep(10000) right at the beginning of my OnStart() method. This gives me a 10-second window to attach my debugger to the service before it does anything else.
Of course I remove the Thread.Sleep() statement when I'm done debugging.
One other thing you may do is the following:
public override void OnStart()
{
try
{
// all your OnStart() logic here
}
catch(Exception ex)
{
// Log ex.Message
if (!EventLog.SourceExists("MyApplication"))
EventLog.CreateEventSource("MyApplication", "Application");
EventLog.WriteEntry("MyApplication", "Failed to start: " + ex.Message);
throw;
}
}
When you log ex.Message, you may get a more detailed error message. Furthermore, you could just log ex.ToString() to get the whole stack trace, and if your .pdb files are in the same directory as your executable, it will even tell you what line the Exception occurred on.
Add lots of verbose logging in your OnStart. It's painful and old school, but it works.
Seems like the problem is with the user context. Let me confirm whether my assumptions are right.
When you say that the code works perfectly from console application, I assume you are executing the Console application under the same user which you had logged in.
When you say that the same code crashes while called from the windows service, I assume the service is running in "Local System" account in your development machine.
If both my assumptions are right, please try out the following steps.
In the services listing right-click your service, select properties and then "Log On" tab.
Select the option "This account" and provide the existing username and password.
Now try starting the service. It should now start without any errors.
Following could be the root cause of your error
If you are using SQL Server make sure you are not using SSPI authentication.
If you are trying to read any shared folder\resource which you don't have permission when using "local system" account.
If any of the required dependencies required by the application is in a different folder which the "Local System" user doesn't have permission to access.
If you are using VBA automation which wont work in "Local System" account.
Try disabling your firewall or antivirus.
You could add some logging around the interop calls to find out which one fails.
Also services by default aren't associated with a desktop; if you open the services.msc control panel applet, get the properties of your service, go to the "Log On" tab, you could check "Allow service to interact with desktop". This could fix the problem for you in some cases.
I would assume the reason could be causing because of heavy use of interops. So you need to tackle this problem differently. I would suggest create a windows or console app with same logic of you service and make sure that it works first without any issues, and then you may want to go with creation of the Win service.
Debugging services is a pain, particularly since startup seems to be when many of the problems manifest (at least for us).
What we typically do is extract as much of the logic as possible to a single class that has start and stop methods. Those class methods are all that the service calls directly. We then create a WinForm application that has two buttons: one to invoke start, another to invoke stop. We can then run this WinForm applicaiton directly from the debugger and see what is happening.
Not the most elegant solution, but it works for us.
Check out this question, which discusses how to catch unhandled exceptions in a window service.
In order to attach a debugger to the Windows Service, it needs to be started first. The reason why the service failed to start can be checked in Windows Event Log.
After that the process of attaching a debugger is pretty straight forward from Visual Studio Debug->Attach To Process.
What I've done is implemented by OnStart() to look something like this:
_myBusinessObject = new MyBusinessObject();
After the Business Object has been constructed, timers and IPC handlers do all the real (Service) work.
Doing it like this allows you to create a Forms/WPF application that call the same code above in the Form_Loaded handler. This way, debugging the Forms application is the exact same as debugging the Service.
The only issue is that if you are using app.config values, there will be a second app.config file that needs to be kept up-to-date.
Use following Code in Service OnStart Method:
System.Diagnostics.Debugger.Launch();
Choose Visual Studio option from Pop Up message
read the 2 articles mentioned here:
http://geekswithblogs.net/BlackRabbitCoder/archive/2011/03/01/c-toolbox-debug-able-self-installable-windows-service-template-redux.aspx
Step 1 - Add #if region to your Program.cs
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new StockInfoService()
};
ServiceBase.Run(ServicesToRun);
#if (!DEBUG)
ServiceBase[] ServicesToRun = new ServiceBase[] { new SqlBackupService() };
ServiceBase.Run(ServicesToRun);
#else
StockInfoService service = new StockInfoService();
service.OnStart();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#endif
}
Step 2 - In Service.cs change your OnStart(string[] args) method without parameter one. (I commended mine.)
public void OnStart()
//protected override void OnStart(string[] args)
{
**Do your thing.
}
Step 3 - Simply hit Start (F5) and debug your code.

Unable to start service written in .NET 2.0 on Windows XP Embedded

I've created a small executable that can be launched either as a normal application by calling MyApp.exe or as a service by calling MyApp.exe -s. Because I'm trying to keep as simple as possible, I "install" this app by manually running
sc create MyAppService binPath= "C:\MyApp\MyApp.exe -s"
Then I start the service with net start MyAppService like normal.
On two Windows XP machines and two Windows 2000 machines, this works fine. However, on two different Windows XP Embedded machines, when I try to start the service I get the message:
System error 1083 has occurred.
The executable program that this service is configured to run in does not implement the service.
On one machine, I was able to fix this by uninstalling and reinstalling .NET 2.0, but on the second machine this did not work.
I'm not sure how to go about debugging this, and searching google only seems to turn up specific services that fail with this message such as BITS and an Exchange service.
Below are the classes MyApp, which is the startup class, and MyAppService, which is the class that extends ServiceBase. Thanks in advance for any direction on this.
MyApp.cs
static class MyApp
{
[STAThread] static void Main( string[] args )
{
....
switch ( arg1 )
{
case "-s":
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyAppService() };
ServiceBase.Run( ServicesToRun );
break;
....
}
}
}
MyAppService.cs:
class MyAppService : ServiceBase
{
static MyAppService()
{
// ...
}
protected override void OnStart( string[] args )
{
// ...
}
}
On the desktop, this can happen if the service isn't registered correctly in the Windows Registry under the account that the svchost instance is supposed to run under. I don't have experience in XPe, but try looking in HKLM\Software\Microsoft\Windows NT\CurrentVersion\Svchost and make sure that MyAppService is correctly listed for the account.
Try to check in the Event log if there is useful info including Security log.
It seems did not recognize the MyAppService as a service or MyApp.exe does not expose any services to the XPe. Focus on this thing to get the root cause.
For fast testing, you can get XPe run in your development PC by using VMWare. VMWare has the way to copy the current running XPe into image and copy to your PC but not sure if it can work properly.
It appears that I have the same problem. The ServiceController.Start() does not start service successfully. The application is in C# .NET2 and running in Window XPe. The work around is below:
TimeSpan timeout = TimeSpan.FromMilliseconds(20000);
while (true)
{
ServiceController service = new ServiceController("myservice");
service.MachineName = ".";
try
{
service.Start()
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
}
catch
{
service.Stop();
continue;
}
}
after looping 2 or 3 times, the service usually get started successfully.
But 30-40 seconds has passed. This is not acceptable.
Dos anybody have experienced on this issue? Thanks!

Categories