My Windows Service failing to get started after a reboot - c#

I can successfully Start/Stop service Manually but it fails to start on a system restart although startup type is set to 'Automatic'. On some terminal, when rebooted, service fail to start with error failed to connect DB
29052019 17:25:27 ERROR Logs.TransactionLogManager - Exception Thrown in getNewSession()
29052019 17:25:27 ERROR Logs.TransactionLogManager - Unable To Open Database Session
29052019 17:25:27 ERROR Logs.TransactionLogManager - Unable to complete network request to host "localhost".
at FirebirdSql.Data.FirebirdClient.FbConnectionInternal.Connect()
at FirebirdSql.Data.FirebirdClient.FbConnectionPoolManager.Pool.CreateNewConnectionIfPossibleImpl(FbConnectionString connectionString)
at FirebirdSql.Data.FirebirdClient.FbConnectionPoolManager.Pool.GetConnection(FbConnection owner)
at FirebirdSql.Data.FirebirdClient.FbConnection.Open()
at NHibernate.Connection.DriverConnectionProvider.GetConnection()
at NHibernate.Tool.hbm2ddl.SuppliedConnectionProviderConnectionHelper.Prepare()
at NHibernate.Tool.hbm2ddl.SchemaMetadataUpdater.GetReservedWords(Dialect dialect, IConnectionHelper connectionHelper)
at NHibernate.Tool.hbm2ddl.SchemaMetadataUpdater.Update(ISessionFactory sessionFactory)
at NHibernate.Impl.SessionFactoryImpl..ctor(Configuration cfg, IMapping mapping, Settings settings, EventListeners listeners)
at NHibernate.Cfg.Configuration.BuildSessionFactory()
at StevensCommon.Database.FluentNHibernateManager.OpenNewSession()
at StevensCommon.DAOs.StevensDAO.GetNewSession()
On development environment whilst debugging I'm not even getting any error. Assuming that on my machine the firebird services does start up before my service, still it fails to start the service on a reboot. And nothing comes up in the log.
I've added some log points within the code and they all gets logged when I Stop/Start the service manually. But nothing shows up in the log when system is rebooted and server never gets started.
Tried adding Firebird Service as a dependencies in the Project/Service Installer, set the DelayedAutoStart = true. Whatever solution I read online I've tried it but service is not starting on a reboot.
Following I'm adding starting/entry point snippet of the service.
Program.cs
static class Program
{
static void Main(string[] args)
{
TransactionLogManager.WriteServiceLog("FLAG - Before DAO Call", null);
// Check to see if we have a licence
if (LicenceFileDAO.GetLicence() != null && LicenceManager.IsLicenceActive())
{
TransactionLogManager.WriteServiceLog("FLAG - Inside DAO Block", null);
//Run the IS Service
ServiceBase[] ServicesToRun = new ServiceBase[] { new MyService() };
ServiceBase.Run(ServicesToRun);
TransactionLogManager.WriteServiceLog("FLAG - End of DAO Call", null);
}
else
{
TransactionLogManager.WriteServiceLog("No Valid Licence Found - Either A Licence Has Not Been Activated Or It Has Expired. Please Contact Support", null);
}
}
}
MyService.cs
public partial class MyService : ServiceBase
{
protected static Timer importTimer = null;
protected static Timer exportTimer = null;
protected static Timer licenceTimer = null;
protected static Timer requestTimer = null;
protected static Timer uploadTimer = null;
protected static Timer handshakeTimer = null;
protected static Timer scheduledReportTimer = null;
protected static Timer alertTimer = null;
public static Boolean ImportRunning = false;
public static Boolean ExportRunning = false;
public static Boolean RequestRunning = false;
public static Boolean UploadRunning = false;
public static Boolean HandshakeRunning = false;
public static Boolean ScheduledReportRunning = false;
public static Boolean AlertReportRunning = false;
public static int? zynkWorkflowProcessId = null;
public MyService()
{
TransactionLogManager.WriteServiceLog("FLAG - 1", null);
InitializeComponent();
InitializeServiceTimers();
try
{
MessengerService.Start();
TransactionLogManager.WriteServiceLog("Messaging Service Started", null);
}
catch (Exception e)
{
TransactionLogManager.WriteServiceLog(e.Message, e.StackTrace);
}
}
private void InitializeComponent()
{
this.eventLog1 = new System.Diagnostics.EventLog();
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).BeginInit();
//
// MyService
//
this.ServiceName = "MyService";
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).EndInit();
}
private void InitializeServiceTimers()
{
if (!System.Diagnostics.EventLog.SourceExists("Stevens Integration Service"))
{
System.Diagnostics.EventLog.CreateEventSource(
"Stevens Integration Service", "ServiceLog");
}
eventLog1.Source = "Stevens Integration Service";
eventLog1.Log = "ServiceLog";
TransactionLogManager.WriteServiceLog("FLAG - 2", null);
importTimer = new Timer(IntegrationServiceSettings.GetImportInterval() * 1000);
exportTimer = new Timer(IntegrationServiceSettings.GetExportInterval() * 1000);
licenceTimer = new Timer(86400 * 1000); // Daily
requestTimer = new Timer(IntegrationServiceSettings.GetRequestInterval() * 1000);
scheduledReportTimer = new Timer(30000);
alertTimer = new Timer(20000);
importTimer.Elapsed += new ElapsedEventHandler(ImportTimerElapsed);
exportTimer.Elapsed += new ElapsedEventHandler(ExportTimerElapsed);
licenceTimer.Elapsed += new ElapsedEventHandler(LicenceTimerElapsed);
requestTimer.Elapsed += new ElapsedEventHandler(RequestTimerElapsed);
scheduledReportTimer.Elapsed += new ElapsedEventHandler(ScheduledReportTimerElapsed);
alertTimer.Elapsed += new ElapsedEventHandler(AlertTimerElapsed);
TransactionLogManager.WriteServiceLog("FLAG - 3", null);
StartTimers();
TransactionLogManager.WriteServiceLog("FLAG - 4", null);
}
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("Stevens Integration Service Starting...");
TransactionLogManager.WriteServiceLog("FLAG - OnStart() Started", null);
if (StevensDAO.TestConnection())
{
eventLog1.WriteEntry("Configure Settings...");
IntegrationServiceSettings.InitialiseAll();
eventLog1.WriteEntry("Done.");
}
TransactionLogManager.WriteServiceLog("FLAG - OnStart() Finished", null);
TransactionLogManager.WriteServiceLogInfo("Started");
eventLog1.WriteEntry("Started.");
}
}
ProjectInstaller - That Includes System.ServiceProcess.ServiceProcessInstaller and System.ServiceProcess.ServiceInstaller
private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;
private System.ServiceProcess.ServiceInstaller serviceInstaller1;
private MyService myService ;
private void InitializeComponent()
{
this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
this.myService = new IntegrationService.MyService();
// serviceProcessInstaller1
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
// serviceInstaller1
this.serviceInstaller1.Description = "My Integration Service";
this.serviceInstaller1.DisplayName = "MyService";
this.serviceInstaller1.ServiceName = "MyService";
//this.serviceInstaller1.ServicesDependedOn = new string[] { "Firebird Guardian - DefaultInstance", "Firebird Server - DefaultInstance" };
//this.serviceInstaller1.DelayedAutoStart = true;
this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
// myService
this.myService.ExitCode = 0;
this.myService.ServiceName = "MyService";
// ProjectInstaller
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
this.serviceProcessInstaller1,
this.serviceInstaller1});
}
LogPoints - On manual Start/Stop I do get following log points, but when I reboot the system nothing comes up
30052019 16:19:35 ERROR Logs.TransactionLogManager - FLAG - Before DAO Call
30052019 16:19:35 ERROR Logs.TransactionLogManager - FLAG - Inside DAO Block
30052019 16:19:35 ERROR Logs.TransactionLogManager - FLAG - 1
30052019 16:19:35 ERROR Logs.TransactionLogManager - FLAG - 2
30052019 16:19:35 ERROR Logs.TransactionLogManager - FLAG - 3
30052019 16:19:35 ERROR Logs.TransactionLogManager - FLAG - 4
30052019 16:19:35 ERROR Logs.TransactionLogManager - Messaging Service Started
30052019 16:19:35 ERROR Logs.TransactionLogManager - FLAG - OnStart() Started
30052019 16:19:35 ERROR Logs.TransactionLogManager - Client 1 is now connected!
30052019 16:19:36 ERROR Logs.TransactionLogManager - FLAG - OnStart() Finished

