The code below builds without any errors and ran fine as console application. However now that I've made it into a WindowsService and used the C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil to successfully install it. It stops as soon as I start it up. I feel like I'm missing something simple that I'm going to forever hit myself over the head once another set of eyes looks at it.
Please forgive the mess you are about see. I will clean it up after its working properly. Thanks in advance for any help that can be provided.
Service1.cs
namespace LGCDialHome
{
public partial class Service1 : ServiceBase
{
private System.Timers.Timer _timer = null;
public Service1()
{
InitializeComponent();
System.Timers.Timer stateTimer = new System.Timers.Timer(60000);
}
protected override void OnStart(string[] args)
{
try
{
EventLog.WriteEntry("Dial Home service started : " + DateTime.Now);
_timer = new System.Timers.Timer();
_timer.Interval = 10000; //in milliseconds
EventLog.WriteEntry("Timer Interval is : " + _timer.Interval);
_timer.Elapsed += timer_Elapsed;
_timer.Start();
}
catch (Exception ex)
{
EventLog.WriteEntry("Dial Home service error : " + ex);
}
}
protected override void OnStop()
{
EventLog.WriteEntry("Dial Home service Stopped : " + DateTime.Now);
}
protected void timer_Elapsed(object sender, ElapsedEventArgs e)
{
int invokeCount = 0;
int maxCount = 10;
string host = Environment.MachineName;
string user = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
string uname = Environment.UserName;
try
{
_timer.Stop();
Console.WriteLine("{0} Checking status {1,2}.",
DateTime.Now.ToString("h:mm:ss.fff"),(++invokeCount).ToString());
Console.WriteLine("Host -> {0} \r\nNTID -> {1}", host, user);
if (invokeCount == maxCount)
{
invokeCount = 0;
}
}
catch (Exception ex)
{
EventLog.WriteEntry("Dial Home service error : " + ex);
}
finally
{
_timer.Start();
}
}
}
}
Well, you will need to debug your code, but attaching to Windows Services is a little different than debugging other types of projects.
Try the following:
1- At the very beginning of your OnStart() method, add the following line:
System.Threading.Thread.Sleep(10000);
2- Set a breakpoint on the next line immediately after the line above. Build and reinstall your service using InstallUtil.
3- Start your service.
4- In Visual Studio, click Debug -> Attach to Process.
5- Find your service in the Available Processes list and attach to it. This will cause the breakpoint to be hit, and will let you debug your code to see if there's any exception thrown (by looking at your code, I feel like the problem might be security related. The user that the service is running as might not have access to the EventLog or something).
Note: After starting your service, you have 10 seconds to perform steps 4 and 5. If you think you need more time, change the sleep value to something like 20000(20 seconds).
Related
I have a windows service created with the microsoft example.
public MyService()
{
InitializeComponent();
}
private void InitializeComponent()
{
this.eventLog1 = new System.Diagnostics.EventLog();
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).BeginInit();
//
// eventLog1
//
this.eventLog1.Log = "Application";
this.eventLog1.Source = "MyService";
//
// MyService
//
this.CanHandlePowerEvent = true;
this.CanHandleSessionChangeEvent = true;
this.CanShutdown = true;
this.ServiceName = "MyService";
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).EndInit();
}
protected override void OnStart(string[] args)
{
try
{
eventLog1.WriteEntry("Initializing...");
Init();
ServiceConfig.Settings.Initialize("MyService");
eventLog1.WriteEntry("Starting...");
//do some stuff
eventLog1.WriteEntry("Started");
}
catch (Exception ex)
{
eventLog1.WriteEntry("Error:" + ex.Message);
}
finally
{
base.OnStart(args);
}
}
This windows service is configured to start automatically when windows starts.
Everything is working fine almost everywhere and almost always, but it happens that rarely this service doesn't start when OS starts.
In these cases I always find the same situation on event log.
On the Application log I have nothing and on the System log I have first the event ID 7039, than the event ID 7036 with "MyService is in running status" and at the same time, but after, another event ID 7036 with "MyService is stopped".
Instead, when everything works fine, I have only "MyService is in running status" on System Log with a time that come after all the Application's log I write and that you can see in the code.
So, my opinion is that in thoose cases it doesn't work, the service is never started by the Service Control Manager, the OnStart method is not called.
So it could be the OS's fault.
What's your opinions?
Thanks!
Needless to say I'm new to C# and doing some basic things to learn along the way. I'm trying to understand async/await feature. I have a form with 2 textboxes and a button. When I click the button, it checks a remote computer's service status (in this case remote registry. While it checks, it writes that it is checking the registry and tells the user to wait. Then starts if the state is stopped and gets some values I look for and writes those to the second textbox.
My code works, and I'm able to get my values. But the GUI freezes during this time. I tried to implement backgroundworker, thread and Async/Wait with no success. I tried doing Task and couldn't get that to work.
All the examples shown here or on other sites simply return int while I'm trying to return a string that writes the status and the values I want to textboxes. I tried to convert it to string with no success.
Long story short, for this type of processes, what would be a better approach? Can someone show me how and comment what does what along the way just so I understand better? I want to learn how to do it but at the same time learn why and learn to write cleaner code.
Thank you everyone for taking their time in advance.
string ComputerName = "Lab01";
public frmRegChecker()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
Check_Status();
}
private void Check_Status()
{
TxtBoxstatus.AppendText("Checking Remote Registry service status on computer : " + ComputerName);
TxtBoxstatus.AppendText(Environment.NewLine);
TxtBoxstatus.AppendText("Please wait... ");
ServiceController sc = new ServiceController("RemoteRegistry", ComputerName);
try
{
TxtBoxstatus.AppendText("The Remote Registry service status is currently set to : " + sc.Status.ToString());
TxtBoxstatus.AppendText(Environment.NewLine);
if (sc.Status == ServiceControllerStatus.Stopped)
{
// Start the service if the current status is stopped.
TxtBoxstatus.AppendText("Starting Remote Registry service...");
TxtBoxstatus.AppendText(Environment.NewLine);
try
{
// Start the service, and wait until its status is "Running".
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 3));
sc.Refresh();
sc.WaitForStatus(ServiceControllerStatus.Running);
// Display the current service status.
TxtBoxstatus.AppendText("The Remote Registry status is now set to:" + sc.Status.ToString());
richTextBox1.AppendText(Environment.NewLine);
try
{
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\");
string _OSVersion = (key.GetValue("CurrentVersion")).ToString();
richTextBox1.AppendText("OS version is : " + _OSVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(Environment.NewLine);
}
}
catch (InvalidOperationException)
{
richTextBox1.AppendText("Could not start the Remote Registry service.");
richTextBox1.AppendText(Environment.NewLine);
}
}
else if (sc.Status == ServiceControllerStatus.Running)
{
try
{
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\");
string _OSVersion = (key.GetValue("CurrentVersion")).ToString();
richTextBox1.AppendText("OS version is : " + _OSVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(Environment.NewLine);
}
}
}
}
catch
{
richTextBox1.AppendText("Error getting registry value from " + ComputerName);
richTextBox1.AppendText(Environment.NewLine);
}
}
Unfortunately, ServiceController is a rather outdated class and doesn't natively support async/await. That would be the cleanest solution if it were possible.
So, what you can do is use async/await with Task.Run. Task.Run executes code on a background thread, and you can use async/await from the UI to consume that background operation. This approach allows exceptions to be propagated and handled in a natural fashion, and it allows return values to also be handled naturally. Strip out the textbox updates for now for simplicity, and the first step looks like this:
private async void Button1_Click(object sender, EventArgs e)
{
try
{
var osVersion = await Task.Run(() => CheckStatus());
richTextBox1.AppendText("OS version is : " + osVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException ex)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(ex.ToString());
richTextBox1.AppendText(Environment.NewLine);
}
}
private string CheckStatus()
{
ServiceController sc = new ServiceController("RemoteRegistry", ComputerName);
if (sc.Status == ServiceControllerStatus.Stopped)
{
// Start the service if the current status is stopped.
// Start the service, and wait until its status is "Running".
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 3));
sc.Refresh();
sc.WaitForStatus(ServiceControllerStatus.Running);
}
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\");
return (key.GetValue("CurrentVersion")).ToString();
}
Next, add the progress updates. There's a built-in mechanism for that - IProgress<T>/Progress<T>, and it works like this:
private async void Button1_Click(object sender, EventArgs e)
{
try
{
var progress = new Progress<string>(update =>
{
TxtBoxstatus.AppendText(update);
TxtBoxstatus.AppendText(Environment.NewLine);
});
var osVersion = await Task.Run(() => CheckStatus(progress));
richTextBox1.AppendText("OS version is : " + osVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException ex)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(ex.ToString());
richTextBox1.AppendText(Environment.NewLine);
}
}
private string CheckStatus(IProgres<string> progress)
{
progress?.Report("Checking Remote Registry service status on computer : " + ComputerName);
progress?.Report("Please wait... ");
ServiceController sc = new ServiceController("RemoteRegistry", ComputerName);
progress?.Report("The Remote Registry service status is currently set to : " + sc.Status.ToString());
if (sc.Status == ServiceControllerStatus.Stopped)
{
// Start the service if the current status is stopped.
progress?.Report("Starting Remote Registry service...");
// Start the service, and wait until its status is "Running".
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 3));
sc.Refresh();
sc.WaitForStatus(ServiceControllerStatus.Running);
progress?.Report("The Remote Registry status is now set to:" + sc.Status.ToString());
}
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\");
return (key.GetValue("CurrentVersion")).ToString();
}
Note the separation of concerns: the only code that touches UI objects is a UI event handler. The CheckStatus method that contains the actual program logic is separated from the UI - all it knows is that it can report progress strings and return a string result.
This can easily be accomplished using async/await. An Example:
A simple WPF form:
<Window x:Class="WpfApp1.MainWindow"
...>
<Grid>
<Button Name="button" Content="Start" Click="Button_Click"/>
<TextBox Name="textButton" />
</Grid>
</Window>
and the associated code-behind:
public partial class MainWindow:Window
{
public MainWindow()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
textButton.Text = "Running...";
string result = await DoIt();
textButton.Text = result;
}
private async Task<string> DoIt()
{
await Task.Delay(3000);
return "Finished...";
}
}
When clicking the button, the long-running 'calculation' in 'DoIt' is started'asynchrounously. While it is running, the UI remains responsive.
When DoIt returns returns its result (in this example after a dummy delay of 3 seconds) the 'click' eventhandler continues...
Remarks:
this example uses code behind for simplicity. The technique works as well using the MVVM-pattern (where the async operation is started from a command).
'async void' is an anti pattern, but is used to comply withe the auto generated eventhandler in code behind.
in a real world application the async 'DoIt' method would propably be situated in a backend 'model class'.
the example assumes you only want to update the UI once the long-running operation has finished. If you want intermediate updates, there are several options (unfortunately a bit more complex).
I think you can still use the backgroundworker to make your textboxes display messages without freezing the GUI. Take reference from this question Here on how to return an object from backgroundworker.
I want to stop windows service in onStart() method when customer doesn't have a license. I use service.Stop(), but it does not work.
protected override void OnStart(string[] args)
{
try
{
_bridgeServiceEventLog.WriteEntry("new OnStart");
if (LicenseValidetor.ValidCountAndTypeDevices())
{
WsInitializeBridge();
}
else
{
service = new ServiceController("BridgeService");
service.Stop();
_bridgeServiceEventLog.WriteEntry("LicenseValidetor Error");
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
catch (Exception e)
{
_bridgeServiceEventLog.WriteEntry("error In onstart method ");
}
}
You cannot stop a service from within the OnStart method of that same service.
The ServiceController.Stop method internally calls ControlService (or it's Ex counterpart). Notice that one of the reasons that this function can fail is:
ERROR_SERVICE_CANNOT_ACCEPT_CTRL
The requested control code cannot be sent to the service because the state of the service is SERVICE_STOPPED, SERVICE_START_PENDING, or SERVICE_STOP_PENDING.
Well, guess what - when you're inside your OnStart method, the state of your service is SERVICE_START_PENDING.
The correct way to cope with this situation is to signal any other threads that you may have started to have them exit, and then to exit your OnStart method. The service control manager will notice that the process has exited and revert your service status to SERVICE_STOPPED. It may also notify an interactive user that "The service started and then stopped" or words to that effect.
I want to add that "simply not starting any workers" may not work (or perhaps I am being just plain stupid ;) ).
I built a service, with a try/catch(all) around my OnStart code. Because of a missing line in my .config file it crashed with an IOException, before it started any worker thread. The exception skipped over my thread starters. No thread was started by my code. Honestly.
But the service DID NOT STOP. I don't know why. As a desperate measure, I rethrew the exception, that helped.
I am still wondering if the file system watcher threads in Enterprise Library configuration were the problem. EntLib is woven to deeply into my code to remove it as an experiment, so I did not investigate further.
The accepted answer explains why what you are doing doesn't work but doesn't offer a good solution.
There are a couple of things your code isn't doing that it should.
Set the .ExitCode to indicate that your service is in an error state.
Throw an exception. Not having a license is exceptional. Throw it.
EXAMPLE:
protected override void OnStart(string[] args)
{
_bridgeServiceEventLog.WriteEntry("new OnStart");
try
{
if (LicenseValidetor.ValidCountAndTypeDevices())
{
WsInitializeBridge();
}
else
{
throw new ApplicationException("LicenseValidetor Error");
}
}
catch (Exception e)
{
this.ExitCode = e.HResult
_bridgeServiceEventLog.WriteEntry($"error In onstart method: {e.Message}");
throw
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
I have noticed that your not waiting to ensure that the Service has actually stopped or if it is even running in the first instance.
Do this :-
protected override void OnStart(string[] args)
{
try
{
_bridgeServiceEventLog.WriteEntry("new OnStart");
if (LicenseValidetor.ValidCountAndTypeDevices())
{
WsInitializeBridge();
}
else
{
int time = 10000;
TimeSpan timeout = TimeSpan.FromMilliseconds(time);
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
_bridgeServiceEventLog.WriteEntry("LicenseValidetor Error");
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
catch (Exception e)
{
_bridgeServiceEventLog.WriteEntry("error In onstart method ");
}
}
I need to have tasks running in my web application. I have been reading and most of the answers are to use the task scheduler in Windows but what I need is to have it in the web application itself.
I finally got something that almost works but I am still having some troubles:
using System;
using System.Timers;
using System.IO;
namespace ServiceIIS
{
public static class Servicios
{
public static bool serviceStarted = false;
static Timer serviceLoad = new Timer();
public static void serviceLoader()
{
if (!serviceStarted)
{
GC.KeepAlive(serviceStarted);
GC.KeepAlive(serviceLoad);
serviceStarted = true;
double Intervalo = loadData();
serviceLoad.Interval = Intervalo;
serviceLoad.Elapsed += new ElapsedEventHandler(serviceLoad_Elapsed);
serviceLoad.Enabled = true;
}
}
static void serviceLoad_Elapsed(object sender, ElapsedEventArgs e)
{
serviceLoad.Stop();
double Intervalo = loadData();
serviceLoad.Interval = Intervalo;
serviceLoad.Start();
}
static double loadData()
{
string dailyLoadTime = "00:00:00";
string log = "";
/*
loadData Code
log = resultMessage;
*/
using (StreamWriter w = File.AppendText("c:\\log.txt"))
{
writeLog(log, w);
w.Close();
}
return (Convert.ToDateTime(DateTime.Today.ToString("yyyy-MM-ddT") + dailyLoadTime).AddDays(1) - DateTime.Now).TotalMilliseconds;
}
public static void writeLog(string resultMessage, TextWriter w)
{
w.Write("\r\nLog : ");
w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString());
w.WriteLine(" :");
w.WriteLine(" :{0}", resultMessage);
w.WriteLine("-------------------------------");
w.Flush();
}
}
}
serviceLoader() will be called if serviceStarted is false, then I tell the garbage collector to ignore serviceStarted and serviceLoad to be cleaned.
Calling loadData() for the first time to get the data and "generate" the interval for the timer to wait until loadData() is called again. Then I create the event handler and start the timer.
Using the writeLog() procedure I know when loadData() is called. Waiting for the time it should be called (00:00:00 hours), there is no calling to loadData() but until a different time... that could be because the way I am computing the interval is not entirely correct.
Then it is called again the same day and once the next day. Finally after the second day, there is no call at all for loadData() so I suppose it is because the garbage collector deleted it, calling serviceLoader() again, loadData() is called at the same time telling me that in effect serviceStarted has been cleaned and surely serveLoad has been cleaned too.
Do you have an idea on what I am doing wrong and how could I get this working? I could not believe that there is no way to do this using IIS.
Thank you in advance for your time reading this.
Elder
It seems there is no entry point for the code you wrote. Typical aspnet entry is Page_Load but, in your purpouse, you must use Application_Start in Global.asax .
Anyway IIS web apps are not intended to host scheduled tasks, so I suggest to develop an .exe to be called by Task Scheduler ora a Windows Service instead.
You should implement this kind of logic in Windows service not IIS.
I am creating this windows service by following the instructions at MSDN Walkthrough: Creating a Windows Service and after successful installation, I go to Services.msc to Start the Windows service and before it finishes starting up I get the following message:
The EIWindowsService service on Local Computer started and then stopped. Some services stop automatically if they are not in use by other services or programs.
I know the Windows Service starts ok because there is an entry to the log file stating that the service started. I did some research before posting on here and the answer from Some Services Stop Automatically states that the problem could either be that the OnStart method is throwing an error, or that the OnStart is not kicking off a thread. So I modified my code so that the only thing within the OnStart is the starting of two timers and the log entry therefore needing no exception handling. I also added a thread to "jump" to another method.
I tried the windows service again and I know that it "moved" to the new method that the thread pointed to because I had a log entry in there that threw aFormatException error due to some conversion I was doing. I commented out the conversion and the windows service still just began to start up and then stopped automatically.
Further research indicated to me that I might need a loop to keep the processing within the method, so I took information from C - Windows Service the service on and set up an infinite while loop. I also found that there might be Garbage Collection going on and established a KeepAlive statement for the timers as suggested in Examples section of MSDN Timer Class. Still the same issues.
At this point I feel I've exhaused all the research I can do so it would be appropriate to post my question here. All my code is below and I will note that before I performed any change I uninstalled the Windows Service, removed the Setup Project, and deleted the installers from the C# code. I then made changes and started back over with the instructions in the Walkthrough starting at the point where it instructs how to setup the installers. I did this each time because I found that if I made changes and did not uninstall the Windows Service, remove the Setup Project, and delete the installers, then my changes would not take effect on the currently installed windows service.
Any assistance you can give would be most appreciated. I will be here for another 15min and then I will check this first thing tomorrow.
SERVICE1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Timers;
namespace EIWindowsService
{
public partial class Service1 : ServiceBase
{
Logs.ErrorLog logFile = new Logs.ErrorLog();
private System.Threading.Thread onStartThread;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
iTimer.Start();
iTimer.Elapsed += new ElapsedEventHandler(iTimer_Elapsed);
pTimer.Start();
pTimer.Elapsed += new ElapsedEventHandler(pTimer_Elapsed);
onStartThread = new System.Threading.Thread(TimerValue);
onStartThread.Start();
logFile.SendToLog("EIWindows Service started on " + GetDate());
}
catch (ArgumentOutOfRangeException ex)
{
logFile.SendToLog("ArgumentOutOfRangeException", "EIWindowsService\\Service1.cs", "OnStart()", ex);
} //end of ArgumentOutOfRangeException CATCH statement
}
protected override void OnStop()
{
iTimer.Stop();
pTimer.Stop();
logFile.SendToLog("EIWindowsService\\Service1.cs", "OnStop()", "EIWindows Service stopped on " + GetDate());
}
private void TimerValue()
{
try
{
/*commented out because it was throwing an exception error*/
//double iTimerValue = Convert.ToDouble(iTimer.ToString());
//double pTimerValue = Convert.ToDouble(pTimer.ToString());
while (1 > 0)
{
//if (iTimerValue % 1800000 == 0) //if the timer hits the 30min mark
//{
// logFile.SendToLog("Current iTimer Value = " + iTimerValue.ToString());
//}
//if (pTimerValue % 1800000 == 0) //if the timer hits the 30min mark
//{
// logFile.SendToLog("Current pTimer Value = " + pTimerValue.ToString());
//}
GC.KeepAlive(iTimer);
GC.KeepAlive(pTimer);
}
//TimerValue();
}
catch (OverflowException ex)
{
logFile.SendToLog("OverflowException", "EIWindowsService\\Service1.cs", "TimerValue()", ex);
} //end of OverflowException CATCH statement
catch (ArgumentException ex)
{
logFile.SendToLog("ArgumentException", "EIWindowsService\\Service1.cs", "TimerValue()", ex);
} //end of ArgumentException CATCH statement
catch (FormatException ex)
{
logFile.SendToLog("FormatException", "EIWindowsService\\Service1.cs", "TimerValue()", ex);
} //end of FormatException CATCH statement
}
private string GetDate()
{
string current = "No Date Recorded";
try
{
current = DateTime.Now.ToString("F");
}
catch (FormatException ex)
{
logFile.SendToLog("FormatException", "EIWindowsService\\Service1.cs", "GetDate()", ex);
} //end of FormatException CATCH statement
return current;
} //end of method GetDate
private void iTimer_Elapsed(object source, ElapsedEventArgs e)
{
try
{
iTimer.Stop();
ImportI();
iTimer.Start();
}
catch (ArgumentOutOfRangeException ex)
{
logFile.SendToLog("ArgumentOutOfRangeException", "EIWindowsService\\Service1.cs", "iTimer_Elapsed()", ex);
} //end of ArgumentOutOfRangeException CATCH statement
} //end of method iTimer_Elapsed
private void pTimer_Elapsed(object source, ElapsedEventArgs e)
{
try
{
pTimer.Stop();
ImportP();
pTimer.Start();
}
catch (ArgumentOutOfRangeException ex)
{
logFile.SendToLog("ArgumentOutOfRangeException", "EIWindowsService\\Service1.cs", "pTimer_Elapsed()", ex);
} //end of ArgumentOutOfRangeException CATCH statement
} //end of method pTimer_Elapsed
private void ImportI()
{
//does some action but commented out because it never gets here and is not relavant to this question.
} //end of method ImportI
private void ImportP()
{
//does some action but commented out because it never gets here and is not relavant to this question.
} //end of method ImportP
}
}
SERVICE1.DESIGNER.CS (the relavant stuff)
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.pTimer = new System.Timers.Timer(10800000); //3hrs
this.iTimer = new System.Timers.Timer(3600000); //1hr
//
// pTimer
//
this.pTimer.Enabled = true;
//
// iTimer
//
this.iTimer.Enabled = true;
//
// Service1
//
this.ServiceName = "EIWindowsService";
}
#endregion
private System.Timers.Timer pTimer;
private System.Timers.Timer iTimer;
You don't need to create a separate thread or worry about the garbage collector. The framework handles all that for you. Just create the timers and they will be called. Here's an example.
public partial class Service1 : ServiceBase
{
private Timer timer;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer = new Timer(1000);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
using (StreamWriter writer = File.AppendText(#"C:\Users\alfonso\Desktop\log.txt"))
{
writer.WriteLine(string.Format("{0} : {1}", DateTime.Now, "Logging from the service"));
}
}
protected override void OnStop()
{
}
}
Something else that may help someone coming across this post and the above solutions do not work. When I had this problem, I had added this to the config of my Windows Service:
<system.web>
<compilation debug ="true" />
</system.web>
I added this so that I could attach the debugger to the service when running it locally, however when I tried to move the service to another server it gave the specified error. By removing this from the config the service worked again.