Service Error 1053: Could not start in timely fashion - c#

Before you ask, yes I searched and searched on this issue, tried what others had work for them and came up with nothing. I have tried:
Running in release mode
Running on LocalSystem, LocalService, and named account
I have no debug code in my project
The summary of my project is a Windows service that scans for files in a source folder and at a set time, converts them and places them in a destination folder. These settings can be changed in a GUI which changes an XML file which the service scans periodically.
The finished product is wrapped in InstallShield. Everything works from VisualStudio. I can install the program and the service works perfectly. When I take my release build and install it myself on the same machine, I get this 1053 error.
Here is my OnStart
protected override void OnStart(string[] args)
{
// Update the service state to Start Pending.
ServiceStatus serviceStatus = new ServiceStatus();
serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
serviceStatus.dwWaitHint = 100000;
SetServiceStatus( this.ServiceHandle, ref serviceStatus );
// Set up a timer to trigger every 30s
System.Threading.Thread t1 = new System.Threading.Thread( new System.Threading.ThreadStart( this.InitTimer ) );
t1.Start();
// Set folders and time from xml
System.Threading.Thread t2 = new System.Threading.Thread( new System.Threading.ThreadStart( this.InitSettings ) );
t2.Start();
// Update the service state to Running.
eventLog1.WriteEntry( "Service successfully started", EventLogEntryType.Information, eventId++ );
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus( this.ServiceHandle, ref serviceStatus );
}
Here is my main
public WTVService(string[] args)
{
InitializeComponent();
string eventSourceName = "Searcher";
string logName = "WTVConverter";
if ( args.Count() > 0 )
{
eventSourceName = args[0];
}
if ( args.Count() > 1 )
{
logName = args[1];
}
eventLog1 = new EventLog();
if ( !EventLog.SourceExists( eventSourceName ) )
{
EventLog.CreateEventSource( eventSourceName, logName );
}
eventLog1.Source = eventSourceName; eventLog1.Log = logName;
}
Let me know what other info might be helpful.
Edit: Also, if it makes a difference, the error comes up instantly, not after the supposed 30 second timeout rule.

So this is interesting. I'm sure the InstallShield crowd is kind of limited here, but this might help someone. What ended up working was changing the build mode from SingleImage to DVD-5. I could not say why, but it now works perfectly. I tested on a machine that had never before run my program and it all worked.

When you are deploying any service through InstallShield you need to either select LocalSystem username or the Admin user credentials.
For execution of any windows service, it requires Admin user or LocalSystem user.
So there is provision of user credentials fr a servive in InstallShield.

Related

Run windows service automatically forever, after starting manually for the first time