Related

Error while installing the windows service using installutil command?

I Will Explain what i am exactly doing.
STEP 1:
I Have taken the one class library file in which i have added the WCF service. In this service i am peforming operations.
STEP 2:
I have added the windows service in the same solution. In this service i have hosted the WCF service and debug it.
So it is working fine.
STEP 3:
Then I had created the set up of that files using installshied(basic msi project) and i install it. It is working fine.
But I am trying to install it using InstallUtil.exe it is giving error.
Error Message:-
Installing assembly 'C:\Users\Dattaprasad\Desktop\TestAllBrowswer\WindowsService1.exe'.
Affected parameters are:
i =
logtoconsole =
logfile = C:\Users\Dattaprasad\Desktop\TestAllBrowswer\WindowsService1.InstallLog
assemblypath = C:\Users\Dattaprasad\Desktop\TestAllBrowswer\WindowsService1.exe
name = HostCompression
Installing service HostCompression...
Service HostCompression has been successfully installed.
Creating EventLog source HostCompression in log Application...
An exception occurred in the OnAfterInstall event handler of System.ServiceProcess.ServiceInstaller.
System.InvalidOperationException: Cannot start service HostCompression on computer '.'.
The inner exception System.ComponentModel.Win32Exception was thrown with the following error message:
The service did not respond to the start or control request in a timely fashion.
Rolling back assembly 'C:\Users\Dattaprasad\Desktop\TestAllBrowswer\WindowsService1.exe'.
Affected parameters are:
i =
logtoconsole =
logfile = C:\Users\Dattaprasad\Desktop\TestAllBrowswer\WindowsService1.InstallLog
assemblypath = C:\Users\Dattaprasad\Desktop\TestAllBrowswer\WindowsService1.exe
name = HostCompression
Restoring event log to previous state for source HostCompression.
Service HostCompression is being removed from the system...
Service HostCompression was successfully removed from the system.
What I have tried:
Service1.cs file:-
ServiceHost m_serviceHost;
public Service1()
{
InitializeComponent();
}
public void OnDebug()
{
OnStart(null);
}
protected override void OnStart(string[] args)
{
if (m_serviceHost != null) m_serviceHost.Close();
//string strAdrHTTP = "http://localhost:9100/CompressService/";
string strAdrTCP = "net.tcp://localhost:9200/CompressService";
string strAdrWebHttp = "http://localhost:9100/CompressService";
Uri[] adrbase = {
//new Uri(strAdrHTTP),
new Uri(strAdrTCP),
new Uri(strAdrWebHttp)
};
m_serviceHost = new ServiceHost(typeof(TestAllBrowser.Test), adrbase);
// ServiceDebugBehavior debug = m_serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
ServiceMetadataBehavior mBehave = new ServiceMetadataBehavior();
m_serviceHost.Description.Behaviors.Add(mBehave);
//m_serviceHost.Description.Behaviors.Add(new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
#region BasicHttpBinding
#endregion
#region NetTcpBinding
NetTcpBinding tcpb = new NetTcpBinding();
tcpb.MaxReceivedMessageSize = 2147483647;
tcpb.MaxBufferPoolSize = 2147483647;
tcpb.MaxBufferSize = 2147483647;
tcpb.TransferMode = TransferMode.Streamed;
//tcpb.ReaderQuotas.MaxArrayLength = 2147483647;
//tcpb.ReaderQuotas.MaxStringContentLength = 2147483647;
tcpb.ReceiveTimeout = new TimeSpan(0, 10, 00);
tcpb.SendTimeout = new TimeSpan(0, 10, 00);
tcpb.CloseTimeout = new TimeSpan(0, 10, 00);
m_serviceHost.AddServiceEndpoint(typeof(TestAllBrowser.ITest), tcpb, strAdrTCP);
m_serviceHost.AddServiceEndpoint(typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
#endregion
#region WebHttpBinding
WebHttpBinding webb = new WebHttpBinding();
webb.MaxReceivedMessageSize = 2147483647;
webb.MaxBufferPoolSize = 2147483647;
webb.MaxBufferSize = 2147483647;
webb.TransferMode = TransferMode.Streamed;
//webb.ReaderQuotas.MaxArrayLength = 2147483647;
//webb.ReaderQuotas.MaxStringContentLength = 2147483647;
webb.ReceiveTimeout = new TimeSpan(0, 10, 00);
webb.SendTimeout = new TimeSpan(0, 10, 00);
webb.CloseTimeout = new TimeSpan(0, 10, 00);
webb.CrossDomainScriptAccessEnabled = true;
m_serviceHost.AddServiceEndpoint(typeof(TestAllBrowser.ITest), webb, strAdrWebHttp).Behaviors.Add((IEndpointBehavior)new WebHttpBehavior());
m_serviceHost.AddServiceEndpoint(typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
#endregion
m_serviceHost.Open();
}
protected override void OnStop()
{
if (m_serviceHost != null)
m_serviceHost.Close();
m_serviceHost = null;
}
ProjectInstaller.cs file:-
[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
private IContainer components = (IContainer)null;
private ServiceProcessInstaller process;
private ServiceInstaller service;
private ServiceProcessInstaller serviceProcessInstaller1;
private ServiceInstaller serviceInstaller1;
public ProjectInstaller()
{
this.process = new ServiceProcessInstaller();
this.process.Account = ServiceAccount.LocalSystem;
this.service = new ServiceInstaller();
this.service.ServiceName = "HostCompression";
this.service.DisplayName = "HostCompression";
this.service.Description = "WCF Service Hosted";
this.service.StartType = ServiceStartMode.Automatic;
this.Installers.Add((Installer)this.process);
this.Installers.Add((Installer)this.service);
this.service.AfterInstall += new InstallEventHandler(this.serviceInstaller1_AfterInstall);
}
private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
{
new ServiceController("HostCompression").Start();
}
private void InitializeComponent()
{
this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
//
// serviceProcessInstaller1
//
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
//
// serviceInstaller1
//
this.serviceInstaller1.ServiceName = "Service1";
this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
//
// ProjectInstaller
//
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
this.serviceProcessInstaller1,
this.serviceInstaller1});
}

Quartz Scheduling Application

I am writing a Scheduling Client Server Application. The Server Application uses Window Service using Quartz and the Client application (For testing using both WEB and Console Applications) . Both client /Server Project build successfully but when i start service and my console application communicate with this service .An exception Comes when Client Object Calls : sched.ScheduleJob(Job,Trigger)
it through Exception on this line.
Below is my code snippet
namespace QuartzService
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
private IScheduler sched;
public void Show()
{
try {
NameValueCollection properties = new NameValueCollection();
properties["quartz.scheduler.instanceName"] = "RemoteServer";
// set thread pool info
properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
properties["quartz.threadPool.threadCount"] = "5";
properties["quartz.threadPool.threadPriority"] = "Normal";
// set remoting exporter
properties["quartz.scheduler.exporter.type"] = "Quartz.Simpl.RemotingSchedulerExporter, Quartz";
properties["quartz.scheduler.exporter.port"] = "555";
properties["quartz.scheduler.exporter.bindName"] = "QuartzScheduler";
properties["quartz.scheduler.exporter.channelType"] = "tcp";
properties["quartz.scheduler.exporter.channelName"] = "httpQuartz";
/// properties = (NameValueCollection)ConfigurationManager.GetSection("quartz");
ISchedulerFactory sf = new StdSchedulerFactory(properties);
sched = sf.GetScheduler();
sched.Start();
string lines = "==================Start===========================\n"+DateTime.Now.TimeOfDay.ToString()+"\n====================END=========================\n";
// Write the string to a file.
string filepath = #"D:\Murtaza\Service\test.txt";
System.IO.StreamWriter file = new System.IO.StreamWriter("c:\\test.txt",true);
file.WriteLine(lines);
file.Close();
// Console.WriteLine("Hello");
// Thread.Sleep(TimeSpan.FromMinutes(1));
// sched.Shutdown(true);
}
catch { }
}
}
}
===============================
Here is Client Console Application Code:
namespace Client
{
class Program
{
static void Main(string[] args)
{
try
{
NameValueCollection properties = new NameValueCollection();
properties["quartz.scheduler.instanceName"] = "RemoteClient";
properties["quartz.scheduler.instanceId"] = "AUTO";
// set thread pool info
properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
properties["quartz.threadPool.threadCount"] = "5";
properties["quartz.threadPool.threadPriority"] = "Normal";
// set remoting expoter
properties["quartz.scheduler.proxy"] = "true";
properties["quartz.scheduler.proxy.address"] = "tcp://10.0.0.46:555/QuartzScheduler";// "tcp://10.0.0.85:555/QuartzScheduler"; //"tcp://10.0.0.46:555/QuartzScheduler";
// First we must get a reference to a scheduler
ISchedulerFactory sf = new StdSchedulerFactory(properties);
IScheduler sched = sf.GetScheduler();
IJobDetail job = JobBuilder.Create<TestJob>()
.WithIdentity("remotelyAddedJob", "default")
.Build();
JobDataMap map = job.JobDataMap;
map.Put("msg", "Your remotely added job has executed!");
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("remotelyAddedTrigger", "default")
.ForJob(job.Key)
.WithCronSchedule("/5 * * ? * *")
.Build();
// schedule the job
sched.ScheduleJob(job, trigger);
}
catch (Exception ex)
{ }
}
}
}

