IllegalMonitorStateException with ArrayList NotifyAll() Wait() - c#

I know there are many answers on this topic and I think I have read them all.
Most of the answers do not include the namespace they use, and compiling the code they suggest is virtually impossible.
I am using VS 2015 Comunity with Xamarin and this is an Android project.
My namespaces:
using Android.Graphics;
using Android.Util;
using Java.Lang;
using Java.Util;
My code:
public static int updateWait() // Called by a thread.
{
int value = 0;
try
{
while (msgList.IsEmpty)
{
msgList.Wait();
}
value = (int)msgList.Get(0);
msgList.Remove(0) ;
}
catch (Exception e)
{
Log.Debug("", "" + e);
}
return value;
}
public static void updateNotify() // called by a service
{
if (msgList.IsEmpty)
{
msgList.Add(1000);
}
try
{
msgList.NotifyAll();
}
catch ( Exception e)
{
Log.Debug("", "" + e);
}
}
The above code works correctly, since the thread from an activity seems to be blocked until the service calls updateNotify(). The problem is IllegalMonitorStateException are generated for every call to msgList.NotifyAll(), which I am ignoring.
Since only one thread notifies, and only one waits, there are no synchronization issues - but the exceptions are worrying.

You can't call notify() on an object if the current thread does not own that object's monitor.
You should put it in synchronized block.
synchronized(msgList) {
msgList.NotifyAll();
}

Related

NetMQ gets stuck when I try to dispose the Poller (Request-Reply pattern)

This is my first project using the NetMQ (ZMQ) framework, so, maybe I didn't understand how to use it exactly.
I create a Windows Forms project with two applications, one send a "ping" to the other and receives a "pong" as an answer. The protocol is not so complex and uses the Request-Reply pattern, all the commands have a first part that identifies the objective, like "query" or "inform", and a second part that contains the command or the message itself. In this case one app send a "query-ping" and the other answer with "inform-pong".
I create a class to encapsulate all the dirty job, so the main form can use the protocol in a very simple way. Everything is working fine, but when I try to close the app, it gets stuck in the poller and the app never closes. In Visual Studio I can see the pause and stop button but I don't get any exception or errors:
and when I click in pause button I get this message (The application is in break mode):
If I click in 'Continue execution' the app back to same state and never closes.
If I remove the poller the app closes normally, but of course, the poller doesn't work and the app doesn't answer anymore.
This is the code from the Form1:
using CommomLib;
using System;
using System.Windows.Forms;
namespace Test1
{
public partial class Form1 : Form
{
ZmqCommunication zmqComm = new ZmqCommunication();
int portNumber;
string status;
public Form1()
{
InitializeComponent();
InitializeZmqComm();
}
public void InitializeZmqComm()
{
// Calls the ZMQ initialization.
portNumber = zmqComm.InitializeComm();
if (portNumber == 0)
status = "Ini error";
else
status = "Ini ok";
}
// Executes a ping command.
private void button1_Click(object sender, EventArgs e)
{
richTextBox1.Clear();
richTextBox1.AppendText(zmqComm.RequestPing(55001) + "\n");
}
}
}
And this is the code from my NetMQ class. It is in a separated library project. In my Dispose method I tried all combinations of Remove, Dispose and StopAsync and nothing works:
using NetMQ;
using NetMQ.Sockets;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
namespace CommomLib
{
public class ZmqCommunication
{
ResponseSocket serverComm = new ResponseSocket();
NetMQPoller serverPoller;
int _portNumber;
public ZmqCommunication()
{
_portNumber = 55000;
}
// Problem here! The serverPoller gets stuck.
public void Dispose()
{
//serverPoller.RemoveAndDispose(serverComm);
//serverComm.Dispose();
if (serverPoller.IsDisposed)
Debug.WriteLine("A");
//serverPoller.RemoveAndDispose(serverComm);
serverPoller.Remove(serverComm);
//serverPoller.StopAsync();
serverPoller.Dispose();
serverComm.Dispose();
if (serverPoller.IsDisposed)
Debug.WriteLine("B");
Thread.Sleep(500);
if (serverPoller.IsDisposed)
Debug.WriteLine("C");
Thread.Sleep(500);
if (serverPoller.IsDisposed)
Debug.WriteLine("D");
}
// ZMQ initialization.
public int InitializeComm()
{
bool ok = true;
bool tryAgain = true;
// Looks for a port.
while (tryAgain && ok)
{
try
{
serverComm.Bind("tcp://127.0.0.1:" + _portNumber);
tryAgain = false;
}
catch (NetMQ.AddressAlreadyInUseException)
{
_portNumber++;
tryAgain = true;
}
catch
{
ok = false;
}
}
if (!ok)
return 0; // Error.
// Set up the pooler.
serverPoller = new NetMQPoller { serverComm };
serverComm.ReceiveReady += (s, a) =>
{
RequestInterpreter();
};
// start polling (on this thread)
serverPoller.RunAsync();
return _portNumber;
}
// Message interpreter.
private void RequestInterpreter()
{
List<string> message = new List<string>();
if (serverComm.TryReceiveMultipartStrings(ref message, 2))
{
if (message[0].Contains("query"))
{
// Received the command "ping" and answers with a "pong".
if (message[1].Contains("ping"))
{
serverComm.SendMoreFrame("inform").SendFrame("pong");
}
}
}
}
// Send the command "ping".
public string RequestPing(int port)
{
using (var requester = new RequestSocket())
{
Debug.WriteLine("Running request port {0}", port);
requester.Connect("tcp://127.0.0.1:" + port);
List<string> msgResp = new List<string>();
requester.SendMoreFrame("query").SendFrame("ping");
if (requester.TryReceiveMultipartStrings(new TimeSpan(0, 0, 10), ref msgResp, 2))
{
if (msgResp[0].Contains("inform"))
{
return msgResp[1];
}
}
}
return "error";
}
}
}
Can you try to call NetMQConfig.Cleanup(); in window close event?
Place a breakpoint and see if you even get to ZmqCommunication.Dispose - that might be the issue - the form class not disposing the ZmqCommunication class.
Thanks guys for the answers, they were not the solution but pointed me in the right direction.
After a lot of debugging, I figured out it was a silly problem. I have two programs almost identical (I had both opened at the same time), one of them had the method Dispose() and the other no. During the debugging, in the breaking point, I thought I was in one program but I was in the other one. Really silly.