I created a Windows service application. It runs depending on the app settings which is included in the app.config file. It will be installed on different locations (networks, PCs) at the same time. Each location will need to set its own parameters in the app.config file. So I don't want it to run automatically after installation. By doing that each location users will be able to open configuration file and change it. Then they can start the service. But after that the service will run forever. Even when they restart the windows, it will run automatically after Windows opened.
Here is my installer class. It doesn't run automatically after installation. That's good. But if I run it manually and restart PC, when restart complete, it still waits to be started manually. What should I do?
public partial class MyServiceInstaller : System.Configuration.Install.Installer
{
ServiceInstaller _serviceInstaller = new ServiceInstaller();
ServiceProcessInstaller _processInstaller = new ServiceProcessInstaller();
string _serviceName = "MyService";
string _displayName = "My Service";
string _description = "My Service - Windows Service";
public MyServiceInstaller()
{
InitializeComponent();
this.BeforeInstall += new InstallEventHandler(MyServiceInstaller_BeforeInstall);
_processInstaller.Account = ServiceAccount.LocalSystem;
_serviceInstaller.StartType = ServiceStartMode.Automatic;
_serviceInstaller.Description = _description;
_serviceInstaller.ServiceName = _serviceName;
_serviceInstaller.DisplayName = _displayName;
Installers.Add(_serviceInstaller);
Installers.Add(_processInstaller);
}
protected override void OnCommitted(System.Collections.IDictionary savedState)
{
ServiceController sc = new ServiceController(_serviceName);
if (sc.Status != ServiceControllerStatus.Running)
{
TimeSpan timeout = TimeSpan.FromMilliseconds(10000);
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, timeout);
sc.Stop();
}
else
{
RestartService(10000);
}
}
private void RestartService(int timeoutMiliseconds)
{
ServiceController service = new ServiceController(_serviceName);
int millisec1 = Environment.TickCount;
TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMiliseconds);
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
int millisec2 = Environment.TickCount;
timeout = TimeSpan.FromMilliseconds(timeoutMiliseconds - (millisec2 - millisec1));
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
}
void MyServiceInstaller_BeforeInstall(object sender, System.Configuration.Install.InstallEventArgs e)
{
List<ServiceController> services = new List<ServiceController>(ServiceController.GetServices());
foreach (ServiceController s in services)
{
if (s.ServiceName == this._serviceInstaller.ServiceName)
{
ServiceInstaller ServiceInstallerObj = new ServiceInstaller();
ServiceInstallerObj.Context = new System.Configuration.Install.InstallContext();
ServiceInstallerObj.Context = Context;
ServiceInstallerObj.ServiceName = _serviceName;
ServiceInstallerObj.Uninstall(null);
}
}
}
}
You can make this easier for yourself, by downloading the NuGet Package called TopShelf.
To summarize briefly, quoting from their page:
Topshelf is a framework for hosting services written using the .NET
framework. The creation of services is simplified, allowing developers
to create a simple console application that can be installed as a
service using Topshelf. The reason for this is simple: It is far
easier to debug a console application than a service. And once the
application is tested and ready for production, Topshelf makes it easy
to install the application as a service.
Your code already seems to be setting the startup type to Automatic.
Can you check the event log to see if your service is attempting to start automatically, but failing. This can happen if your service depends on another service which has not yet started.
You can use sc config after service start to modify start type.
eg.
sc config yourservicename start=auto
Or you can use ChangeServiceConfig.

Start an offline ClickOnce Application and wait for Exit

I have deployed a ClickOnce Windows Forms application (App A)
Another application (App B) starts App A with a filename as parameter.
I do this with this Code
var basePath = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
var location = String.Format(#"{0}\{1}\{2}\{3}",
basePath, "MyCompany", "MyProduct", "MyApp.appref-ms");
var fileName = #"c:\temp\somefile.ext";
var uri = new Uri(fileName).ToString();
Process.Start(location, uri);
App A grabs the file name from AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData[0] and show the content.
This works like a charm. However, now I want App B to wait for App A to exit.
But a call to Process.WaitForExit() returns instantly.
Is there a way to open a ClickOnce App and wait for it to exit? I can, if necessary, change the way the app is opend but the requirement is that I need to run the app as a ClickOnce app (I know that somewhere in my user profile AppData\Local\Apps\2.0\ folder the exe exists and can be started directly but If I do that ApplicationDeployment.IsNetworkDeployed is false and ApplicationDeployment.CurrentDeployment is null. In that I loose the ClickOnce Update Capabilities).
my suggestion would be to use Mutex in App A, and let App B check and wait for it. This is the cleanest way from my point of view.
App A does this when starts:
private static Mutex mutex;
public static void Main()
{
// if you want your app to be limited to a single instance
// across ALL SESSIONS (multiple users & terminal services), then use the following line instead:
// string mutexName = string.Format("Global\\{0}", ProgramInfo.AssemblyGuid);
var mutexName = string.Format("Local\\{0}", SOME_SHARED_GUID);
mutex = new Mutex(true, mutexName, out singleInstance);
if (singleInstance == false)
{
// that means your app has more than one instance running
// you need to decide what to do here.
}
// rest of initialization code
Application.Run();
// release the mutex so App B can continue
mutex.ReleaseMutex();
}
and App B just waits for the mutex to be released:
Process.Start(location, uri);
Thread.Sleep(5000); // give it 5 seconds or so to check for updates and start
var mutexName = string.Format("Local\\{0}", SOME_SHARED_GUID);
mutex = new Mutex(false, mutexName);
mutex.WaitOne();
The problem is that starting the appref-ms process does not actually start the application it starts the deployment manifest, which then launches the application itself, so the process you are starting exits straight away.
You can add a check to see when you application has started if you know the name (which I assume you do) like this:
string myAppName = "YourAppName";
DateTime startTime = DateTime.Now;
int newProcessId = 0;
List<int> runningProcessIds = new List<int>();
//find all the running processes and record their Ids
foreach (void proc_loopVariable in Process.GetProcessesByName(myAppName)) {
proc = proc_loopVariable;
runningProcessIds.Add(proc.Id);
}
//start the new process
Process.Start(location);
//wait for the new application to be started
while (!(Process.GetProcessesByName(myAppName).Count != runningProcessIds.Count)) {
//timeout if we have not seen the application start
if ((DateTime.Now - startTime).TotalSeconds > 30)
break;
}
//loop through all the running processes again to find the id of the one that has just started
foreach (void proc_loopVariable in Process.GetProcessesByName(myAppName)) {
proc = proc_loopVariable;
if (!runningProcessIds.Contains(proc.Id)) {
newProcessId = proc.Id;
break;
}
}
//wait for the application to finish
Process.GetProcessById(newProcessId).WaitForExit();
Debug.WriteLine("Finished");