Named Pipes Server Not Listening

I am trying to make a Windows Service that simply sits and listens for messages on a named pipe. But it's not working. Trying to connect to the named pipe simply times out, and when I view the process handles of the service's process in Process Explorer, I do not see the named pipe.
Here is what I have so far:
namespace Service
{
class Service : ServiceBase
{
Thread workerThread;
static bool serviceStarted = false;
static PipeSecurity pipeSecurity = new PipeSecurity();
public Service()
{
this.ServiceName = "Service";
this.EventLog.Log = "Application";
this.EventLog.Source = "ServiceName";
this.CanHandlePowerEvent = false;
this.CanHandleSessionChangeEvent = false;
this.CanPauseAndContinue = false;
this.CanShutdown = true;
this.CanStop = true;
}
static void Main()
{
ServiceBase.Run(new Service());
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
pipeSecurity.AddAccessRule(new PipeAccessRule("Authenticated Users", PipeAccessRights.ReadWrite, AccessControlType.Allow));
pipeSecurity.AddAccessRule(new PipeAccessRule(WindowsIdentity.GetCurrent().User, PipeAccessRights.FullControl, AccessControlType.Allow));
ThreadStart threadStart = new ThreadStart(WorkerThread);
workerThread = new Thread(threadStart);
workerThread.Start();
serviceStarted = true;
}
protected override void OnStop()
{
base.OnStop();
serviceStarted = false;
workerThread.Join(new TimeSpan(0, 0, 30));
}
protected override void OnShutdown()
{
base.OnShutdown();
serviceStarted = false;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
private void WorkerThread()
{
while (serviceStarted)
{
try
{
using (NamedPipeServerStream pipeServerStream = new NamedPipeServerStream("PipeName", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.None, 128, 128, pipeSecurity))
{
pipeServerStream.WaitForConnection();
byte[] buffer = new byte[128];
StringBuilder message = new StringBuilder();
do
{
int len = pipeServerStream.Read(buffer, 0, buffer.Length);
message.Append(Encoding.UTF8.GetString(buffer, 0, len));
}
while (!pipeServerStream.IsMessageComplete);
EventLog.WriteEntry(message.ToString());
}
}
catch(Exception ex)
{
}
finally
{
if (serviceStarted)
Thread.Sleep(100);
}
}
Thread.CurrentThread.Abort();
}
}
}
It seems like the named pipe is just not getting created. Any ideas? When I attempt to connect via Powershell:
PS C:\> $Client = New-Object System.IO.Pipes.NamedPipeClientStream(".", "PipeName", [System.IO.Pipes.PipeDirection]::Out)
PS C:\> $Client.Connect(1000)
Exception calling "Connect" with "1" argument(s): "The operation has timed out."
At line:1 char:1
+ $Client.Connect(1000)
new NamedPipeServerStream("PipeName", ...)
That pipe is only accessible to processes that run in the same session. Which is session 0 for services. Your Powershell program runs on the desktop session. To make it visible to all sessions, you must prefix the name with "Global\\"
Btw, don't hesitate to add some logging so you have positive proof that the pipe server is about to call WaitForConnection(). That removes considerable doubt on your (and our) end that the pipe is actually listening. Using empty catch blocks creates too much FUD.

how to make service act dynamically based on service running condition

hi friends i was trying to make my service act dynamically... i have set time for my service about for 2 min ,if suppose it was doin huge amount of work means it will exceeds that 2 min time limit then we need to check the service condition if work is pending means we need to run that instance until upto finish
so that i have tried this below code on googling ... i m having method were i need to cooperate in below service, can any one help me
public static void StartService(string serviceName, int timeoutMilliseconds)
{
ServiceController service = new ServiceController(serviceName);
try
{
TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
}
catch
{
// ...
}
}
as of now i m doing this below logic
protected override void OnStart(string[] args)
{
// my service name
Workjob("FTSCSVGenerator");
// ad 1: handle Elapsed event and CsvGenFromDatabase is method which i have to executed
timerjob.Elapsed += new ElapsedEventHandler(CsvGenFromDatabase);
// ad 2: set interval to 1 minute (= 60,000 milliseconds)
timerjob.Interval = Convert.ToDouble(DueTime);
// ////ad 3: enabling the timer
timerjob.Enabled = true;
eventLog1.WriteEntry("my service started");
}
protected override void OnStop()
{
eventLog1.WriteEntry("my service stopped");
}
private void Workjob(string servicename )
{
ServiceController servicecsv = new ServiceController(servicename);
if ((servicecsv.Status.Equals(ServiceControllerStatus.Stopped)) || (servicecsv.Status.Equals(ServiceControllerStatus.StopPending)))
{
// Start the service if the current status is stopped.
servicecsv.Start( );
}
else
{
// Stop the service if its status is not set to "Stopped".
servicecsv.Stop();
}
}
I have built services that operate in a similar manner before, my advice would be to NOT start and stop the service from external code. Instead, apply the Timer methodology within the service itself, which should always be running. On TimerElapsed, do work and then return to an idle state. Thus alleviating the need to start and stop.
Further, I would protect the "stop" of a service to not allow the stop if the service is "working"
Sample Code
Note: I employ a process I call "zeroing" with my timer. Zeroing, in my context, is the process of getting the events to fire on zero seconds of every minute. To do that, I first set the time to fire every second and I check to see if the seconds part of the current time is zero, once that occurs I switch the timer elapse to every minute. I do this to give myself some sanity while testing.
Also, my scheduling is configurable so every minute when it "ticks" i check my config to see if the process "should" execute. I do so with the following Xml Schema:
<?xml version="1.0" encoding="utf-8"?>
<ScheduleDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ScheduleInterval>1</ScheduleInterval>
<ScheduleUnits>min</ScheduleUnits>
<DailyStartTime>1753-01-01T08:00:00</DailyStartTime>
<ExcludedWeekDays>
<string>Sunday</string>
<string>Saturday</string>
</ExcludedWeekDays>
<ExcludedDates>
<string>12/25</string>
<string>02/02</string>
<string>03/17</string>
</ExcludedDates>
<DailyRunTimes>
<!-- code ommitted for size // -->
</DailyRunTimes>
</ScheduleDefinition>
Finally, this code sample is for a DataSync Services, so any references to "DataMigrationService" or "DataMigrationManager" are my own custom classes and are used as an abstraction to give me an object to control within the service.
... here's the code:
using System;
using System.Diagnostics;
using System.Reflection;
using System.ServiceProcess;
using System.Threading;
using System.Xml;
using System.Xml.Serialization;
using DataMigration.Configuration;
using DataMigration.ObjectModel;
namespace DataSyncService
{
public partial class DataSyncService : ServiceBase
{
#region Private Members
private System.Timers.Timer _timer = null;
private SimpleScheduleManager.ScheduleDefinition _definition = null;
private DataMigrationManager _manager = new DataMigrationManager();
#endregion
#region Constructor(s)
public DataSyncService()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(AssemblyResolver.Resolve);
InitializeComponent();
}
~DataSyncService()
{
_manager = null;
_definition = null;
_timer = null;
}
#endregion
#region Public Method(s)
protected override void OnStart(string[] args)
{
Assembly assembly = Assembly.GetExecutingAssembly();
_manager.ProcessMonitor.Logger.Debug("Assembly Version: ", assembly.GetName().FullName);
assembly = null;
SetScheduleFromConfigurationFile();
_timer = new System.Timers.Timer(1000);
_timer.AutoReset = true;
_timer.Enabled = true;
_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_ZeroingProcess);
_timer.Start();
}
protected override void OnStop()
{
_timer.Stop();
_timer.Enabled = false;
_timer = null;
// block if the Process is active!
if (_manager.State == DataMigrationState.Processing)
{
// I invented my own CancellableAsyncResult (back in the day), now you can use CancellationTokenSource
CancellableAsyncResult result = _manager.RequestCancel() as CancellableAsyncResult;
while (!result.IsCompleted) { Thread.Sleep(ServiceConstants.ThreadSleepCount); }
try
{
result.EndInvoke();
}
catch (Exception ex)
{
ProcessMonitorMessage message = ProcessMonitorMessage.GetErrorOccurredInstance();
message.EventType = ProcessMonitorEventType.ProcessAlert;
message.Severity = ProcessMessageSeverity.ErrorStop;
message.SubjectLine = "Error while stopping service. ";
message.EventDescription = ex.Message;
_manager.ProcessMonitor.ReportError(message);
}
}
}
#endregion
#region Private Method(s)
private bool MigrationIsScheduledToRunNow()
{
DateTime now = DateTime.Now;
foreach (string dowString in _definition.ExcludedWeekDays)
{
if (now.DayOfWeek.ToString().Equals(dowString))
{
Trace.WriteLine("Today is " + dowString, "Excluded by Schedule definition");
return false;
}
}
foreach (string datePart in _definition.ExcludedDates)
{
string dateString = datePart + "/2008"; // 2008 is a leap year so it "allows" all 366 possible dates.
DateTime excludedDate = Convert.ToDateTime(dateString);
if (excludedDate.Day.Equals(now.Day) && excludedDate.Month.Equals(now.Month))
{
Trace.WriteLine("Today is " + datePart, "Excluded by Schedule definition");
return false;
}
}
foreach (DateTime runTime in _definition.DailyRunTimes)
{
if (runTime.Hour.Equals(now.Hour) && runTime.Minute.Equals(now.Minute))
{
Trace.WriteLine("Confirmed Scheduled RunTime: " + runTime.TimeOfDay.ToString(), "Included by Schedule definition");
return true;
}
}
return false;
}
/// <summary>
/// Load Scheduling Configuration Options from the Xml Config file.
/// </summary>
private void SetScheduleFromConfigurationFile()
{
string basePath = AppDomain.CurrentDomain.BaseDirectory;
if (basePath.EndsWith("\\")) { basePath = basePath.Substring(0, basePath.Length - 1); }
string path = string.Format("{0}\\Scheduling\\scheduledefinition.xml", basePath);
_manager.ProcessMonitor.Logger.Debug("Configuration File Path", path);
XmlSerializer serializer = new XmlSerializer(typeof(SimpleScheduleManager.ScheduleDefinition));
XmlTextReader reader = new XmlTextReader(path);
reader.WhitespaceHandling = WhitespaceHandling.None;
_definition = serializer.Deserialize(reader) as SimpleScheduleManager.ScheduleDefinition;
reader = null;
serializer = null;
}
#endregion
#region Timer Events
private void _timer_ZeroingProcess(object sender, System.Timers.ElapsedEventArgs e)
{
if (DateTime.Now.Second.Equals(0))
{
_timer.Interval = 60000;
_timer.Elapsed -= new System.Timers.ElapsedEventHandler(_timer_ZeroingProcess);
_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
_timer_Elapsed(sender, e);
}
}
private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
_manager.ProcessMonitor.Logger.Info("Timer Elapsed", DateTime.Now.ToString());
if (MigrationIsScheduledToRunNow())
{
switch (_manager.State)
{
case DataMigrationState.Idle:
_manager.ProcessMonitor.Logger.Info("DataMigration Manager is idle. Begin Processing.");
_manager.BeginMigration();
break;
case DataMigrationState.Failed:
_manager.ProcessMonitor.Logger.Warn("Data Migration is in failed state, Email <NotificationRecipients> alerting them.");
break;
default:
_manager.ProcessMonitor.Logger.Warn("DataMigration Manager is still processing. Skipping this iteration.");
break;
}
}
}
#endregion
}
}