C# Best Practice used for application multithreading log building cross-form instance

I'm building a UI which consists of one main Form with possible instances of additional forms and custom classes. What I'm still missing is a consistent way of logging errors. So what I do is I created try-catch blocks around all code that could generate errors, mainly the things that process incoming data. I'm receiving a constant data flow (JSON) from some site, so the built in threading functionality of the framework makes it a multi threading application. Again, the multi threading part is the built-in functionality, I'm not doing this myself actively, since I'm not that smart yet, from a C# point of view. ;)
For the logging part, I've got the code below from here. Even though I'm not so smart yet, I do think I actually understand what is going on there. My concern/question however, is this: how do I implement a Multi-Threading logging mechanism that writes errors to ONE log file cross-form cross-class.
Here is an example that you can use a reference:
// MyMainForm.cs
namespace MyNameSpace
{
public partial class MyMainForm : Form
{
FooClass MyClass = new FooClass(); //<< errors could occur here
Form f = new MyForm(); //<< errors could occur here
... //<< errors could occur here
}
}
// FooClass.cs
namespace MyNameSpace
{
public class FooClass
{
public string ErrorGeneratingMethod()
{
try...catch(Exception e) { /* Write to Log file */ }
}
}
}
// Don't really know where to put this...
private static ReaderWriterLockSlim _readWriteLock = new ReaderWriterLockSlim();
public void WriteToFileThreadSafe(string text, string context)
{
string t = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
string path = Properties.Settings.Default.FQLogFileLocation;
// Set Status to Locked
_readWriteLock.EnterWriteLock();
try
{
// Append text to the file
using (StreamWriter sw = File.AppendText(path))
{
sw.WriteLine("[" + t + "]["+ context + "]" + text);
sw.Close();
}
} catch (Exception e)
{
MessageBox.Show(e.Message); // Really Exceptional (should never happen)
}
finally
{
// Release lock
_readWriteLock.ExitWriteLock();
}
}
So basically what is important for me to know is where do I put WriteToFileThreadSafe() together with _readWriteLock?
And how do I safely use this function in multiple threads in multiple forms and classes?
Thanks a lot in advance for letting me learn from you guru's :)