Start Windows Service in C#

I want to start a windows service that was just installed.
ServiceBase[] ServicesToRun;
if (bool.Parse(System.Configuration.ConfigurationManager.AppSettings["RunService"]))
{
ServicesToRun = new ServiceBase[] { new IvrService() };
ServiceBase.Run(ServicesToRun);
}
The IvrService code is:
partial class IvrService : ServiceBase
{
public IvrService()
{
InitializeComponent();
Process myProcess;
myProcess = System.Diagnostics.Process.GetCurrentProcess();
string pathname = Path.GetDirectoryName(myProcess.MainModule.FileName);
//eventLog1.WriteEntry(pathname);
Directory.SetCurrentDirectory(pathname);
}
protected override void OnStart(string[] args)
{
string sProcessName = Process.GetCurrentProcess().ProcessName;
if (Environment.UserInteractive)
{
if (sProcessName.ToLower() != "services.exe")
{
// In an interactive session.
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new IvrInteractive());
IvrApplication.Start(); // the key function of the service, start it here
return;
}
}
}
I am not sure how to start the service. Using ServiceController.Start()? But I already have ServiceBase.Run(ServicesToRun); Is it for starting a service?
Code hint is definitely appreciated.
To answer the question about starting a service from code, you would want something like this (which would be equivalent to running net start myservice from the command line):
ServiceController sc = new ServiceController();
sc.ServiceName = "myservice";
if (sc.Status == ServiceControllerStatus.Running ||
sc.Status == ServiceControllerStatus.StartPending)
{
Console.WriteLine("Service is already running");
}
else
{
try
{
Console.Write("Start pending... ");
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 10));
if (sc.Status == ServiceControllerStatus.Running)
{
Console.WriteLine("Service started successfully.");
}
else
{
Console.WriteLine("Service not started.");
Console.WriteLine(" Current State: {0}", sc.Status.ToString("f"));
}
}
catch (InvalidOperationException)
{
Console.WriteLine("Could not start the service.");
}
}
This will start the service, but keep in mind that it will be a different process than the one that is executing the above code.
Now to answer the question about debugging a service.
One option is to attach after the service has been started.
The other is to make your service executable be able to run the main code, not as a service but as a normal executable (typically setup via a command line parameter). Then you can F5 into it from your IDE.
EDIT: Adding sample flow of events (based on questions from some of the comments)
OS is asked to start a service. This can be done from the control panel, the command line, APIs (such as the code above), or automatically by the OS (depending on the service's startup settings).
The operating system then creates a new process.
The process then registers the service callbacks (for example ServiceBase.Run in C# or StartServiceCtrlDispatcher in native code). And then starts running its code (which will call your ServiceBase.OnStart() method).
The OS can then request that a service be paused, stopped, etc. At which point it will send a control event to the already running process (from step 2). Which will result in a call to your ServiceBase.OnStop() method.
EDIT: Allowing a service to run as a normal executable or as a command line app: One approach is to configure your app as a console application, then run different code based on a command line switch:
static void Main(string[] args)
{
if (args.Length == 0)
{
// we are running as a service
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService() };
ServiceBase.Run(ServicesToRun);
}
else if (args[0].Equals("/debug", StringComparison.OrdinalIgnoreCase))
{
// run the code inline without it being a service
MyService debug = new MyService();
// use the debug object here
}
First you need to install the service using InstallUtil, e.g.
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe C:\MyService.exe
You need to start the service from the command line, e.g.
net start ServiceName // whatever the service is called
Then you need to attach to the process with Visual Studio, via Tools > Attach To Process.
Stick the breakpoints in the solution wherever you want it to break and the dev environment should take over.
To start it from the dev environment, put the net start ServiceName command into a batch file, and then in the Project Properties > Build Events "Post Build Event Command Line" you can add the path to the batch file.
*note that looking now, I'm not sure if you need to even use a batch file, you might be able to put the command directly in there. Try and edit this answer with whatever works.

Process cannot access the file because it is being used by another process on Directory.Move()

We have a client application with the following architecture: a manager process manages a couple of worker processes (reader and writer) and periodically queries the server for version updates. If a version update is available, the manager downloads it to the client computer, shuts down the worker threads, starts an updater process to handle the update and exits. The updater, on startup, receives the manager PID and the update file location; it then waits for the manager to exit, backs up all files of the manager and workers, recreates their directories and spreads the new version files to the new directories.
When going through this process as described, the first call to Directory.Move(string, string) – which serves to back up the manager directory – throws the IOException. The strange thing is, if I let the manager shut down without starting the updater and then start the updater executable myself, the exception is not thrown.
Manager code for managing worker threads:
public void Run()
{
_config = GetConfiguration();
Process reader, writer;
//Start reader and writer with appropriate arguments
//Keep reader and writer alive
reader.Kill();
writer.Kill();
reader.WaitForExit();
writer.WaitForExit();
reader.Dispose();
writer.Dispose();
}
Manager code for querying the database:
EndpointAddress endpoint;
BasicHttpBinding httpBinding = new BasicHttpBinding();
httpBinding.MaxReceivedMessageSize = 2000000000;
ChannelFactory<IService> chanFactory = new ChannelFactory<IService>(httpBinding);
IService service;
try
{
endpoint = new EndpointAddress(ConfigurationManager.AppSettings["Service URL"]);
service = chanFactory.CreateChannel(endpoint);
UpdateInstructions instructions = service.GetUpdateInstructions(_config.SiteID, Assembly.GetExecutingAssembly().GetName().Version.ToString(), _config.Version);
HandleUpdateInstructions(instructions); //Downloads files and starts the updater process
}
catch (Exception ex)
{
//Report exception
}
finally
{
if (chanFactory.State != CommunicationState.Faulted)
chanFactory.Close();
}
Manager code for starting the updater process:
private void StartUpdater(string updateFilePath, string configFilePath)
{
ProcessStartInfo updaterStartInfo = new ProcessStartInfo(_config.UpdaterExePath, string.Format("{0} \"{1}\" \"{2}\"", Process.GetCurrentProcess().Id, updateFilePath, configFilePath));
Process updater = Process.Start(updaterStartInfo);
updater.Dispose();
}
Updater code for waiting for the manager to close:
bool isManagerUp = true;
while (isManagerUp)
{
try
{
Process managerProcess = Process.GetProcessById(bDoxForceManagerPID);
managerProcess.WaitForExit();
managerProcess.Dispose();
isManagerUp = false;
}
catch
{
isManagerUp = false;
}
}
Updater code for updating a module:
//updateDirectory is the directory of the new files to be inserted, moduleDirectory is the working directory of the module that will be updated, in this case the manager
private void UpdateModule(DirectoryInfo updateDirectory, DirectoryInfo moduleDirectory)
{
string backupDirectory = MakeBackupDirectoryFullPath(moduleDirectory.Parent.FullName);
Directory.Move(moduleDirectory.FullName, backupDirectory); // IOException as described above.
Directory.CreateDirectory(moduleDirectory.FullName);
foreach (FileInfo updateFile in updateDirectory.EnumerateFiles())
{
string newFilePath = moduleDirectory.FullName + "\\" + updateFile.Name;
File.Copy(updateFile.FullName, newFilePath);
}
Directory.Delete(updateDirectory.FullName, true);
}
Thank to Adam Caviness answer we were able to figure it out.
Our processes were Console applications, they created a .vshost files that kept on working after the processes were order to terminate.
Attempting to move the directory with the running .vshost files caused the problem.
Turning the processes into Windows services didn't create a .vshost files and solved this issue.
I suggest you use MS (formally SysInternals) Process Monitor to track this down and thus first rule out any anti-virus/anti-malware/heuristics (should you not be going av commando like we devs do). The clue to that makes me point you in this direction is that you can start the updater yourself and the exception is not thrown. Just this year already I've ran into this issue and had to add an AV directory exclusion.

How do I debug Windows services in Visual Studio?

Is it possible to debug the Windows services in Visual Studio?
I used code like
System.Diagnostics.Debugger.Break();
but it is giving some code error like:
I got two event error: eventID 4096
VsJITDebugger and "The service did
not respond to the start or control
request in a timely fashion."
Use the following code in service OnStart method:
System.Diagnostics.Debugger.Launch();
Choose the Visual Studio option from the pop up message.
Note: To use it in only Debug mode, a #if DEBUG compiler directive can be used, as follows. This will prevent accidental or debugging in release mode on a production server.
#if DEBUG
System.Diagnostics.Debugger.Launch();
#endif
You can also try this.
Create your Windows service and install and start…. That is, Windows services must be running in your system.
While your service is running, go to the Debug menu, click on Attach Process (or process in old Visual Studio)
Find your running service, and then make sure the Show process from all users and Show processes in all sessions is selected, if not then select it.
Click the Attach button
Click OK
Click Close
Set a break point to your desirable location and wait for execute. It will debug automatic whenever your code reaches to that point.
Remember, put your breakpoint at reachable place, if it is onStart(), then stop and start the service again
(After a lot of googling, I found this in "How to debug the Windows Services in Visual Studio".)
You should separate out all the code that will do stuff from the service project into a separate project, and then make a test application that you can run and debug normally.
The service project would be just the shell needed to implement the service part of it.
Either that as suggested by Lasse V. Karlsen, or set up a loop in your service that will wait for a debugger to attach. The simplest is
while (!Debugger.IsAttached)
{
Thread.Sleep(1000);
}
... continue with code
That way you can start the service and inside Visual Studio you choose "Attach to Process..." and attach to your service which then will resume normal exution.
Given that ServiceBase.OnStart has protected visibility, I went down the reflection route to achieve the debugging.
private static void Main(string[] args)
{
var serviceBases = new ServiceBase[] {new Service() /* ... */ };
#if DEBUG
if (Environment.UserInteractive)
{
const BindingFlags bindingFlags =
BindingFlags.Instance | BindingFlags.NonPublic;
foreach (var serviceBase in serviceBases)
{
var serviceType = serviceBase.GetType();
var methodInfo = serviceType.GetMethod("OnStart", bindingFlags);
new Thread(service => methodInfo.Invoke(service, new object[] {args})).Start(serviceBase);
}
return;
}
#endif
ServiceBase.Run(serviceBases);
}
Note that Thread is, by default, a foreground thread. returning from Main while the faux-service threads are running won't terminate the process.
A Microsoft article explains how to debug a Windows service here and what part anyone can miss if they debug it by attaching to a process.
Below is my working code. I have followed the approach suggested by Microsoft.
Add this code to program.cs:
static void Main(string[] args)
{
// 'If' block will execute when launched through Visual Studio
if (Environment.UserInteractive)
{
ServiceMonitor serviceRequest = new ServiceMonitor();
serviceRequest.TestOnStartAndOnStop(args);
}
else // This block will execute when code is compiled as a Windows application
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new ServiceMonitor()
};
ServiceBase.Run(ServicesToRun);
}
}
Add this code to the ServiceMonitor class.
internal void TestOnStartAndOnStop(string[] args)
{
this.OnStart(args);
Console.ReadLine();
this.OnStop();
}
Now go to Project Properties, select tab "Application" and select Output Type as "Console Application" when debugging, or "Windows Application" when done with debugging, recompile and install your service.
You can make a console application. I use this main function:
static void Main(string[] args)
{
ImportFileService ws = new ImportFileService();
ws.OnStart(args);
while (true)
{
ConsoleKeyInfo key = System.Console.ReadKey();
if (key.Key == ConsoleKey.Escape)
break;
}
ws.OnStop();
}
My ImportFileService class is exactly the same as in my Windows service's application, except the inheritant (ServiceBase).
I found this question, but I think a clear and simple answer is missing.
I don't want to attach my debugger to a process, but I still want to be able to call the service OnStart and OnStop methods. I also want it to run as a console application so that I can log information from NLog to a console.
I found these brilliant guides that does this:
Debugging a Windows Service Project
Easier way to debug a Windows service
Start by changing the projects Output type to Console Application.
Change your Program.cs to look like this:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
// Startup as service.
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
if (Environment.UserInteractive)
{
RunInteractive(ServicesToRun);
}
else
{
ServiceBase.Run(ServicesToRun);
}
}
}
Then add the following method to allow services running in interactive mode.
static void RunInteractive(ServiceBase[] servicesToRun)
{
Console.WriteLine("Services running in interactive mode.");
Console.WriteLine();
MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart",
BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ServiceBase service in servicesToRun)
{
Console.Write("Starting {0}...", service.ServiceName);
onStartMethod.Invoke(service, new object[] { new string[] { } });
Console.Write("Started");
}
Console.WriteLine();
Console.WriteLine();
Console.WriteLine(
"Press any key to stop the services and end the process...");
Console.ReadKey();
Console.WriteLine();
MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop",
BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ServiceBase service in servicesToRun)
{
Console.Write("Stopping {0}...", service.ServiceName);
onStopMethod.Invoke(service, null);
Console.WriteLine("Stopped");
}
Console.WriteLine("All services stopped.");
// Keep the console alive for a second to allow the user to see the message.
Thread.Sleep(1000);
}
I use a great Nuget package called ServiceProcess.Helpers.
And I quote...
It helps windows services debugging by creating a play/stop/pause UI when running with a debugger attached, but also allows the service to be installed and run by the windows server environment.
All this with one line of code.
http://windowsservicehelper.codeplex.com/
Once installed and wired in all you need to do is set your windows service project as the start-up project and click start on your debugger.
You can also try System.Diagnostics.Debugger.Launch() method. It helps in taking the debugger pointer to the specified location and you can then debug you code.
Before this step please install your service.exe using the command line of Visual Studio command prompt - installutil projectservice.exe
Then start your service from the Control Panel -> Administrative Tools -> Computer Management ->Service and Application -> Services -> Your Service Name
I just added this code to my service class so I could indirectly call OnStart, similar for OnStop.
public void MyOnStart(string[] args)
{
OnStart(args);
}
I'm using the /Console parameter in the Visual Studio project Debug → Start Options → Command line arguments:
public static class Program
{
[STAThread]
public static void Main(string[] args)
{
var runMode = args.Contains(#"/Console")
? WindowsService.RunMode.Console
: WindowsService.RunMode.WindowsService;
new WinodwsService().Run(runMode);
}
}
public class WindowsService : ServiceBase
{
public enum RunMode
{
Console,
WindowsService
}
public void Run(RunMode runMode)
{
if (runMode.Equals(RunMode.Console))
{
this.StartService();
Console.WriteLine("Press <ENTER> to stop service...");
Console.ReadLine();
this.StopService();
Console.WriteLine("Press <ENTER> to exit.");
Console.ReadLine();
}
else if (runMode.Equals(RunMode.WindowsService))
{
ServiceBase.Run(new[] { this });
}
}
protected override void OnStart(string[] args)
{
StartService(args);
}
protected override void OnStop()
{
StopService();
}
/// <summary>
/// Logic to Start Service
/// Public accessibility for running as a console application in Visual Studio debugging experience
/// </summary>
public virtual void StartService(params string[] args){ ... }
/// <summary>
/// Logic to Stop Service
/// Public accessibility for running as a console application in Visual Studio debugging experience
/// </summary>
public virtual void StopService() {....}
}
Unfortunately, if you're trying to debug something at the very start of a Windows Service operation, "attaching" to the running process won't work. I tried using Debugger.Break() within the OnStart procecdure, but with a 64-bit, Visual Studio 2010 compiled application, the break command just throws an error like this:
System error 1067 has occurred.
At that point, you need to set up an "Image File Execution" option in your registry for your executable. It takes five minutes to set up, and it works very well. Here's a Microsoft article where the details are:
How to: Launch the Debugger Automatically
Try Visual Studio's very own post-build event command line.
Try to add this in post-build:
#echo off
sc query "ServiceName" > nul
if errorlevel 1060 goto install
goto stop
:delete
echo delete
sc delete "ServiceName" > nul
echo %errorlevel%
goto install
:install
echo install
sc create "ServiceName" displayname= "Service Display Name" binpath= "$(TargetPath)" start= auto > nul
echo %errorlevel%
goto start
:start
echo start
sc start "ServiceName" > nul
echo %errorlevel%
goto end
:stop
echo stop
sc stop "ServiceName" > nul
echo %errorlevel%
goto delete
:end
If the build error with a message like Error 1 The command "#echo off sc query "ServiceName" > nul so on, Ctrl + C then Ctrl + V the error message into Notepad and look at the last sentence of the message.
It could be saying exited with code x. Look for the code in some common error here and see how to resolve it.
1072 -- Marked for deletion → Close all applications that maybe using the service including services.msc and Windows event log.
1058 -- Can't be started because disabled or has no enabled associated devices → just delete it.
1060 -- Doesn't exist → just delete it.
1062 -- Has not been started → just delete it.
1053 -- Didn't respond to start or control → see event log (if logged to event log). It may be the service itself throwing an exception.
1056 -- Service is already running → stop the service, and then delete.
More on error codes here.
And if the build error with message like this,
Error 11 Could not copy "obj\x86\Debug\ServiceName.exe" to "bin\Debug\ServiceName.exe". Exceeded retry count of 10. Failed. ServiceName
Error 12 Unable to copy file "obj\x86\Debug\ServiceName.exe" to "bin\Debug\ServiceName.exe". The process cannot access the file 'bin\Debug\ServiceName.exe' because it is being used by another process. ServiceName
open cmd, and then try to kill it first with taskkill /fi "services eq ServiceName" /f
If all is well, F5 should be sufficient to debug it.
In the OnStart method, do the following.
protected override void OnStart(string[] args)
{
try
{
RequestAdditionalTime(600000);
System.Diagnostics.Debugger.Launch(); // Put breakpoint here.
.... Your code
}
catch (Exception ex)
{
.... Your exception code
}
}
Then run a command prompt as administrator and put in the following:
c:\> sc create test-xyzService binPath= <ProjectPath>\bin\debug\service.exe type= own start= demand
The above line will create test-xyzService in the service list.
To start the service, this will prompt you to attach to debut in Visual Studio or not.
c:\> sc start text-xyzService
To stop the service:
c:\> sc stop test-xyzService
To delete or uninstall:
c:\> sc delete text-xyzService
Debug a Windows Service over http (tested with VS 2015 Update 3 and .Net FW 4.6)
Firstly, you have to create a Console Project within your VS Solution(Add -> New Project -> Console Application).
Within the new project, create a class "ConsoleHost" with that code:
class ConsoleHost : IDisposable
{
public static Uri BaseAddress = new Uri(http://localhost:8161/MyService/mex);
private ServiceHost host;
public void Start(Uri baseAddress)
{
if (host != null) return;
host = new ServiceHost(typeof(MyService), baseAddress ?? BaseAddress);
//binding
var binding = new BasicHttpBinding()
{
Name = "MyService",
MessageEncoding = WSMessageEncoding.Text,
TextEncoding = Encoding.UTF8,
MaxBufferPoolSize = 2147483647,
MaxBufferSize = 2147483647,
MaxReceivedMessageSize = 2147483647
};
host.Description.Endpoints.Clear();
host.AddServiceEndpoint(typeof(IMyService), binding, baseAddress ?? BaseAddress);
// Enable metadata publishing.
var smb = new ServiceMetadataBehavior
{
HttpGetEnabled = true,
MetadataExporter = { PolicyVersion = PolicyVersion.Policy15 },
};
host.Description.Behaviors.Add(smb);
var defaultBehaviour = host.Description.Behaviors.OfType<ServiceDebugBehavior>().FirstOrDefault();
if (defaultBehaviour != null)
{
defaultBehaviour.IncludeExceptionDetailInFaults = true;
}
host.Open();
}
public void Stop()
{
if (host == null)
return;
host.Close();
host = null;
}
public void Dispose()
{
this.Stop();
}
}
And this is the code for the Program.cs class:
public static class Program
{
[STAThread]
public static void Main(string[] args)
{
var baseAddress = new Uri(http://localhost:8161/MyService);
var host = new ConsoleHost();
host.Start(null);
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
host.Stop();
}
}
Configurations such as connectionstrings should be copied in the App.config file of the Console project.
To sturt up the console, righ-click on Console project and click Debug -> Start new instance.
Just add a contructor to your service class (if you don't have it already). Below, you can check and example for visual basic .net.
Public Sub New()
OnStart(Nothing)
End Sub
After, that, right-click on project and select "Debug -> Start a new instance".

Categories