Multiple windows services in a single project = mystery

I'm having a bizarre issue that I haven't seen before and I'm thinking it MUST be something simple that I'm not seeing in my code.
I have a project with 2 windows services defined. One I've called DataSyncService, the other SubscriptionService. Both are added to the same project installer. Both use a timer control from System.Timers.
If I start both services together, they seem to work fine. The timers elapse at the appropriate time and everything looks okay. However, if I start either service individually, leaving the other stopped, everything goes haywire. The timer elapses constantly and on the wrong service. In other words, if I start the DataSyncService, the SubscriptionService timer elapses over and over. ...which is obviously strange.
The setup is similar to what I've done in the past so I'm really stumped. I even tried deleting both service and starting over but it doesn't seem to make a difference. At this point, I'm thinking I've made a simple error in the way I'm defining the services and my brain just won't let me see it. It must be creating some sort of threading issue that causes one service to race when the other is stopped. Here the code....
From Program.cs:
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new DataSyncService(),
new SubscriptionService()
};
ServiceBase.Run(ServicesToRun);
}
From ProjectInstaller.designer.cs:
private void InitializeComponent()
{
this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
this.dataSyncInstaller = new System.ServiceProcess.ServiceInstaller();
this.subscriptionInstaller = new System.ServiceProcess.ServiceInstaller();
//
// serviceProcessInstaller1
//
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
//
// dataSyncInstaller
//
this.dataSyncInstaller.DisplayName = "Data Sync Service";
this.dataSyncInstaller.ServiceName = "DataSyncService";
this.dataSyncInstaller.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
//
// subscriptionInstaller
//
this.subscriptionInstaller.DisplayName = "Subscription Service";
this.subscriptionInstaller.ServiceName = "SubscriptionService";
this.subscriptionInstaller.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
//
// ProjectInstaller
//
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
this.serviceProcessInstaller1,
this.dataSyncInstaller,
this.subscriptionInstaller});
}
private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;
private System.ServiceProcess.ServiceInstaller dataSyncInstaller;
private System.ServiceProcess.ServiceInstaller subscriptionInstaller;
From DataSyncService.cs:
public static readonly int _defaultInterval = 43200000;
//log4net.ILog log;
public DataSyncService()
{
InitializeComponent();
//log = LogFactory.Instance.GetLogger(this);
}
protected override void OnStart(string[] args)
{
timer1.Interval = _defaultInterval; //GetInterval();
timer1.Enabled = true;
EventLog.WriteEntry("MyProj", "Data Sync Service Started", EventLogEntryType.Information);
//log.Info("Data Sync Service Started");
}
private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
EventLog.WriteEntry("MyProj", "Data Sync Timer Elapsed.", EventLogEntryType.Information);
}
private void InitializeComponent()
{
this.timer1 = new System.Timers.Timer();
((System.ComponentModel.ISupportInitialize)(this.timer1)).BeginInit();
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(this.timer1_Elapsed);
//
// DataSyncService
//
this.ServiceName = "DataSyncService";
((System.ComponentModel.ISupportInitialize)(this.timer1)).EndInit();
}
From SubscriptionService:
public static readonly int _defaultInterval = 300000;
//log4net.ILog log;
public SubscriptionService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer1.Interval = _defaultInterval; //GetInterval();
timer1.Enabled = true;
EventLog.WriteEntry("MyProj", "Subscription Service Started", EventLogEntryType.Information);
//log.Info("Subscription Service Started");
}
private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
EventLog.WriteEntry("MyProj", "Subscription Service Time Elapsed", EventLogEntryType.Information);
}
private void InitializeComponent() //in designer
{
this.timer1 = new System.Timers.Timer();
((System.ComponentModel.ISupportInitialize)(this.timer1)).BeginInit();
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(this.timer1_Elapsed);
//
// SubscriptionService
//
this.ServiceName = "SubscriptionService";
((System.ComponentModel.ISupportInitialize)(this.timer1)).EndInit();
}
Again, the problem is that the timer1_elapsed handler runs constantly when only one of the services is started. And it's the handler on the OPPOSITE service.
Anybody see anything?
In the Service.Designer.cs files InitializeComponent() methods, I'm missing
this.CanShutdown = true;
...and I shouldn't be enabling the timers there since I do it in the OnStart handlers.
So it should be something like:
private void InitializeComponent()
{
this.timer1 = new System.Timers.Timer();
((System.ComponentModel.ISupportInitialize)(this.timer1)).BeginInit();
//
// timer1
//
this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(this.timer1_Elapsed);
//
// DataSyncService
//
this.ServiceName = "DataSyncService";
this.CanShutdown = true;
((System.ComponentModel.ISupportInitialize)(this.timer1)).EndInit();
}

Categories