C# exception - Unable to cast COM object of type..... The application called an interface that was marshalled for a different thread

Here is my code, a simplified version
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using RDSCOMMUNICATORLib;
using System.Timers;
using System.Threading;
namespace RDSConsoleApplication
{
class Program
{
static public RDSComClass oObj = new RDSComClass();
static void Main(string[] args)
{
try
{
oObj.Host = "127.0.0.1";
oObj.Port = 2902;
oObj.LoadPiece(); // OK HERE
IConnectionEvents_OnPieceEventHandler PieceArraved = new IConnectionEvents_OnPieceEventHandler(oObj_OnPiece);
oObj.OnPiece += PieceArraved;
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
}
} // end main
static public void oObj_OnPiece(int lLSCRef, string strLSCName, int lPieceNumber, int bWithScans)
{
try
{
// HERE WE START GETTING EXCEPTION "Unable to cast COM object of type.....
// The application called an interface that was marshalled for a different thread"
oObj.LoadPiece();
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
}
}
} // end class Program
} // end namespace
I am referencing a COM object inside C# console application that serves as a gateway to connect to the back end and periodically receive some "piece" objects.
As a test, when I try from within the main method all works fine: I can connect, receive "piece" object and access its properties. The problem is that I need to receive and process that same "piece" object from within oObj_OnPiece callback method, and it throws the above mentioned exception. I browsed other similar posts, I understand it's a threading issue, but not sure how to resolve it. Any help is appreciated.
You try to query an interface, which is already in use in a different thread in your application. In your case you have queried by your call the interface in your main-thread first. I guess this is the first thread.
Is it possible that the eventhandler is opening a different thread to deal with the event? If this is the case ( just check this by adding one breakpoint in your event-handler before trying to access the interface , start your program and check if there a 2 threads running ).
What you have to do is: ensure that you query your interface only in one thread by removing the first call to your COM-object.

Using managed threads and fibers in CLR

Okay, the following link has a warning that the discussion uses unsupported and undocumented apis. Well I'm trying to use the code sample any way. It mostly works. Any ideas about the specific issue below relating to exceptions?
http://msdn.microsoft.com/en-us/magazine/cc164086.aspx
FYI, I made an improvement over the original sample. It was maintaining a pointer to the "previousfiber". Instead, the updated sample below uses a "mainfiber" pointer which gets passed to every fiber class. In that way, they always yield back to the main fiber. That allows the main fiber to handle scheduling for all other fibers. The other fibers always "yield" back to the main fiber.
The reason for posting this question has to do with throwing exceptions inside a fiber. According to the article, by using the CorBindToRunTime API with CreateLogicalThreadState(), SwitchOutLogicalThreadState(), etc, the framework will create a managed thread for each fiber and properly handle exceptions.
However, in the included code examples it has an UUnit test which experiments with throwing a managed exception within a Fiber and also catching it within the same fiber. That soft of works. But after handling it by logging a message, it seems the stack is in a bad state because if the fiber calls any other method even an empty method, the whole application crashes.
This implies to me that SwitchOutLogicalThreadState() and SwitchInLogicalThreadState() maybe aren't being used properly or else maybe they're not doing their job.
NOTE: One clue to the problem is that the managed code logs out the Thread.CurrentThread.ManagedThreadId and it is the same for every fiber. This suggests that the CreateLogicalThreadState() method didn't really create a new managed thread as advertised.
To analyze this better, I have made a pseudocode listing of the order of low level APIs called to handle the fibers. Remember, that fibers all run on the same thread so there's nothing concurrently happening, it's a linear logic. The necessary trick of course is to save and restore the stack. That's where it seems to be having trouble.
It starts out as simply a thread so then it converts to a fiber:
ConvertThreadToFiber(objptr);
CreateFiber() // create several win32 fibers.
Now invoke a fiber the first time, it's startup method does this:
corhost->SwitchOutLogicalThreadState(&cookie); The main cookie is
held on the stack.
SwitchToFiber(); // first time calls the fiber startup method
corhost->CreateLogicalThreadState();
run the main fiber abstract method.
Eventually the fiber needs to yield back to the main fiber:
corhost->SwitchOutLogicalThreadState(&cookie);
SwitchToFiber(fiber);
corhost->SwitchInLogicalThreadState(&cookie); // the main fiber
cookie, right?
Also the main fiber will resume a preexisting fiber:
corhost->SwitchOutLogicalThreadState(&cookie);
SwitchToFiber(fiber);
corhost->SwitchInLogicalThreadState(&cookie); // the main fiber cookie, right?
The following is fibers.cpp which wraps the fiber api for managed code.
#define _WIN32_WINNT 0x400
#using <mscorlib.dll>
#include <windows.h>
#include <mscoree.h>
#include <iostream>
using namespace std;
#if defined(Yield)
#undef Yield
#endif
#define CORHOST
namespace Fibers {
typedef System::Runtime::InteropServices::GCHandle GCHandle;
VOID CALLBACK unmanaged_fiberproc(PVOID pvoid);
__gc private struct StopFiber {};
enum FiberStateEnum {
FiberCreated, FiberRunning, FiberStopPending, FiberStopped
};
#pragma unmanaged
#if defined(CORHOST)
ICorRuntimeHost *corhost;
void initialize_corhost() {
CorBindToCurrentRuntime(0, CLSID_CorRuntimeHost,
IID_ICorRuntimeHost, (void**) &corhost);
}
#endif
void CorSwitchToFiber(void *fiber) {
#if defined(CORHOST)
DWORD *cookie;
corhost->SwitchOutLogicalThreadState(&cookie);
#endif
SwitchToFiber(fiber);
#if defined(CORHOST)
corhost->SwitchInLogicalThreadState(cookie);
#endif
}
#pragma managed
__gc __abstract public class Fiber : public System::IDisposable {
public:
#if defined(CORHOST)
static Fiber() { initialize_corhost(); }
#endif
Fiber() : state(FiberCreated) {
void *objptr = (void*) GCHandle::op_Explicit(GCHandle::Alloc(this));
fiber = ConvertThreadToFiber(objptr);
mainfiber = fiber;
//System::Console::WriteLine( S"Created main fiber.");
}
Fiber(Fiber *_mainfiber) : state(FiberCreated) {
void *objptr = (void*) GCHandle::op_Explicit(GCHandle::Alloc(this));
fiber = CreateFiber(0, unmanaged_fiberproc, objptr);
mainfiber = _mainfiber->fiber;
//System::Console::WriteLine(S"Created worker fiber");
}
__property bool get_IsRunning() {
return state != FiberStopped;
}
int GetHashCode() {
return (int) fiber;
}
bool Resume() {
if(!fiber || state == FiberStopped) {
return false;
}
if( state == FiberStopPending) {
Dispose();
return false;
}
void *current = GetCurrentFiber();
if(fiber == current) {
return false;
}
CorSwitchToFiber(fiber);
return true;
}
void Dispose() {
if(fiber) {
void *current = GetCurrentFiber();
if(fiber == current) {
state = FiberStopPending;
CorSwitchToFiber(mainfiber);
}
state = FiberStopped;
System::Console::WriteLine( S"\nDeleting Fiber.");
DeleteFiber(fiber);
fiber = 0;
}
}
protected:
virtual void Run() = 0;
void Yield() {
CorSwitchToFiber(mainfiber);
if(state == FiberStopPending)
throw new StopFiber;
}
private:
void *fiber, *mainfiber;
FiberStateEnum state;
private public:
void main() {
state = FiberRunning;
try {
Run();
} catch(System::Object *x) {
System::Console::Error->WriteLine(
S"\nFIBERS.DLL: main Caught {0}", x);
}
Dispose();
}
};
void fibermain(void* objptr) {
//System::Console::WriteLine( S"\nfibermain()");
System::IntPtr ptr = (System::IntPtr) objptr;
GCHandle g = GCHandle::op_Explicit(ptr);
Fiber *fiber = static_cast<Fiber*>(g.Target);
g.Free();
fiber->main();
System::Console::WriteLine( S"\nfibermain returning");
}
#pragma unmanaged
VOID CALLBACK unmanaged_fiberproc(PVOID objptr) {
#if defined(CORHOST)
corhost->CreateLogicalThreadState();
#endif
fibermain(objptr);
#if defined(CORHOST)
corhost->DeleteLogicalThreadState();
#endif
}
}
The above fibers.cpp class file is the only class in the Visaul c++ project. It's built as a DLL with CLR support using /CLR:oldstyle switch.
using System;
using System.Threading;
using Fibers;
using NUnit.Framework;
namespace TickZoom.Utilities
{
public class FiberTask : Fiber
{
public FiberTask()
{
}
public FiberTask(FiberTask mainTask)
: base(mainTask)
{
}
protected override void Run()
{
while (true)
{
Console.WriteLine("Top of worker loop.");
try
{
Work();
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
Console.WriteLine("After the exception.");
Work();
}
}
private void Work()
{
Console.WriteLine("Doing work on fiber: " + GetHashCode() + ", thread id: " + Thread.CurrentThread.ManagedThreadId);
++counter;
Console.WriteLine("Incremented counter " + counter);
if (counter == 2)
{
Console.WriteLine("Throwing an exception.");
throw new InvalidCastException("Just a test exception.");
}
Yield();
}
public static int counter;
}
[TestFixture]
public class TestingFibers
{
[Test]
public void TestIdeas()
{
var fiberTasks = new System.Collections.Generic.List<FiberTask>();
var mainFiber = new FiberTask();
for( var i=0; i< 5; i++)
{
fiberTasks.Add(new FiberTask(mainFiber));
}
for (var i = 0; i < fiberTasks.Count; i++)
{
Console.WriteLine("Resuming " + i);
var fiberTask = fiberTasks[i];
if( !fiberTask.Resume())
{
Console.WriteLine("Fiber " + i + " was disposed.");
fiberTasks.RemoveAt(i);
i--;
}
}
for (var i = 0; i < fiberTasks.Count; i++)
{
Console.WriteLine("Disposing " + i);
fiberTasks[i].Dispose();
}
}
}
}
The above unit test gives the following output and then crashes badly:
Resuming 0
Top of worker loop.
Doing work on fiber: 476184704, thread id: 7
Incremented counter 1
Resuming 1
Top of worker loop.
Doing work on fiber: 453842656, thread id: 7
Incremented counter 2
Throwing an exception.
Exception: Just a test exception.
After the exception.
A time ago, I experienced the same problem - I tried to use the code snippet in .NET 3.5 (later on 4.0) and it crashed. This convinced me to turn away from the "hacky" solution. The truth is that .NET is missing a generic co-routine concept. There are some guys which simulate co-routines by enumerators and the yield keyword (see http://fxcritic.blogspot.com/2008/05/lightweight-fibercoroutines.html). However, this has clear disadvantages to me: It is not as intuitive to use as good-old Win32 fibers and it requires you to use IEnumerable as return type for each co-routine.
Maybe this arcticle: http://msdn.microsoft.com/en-us/vstudio/gg316360 is interesting for you. Microsoft is about to introduce a new async keyword. A community technology preview (CTP) is offered for download. I guess it should be possible to develop a clean co-routine implementation on top of those async extensions.
When using fibers you must store the exception management stack state on a local variable (on the stack) before you switch to your main fiber.
The first operation right after the switch (when execution comes back) is restoring the exception stack from your backup in a local variable.
Take a look at this blog entry on how to use fibers with Delphi without breaking exception handling: http://jsbattig.blogspot.com/2015/03/how-to-properly-support-windows-fibers.html
The point is, if you want to use Fibers AND write exception handlers AND switch fibers inside and try finally or try-catch block, you will have to figure out how to do this with CLR.
I'm playing around with Fibers in C# and I could not find the way yet. If there were a way to do it, I imagine it will be a hack at the end of the day.
You can use Delphi coroutines framework https://github.com/Purik/AIO
It has completed Fibers implementation.
For example, you can wrap anonymous procedure to Fiber- procedure will be runned in Fiber context, you can access and detect any exception raised in Fiber

C# Windows Service - Started and then Stopped Automatically

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.

Categories

Resources