c# Read real time from windows event log - c#

i can succesfully read events from event log. But polling all events has very bad performance. I wonder if there is an event or something that i can subscribe to catch log entries "as they happen"?
Is this possible?
EventLog log = new EventLog("Security");
var entries = log.Entries.Cast<EventLogEntry>().Where(x => x.InstanceId == 4624).Select(x => new
{
x.MachineName,
x.Site,
x.Source,
x.UserName,
x.Message
}).ToList();
Console.WriteLine(entries[0].UserName);

You can use EventLogWatcher for this purpose. You can subscribe to desired log filter(s) and implement a handler function to execute when you receive any events.
public static void eventLogSubscription()
{
using (EventLog eventLog = new EventLog("Application"))
{
String path = Path.GetTempPath();
eventLog.Source = "Event Log Reader Application";
eventLog.WriteEvent(new EventInstance(1003, 0, EventLogEntryType.Information), new object[] { "The event log watcher has started" , path});
//eventLog.WriteEntry(arg.EventRecord.ToXml(), EventLogEntryType.Information, 1001, 1);
eventLog.Dispose();
}
EventLogWatcher watcher = null;
try
{
string eventQueryString = "*[System/EventID=4688]" +
"and " +
"*[EventData[Data[#Name = 'NewProcessName'] = 'C:\\Windows\\explorer.exe']]";
EventLogQuery eventQuery = new EventLogQuery(
"Security", PathType.LogName, eventQueryString);
watcher = new EventLogWatcher(eventQuery);
watcher.EventRecordWritten +=
new EventHandler<EventRecordWrittenEventArgs>(
handlerExplorerLaunch);
watcher.Enabled = true;
}
catch (EventLogReadingException e)
{
Console.WriteLine("Error reading the log: {0}", e.Message);
}
Console.ReadKey();
}
public static void handlerExplorerLaunch(object obj,
EventRecordWrittenEventArgs arg)
{ if (arg.EventRecord != null)
{
using (EventLog eventLog = new EventLog("Application"))
{
eventLog.Source = "Event Log Reader Application";
eventLog.WriteEvent(new EventInstance(1001, 0, EventLogEntryType.Information), new object[] {arg.EventRecord.FormatDescription() });
//eventLog.WriteEntry(arg.EventRecord.ToXml(), EventLogEntryType.Information, 1001, 1);
eventLog.Dispose();
}
}
else
{
Console.WriteLine("The event instance was null.");
}
}

I have found this to work more reliably.
using System;
using System.Diagnostics.Eventing.Reader;
static void Main(string[] args)
{
if (args is null) throw new ArgumentNullException(nameof(args));
LoadEventLogs();
Console.ReadKey();
}
private static void LoadEventLogs()
{
EventLogSession session = new EventLogSession();
EventLogQuery query = new EventLogQuery("Security", PathType.LogName, "*[System/EventID=4688]")
{
TolerateQueryErrors = true,
Session = session
};
EventLogWatcher logWatcher = new EventLogWatcher(query);
logWatcher.EventRecordWritten += new EventHandler<EventRecordWrittenEventArgs>(LogWatcher_EventRecordWritten);
try
{
logWatcher.Enabled = true;
}
catch (EventLogException ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
private static void LogWatcher_EventRecordWritten(object sender, EventRecordWrittenEventArgs e)
{
var time = e.EventRecord.TimeCreated;
var id = e.EventRecord.Id;
var logname = e.EventRecord.LogName;
var level = e.EventRecord.Level;
var task = e.EventRecord.TaskDisplayName;
var opCode = e.EventRecord.OpcodeDisplayName;
var mname = e.EventRecord.MachineName;
Console.WriteLine($#"{time}, {id}, {logname}, {level}, {task}, {opCode}, {mname}");
}

Related

Using named pipes, how to write messages client receives in its form one by one?

I have a Windows service and a client listening with the following funcionality:
Win service:
Creates named pipe
Creates client process
Waits for connection
Writes to client process
Reads from client
Writes to client process
Reads from client
...
public static bool StartProcessAsCurrentUser()
{
var hUserToken = IntPtr.Zero;
var sInfo = new STARTUPINFO();
var procInfo = new PROCESS_INFORMATION();
var pEnv = IntPtr.Zero;
int iResultOfCreateProcessAsUser;
string cmdLine = "ClientNamedPipeForm.exe";
sInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
byte[] buffer = new byte[BUFSIZE];
try
{
var tSecurity = new SECURITY_ATTRIBUTES();
tSecurity.nLength = Marshal.SizeOf(tSecurity);
var pSecurity = new SECURITY_ATTRIBUTES();
pSecurity.nLength = Marshal.SizeOf(pSecurity);
pSecurity.bInheritHandle = true; //For controling handles from child process
IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf(pSecurity));
Marshal.StructureToPtr(pSecurity, pointer, true);
PipeSecurity ps = new PipeSecurity();
System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(System.Security.Principal.WellKnownSidType.WorldSid, null);
PipeAccessRule par = new PipeAccessRule(sid, PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow);
ps.AddAccessRule(par);
NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.WriteThrough, 10, 10, ps);
StreamWriter sw = new StreamWriter(pipeServer);
if (!CreateProcessAsUser(hUserToken,
null, // Application Name
cmdLine, // Command Line
IntPtr.Zero,
IntPtr.Zero,
true,
dwCreationFlags,
pEnv,
null, // Working directory
ref sInfo,
out procInfo))
{
throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed.\n");
}
try
{
pipeServer.WaitForConnection();
sw.WriteLine("Waiting");
sw.Flush();
pipeServer.WaitForPipeDrain();
Thread.Sleep(5000);
sw.WriteLine("Waiting2");
sw.Flush();
pipeServer.WaitForPipeDrain();
Thread.Sleep(5000);
sw.WriteLine("Waiting32");
sw.Flush();
pipeServer.WaitForPipeDrain();
Thread.Sleep(5000);
sw.WriteLine("QUIT");
sw.Flush();
pipeServer.WaitForPipeDrain();
}
catch (Exception ex) { throw ex; }
finally
{
if (pipeServer.IsConnected) { pipeServer.Disconnect(); }
}
}
finally
{
//Closing things
}
return true;
}
Client:
Creates named pipe
Connects
Reads from service
Writes in its Form
Writes to service
Reads from service
Writes in its Form
Writes to service
...
private void Client()
{
try
{
IntPtr hPipe;
string dwWritten;
byte[] buffer = new byte[BUFSIZE];
NamedPipeClientStream pipeClient = new NamedPipeClientStream(".","testpipe", PipeDirection.In, PipeOptions.WriteThrough);
if (pipeClient.IsConnected != true) { pipeClient.Connect(); }
StreamReader sr = new StreamReader(pipeClient);
string temp;
bool cont = true;
while (cont)
{
temp = "";
temp = sr.ReadLine();
if (temp != null)
{
listBox1.Items.Add(temp);
listBox1.Refresh();
}
if (temp != "QUIT")
{
sw.WriteLine("Response");
sw.Flush();
pipeClient.WaitForPipeDrain();
}
else
{
sw.WriteLine("Response");
cont = false;
}
}
}
catch (Exception ex)
{
throw new Exception("Exception: " + ex.Message);
}
The problem appears writting to listbox1. Form (and its listbox1) only appears on user screen when the whole process has ended, and it shows the four message at once. I have Thread.Sleep(5000) in service side in order to evidence that each message is written separately, but I'm not sure if process doesn't wait to Thread and I'm testing it wrongly or Form is shown with all messages at once by some reason...
Your problem is the while loop that is blocking the current Thread, this thread is also used to refresh the UI.
1) A poor solution is calling DoEvents() within the while loop. But it would be wise to do more research to implement method 2
2) It's better to create a class that will create a Thread and triggers an event to when a message is received.
For example: (writting online so may contain some syntax/typos) So I will call it PSEUDO code ;-)
public class MessageEventArgs : EventArgs
{
public string Message { get; private set;}
public MessageEventArgs(string message)
{
Message = message;
}
}
public class MyReceiver : IDisposable
{
private Thread _thread;
private ManualResetEvent _terminating = new ManualResetEvent(false);
public void Start()
{
_thread = new Thread(() =>
{
try
{
IntPtr hPipe;
string dwWritten;
byte[] buffer = new byte[BUFSIZE];
NamedPipeClientStream pipeClient = new NamedPipeClientStream(".","testpipe", PipeDirection.In, PipeOptions.WriteThrough);
if (pipeClient.IsConnected != true) { pipeClient.Connect(); }
StreamReader sr = new StreamReader(pipeClient);
string temp;
while(!_terminating.WaitOne(0))
{
temp = "";
temp = sr.ReadLine();
if (temp != null)
{
OnMessage?.Invoke(temp);
}
if (temp != "QUIT")
{
sw.WriteLine("Response");
sw.Flush();
pipeClient.WaitForPipeDrain();
}
else
{
sw.WriteLine("Response");
_terminating.Set();
}
}
}
catch (Exception ex)
{
throw new Exception("Exception: " + ex.Message);
}
});
_thread.Start();
}
public void Dispose()
{
_terminating.Set();
_thread.Join();
}
public event EventHandler<MessageEventArgs> OnMessage;
}
// Example of how to use the Receiver class.
public class Form1: Form
{
MyReceiver _receiver;
public Form1()
{
InitializeComponent();
this.FormClosed += FormClosed;
_receiver = new MyReceiver();
_receiver.OnMessage += MessageReceived;
_receiver.Start();
}
public void MessageReceived(object sender, MessageEventArgs e)
{
// You need to invoke this, because the event is run on other than the UI thread.
this.Invoke(new Action(() =>
{
listBox1.Items.Add(e.Message);
});
}
public void FormClosed(object sender, EventArgs e)
{
_receiver.Dispose();
}
}

Service stops when connection is lost to the database

I have coded a service in C# which runs and updates a CRM solution. I am trying to get the service to re-establish a connection to the database if it has to drop for some reason. So far when I detach the database and then reattach it, the service stops by itself.. Another thing is that then I detach the database, there is no exception logged by my synch app - it just stops dead.
My partial class where I call my synch from:
namespace Vessel_Schedule_Synch
{
[DisplayName("CRM Vessel Synch")]
partial class startVessel : ServiceBase
{
System.Threading.Timer t;
VesselUpdater v;
protected override void OnStart(string[] args)
{
//System.Threading.Thread.Sleep(20000);
v = new VesselUpdater();
t = new System.Threading.Timer(new System.Threading.TimerCallback(t_TimerCallback), null, 0, 300000);
//InfoLogger.Info("Starting service " + this.ServiceName, true);
}
private void t_TimerCallback(object state)
{
t.Change(Timeout.Infinite, Timeout.Infinite);
lock (v)
{
InfoLogger.Info("Timer fired... updating vessels");
try
{
v.Process();
v.updateCRM();
}
catch (Exception e)
{
if (v == null)
{ throw e; }
else
{
InfoLogger.Exception(e);
}
}
finally
{
InfoLogger.Info("End of Timer Trigger... Restarting Timer.");
t.Change(30000, 30000);
}
}
}
protected override void OnStop()
{
InfoLogger.Info("Service Stopped " + this.ServiceName, true);
}
}
}
My synch class where I have tried to use a bool to test the connection:
namespace Vessel_Schedule_Synch
{
class VesselUpdater
{
private OrganizationServiceProxy _serviceProxy;
private IOrganizationService _service;
private Logger logger = LogManager.GetLogger("VesselUpdater");
public string ConnectionString { get; set; }
public string ServiceUrl { get; set; }
int i = 0;
private bool InitialiseCRMConnection;
public VesselUpdater()
{
InitialiseCRMConnection = true;
Console.WriteLine("Starting the service");
LogMessage("Starting service");
ServiceUrl = ConfigurationManager.AppSettings["CRMUrl"];
LogMessage(ConnectionString);
ConnectionString = ConfigurationManager.ConnectionStrings["iRoot"].ConnectionString;
LogMessage(ServiceUrl);
Console.WriteLine(ServiceUrl);
}
public void Process()
{
if (!InitialiseCRMConnection)
return;
LogMessage("Process Starting");
ClientCredentials UserCredentials = new ClientCredentials();
string UserName = ConfigurationManager.AppSettings["User"];
string Password = ConfigurationManager.AppSettings["Password"];
UserCredentials.UserName.UserName = UserName;
UserCredentials.UserName.Password = Password;
ClientCredentials DivCredentials = null;
Uri HomeRealmURI = null;
Uri serviceurl = new Uri(ServiceUrl);
_serviceProxy = new OrganizationServiceProxy(serviceurl, HomeRealmURI, UserCredentials, DivCredentials);
_serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
_service = (IOrganizationService)_serviceProxy;
_serviceProxy.EnableProxyTypes();
LogMessage("CRM Connection Initiated");
InitialiseCRMConnection = false;
}
public void updateCRM()
{
try
{
ProcessVesselSchedule("Insert");
ProcessVesselSchedule("Modification");
}
catch (Exception e)
{
InitialiseCRMConnection = true;
InfoLogger.Exception(e);
LogMessage("Exception " + e);
}
}
private void ProcessVesselSchedule(string Type)
{
if (InitialiseCRMConnection)
return;
try
{
LogMessage(string.Format("Processing Vessesl Schedules {0}", Type));
using (SqlConnection con = new SqlConnection(ConnectionString))
{
SqlCommand cmd = new SqlCommand("VesselScheduleInformation", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Type", Type);
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
try
{
LogMessage("Processing Record");
LogMessage(dr["new_Name"].ToString());
string Name = dr["new_Name"].ToString() + " " + dr["new_VoyageNo"].ToString();
string Vesselname = dr["new_Name"].ToString();
int LineNo = (int)dr["Line Number"];
string NAVVesselScheduleCode = dr["new_NAVVesselScheduleCode"].ToString();
string CarrierService = dr["new_CarrierService"].ToString();
string ETA = dr["new_ETA"].ToString();
string ETD = dr["new_ETD"].ToString();
string VesselCode = dr["new_Vessel"].ToString();//Vessel Code
string VoyageNo = dr["new_VoyageNo"].ToString();
string TranshipmentVessel = dr["new_TranshipmentVessel"].ToString();
string TranshipmentVoyageNo = dr["new_TranshipmentVoyageNo"].ToString();
string Port = dr["new_Port"].ToString();
string PortOfDis = dr["new_DischargePort"].ToString();
string PortOfLoad = dr["new_LoadPort"].ToString();
//string StackStart = dr["new_StackStart"].ToString();
//string StackEnd = dr["new_StackEnd"].ToString();
bool Create = false;
LogMessage("Assigned all variables");
Console.WriteLine("Assigned all variables");
new_vesselschedule VesselS = FindVessleSchedule(NAVVesselScheduleCode, LineNo, out Create);
//if (DateTime.Parse(StackStart).ToUniversalTime() >= DateTime.Parse("1900-01-01"))
//{
// VesselS["new_stackstart"] = DateTime.Parse(StackStart).ToUniversalTime();
//}
//if (DateTime.Parse(StackEnd).ToUniversalTime() >= DateTime.Parse("1900-01-01"))
//{
// VesselS["new_stackend"] = DateTime.Parse(StackEnd).ToUniversalTime();
//}
VesselS.new_name = Name;
VesselS.new_navvesselschedulecode = NAVVesselScheduleCode;
VesselS.new_CarrierService = CarrierService;
if (DateTime.Parse(ETA).ToUniversalTime() >= DateTime.Parse("1900-01-01"))
{
VesselS.new_ETA = DateTime.Parse(ETA).ToUniversalTime();
}
if (DateTime.Parse(ETD).ToUniversalTime() >= DateTime.Parse("1900-01-01"))
{
VesselS.new_ETD = DateTime.Parse(ETD).ToUniversalTime();
}
VesselS.new_vesselcodeimport = VesselCode;
VesselS.new_vesselnameimport = Vesselname;
VesselS.new_VoyageNo = VoyageNo;
VesselS.new_TransshipmentVessel = TranshipmentVessel;
VesselS.new_TransshipmentVoyageNo = TranshipmentVoyageNo;
VesselS.new_dischargeportimport = PortOfDis;
VesselS.new_loadportimport = PortOfLoad;
if (Create)
{
LogMessage(string.Format("Created {0} {1}", NAVVesselScheduleCode, LineNo));
_serviceProxy.Create(VesselS);
}
else
{
LogMessage(string.Format("Updated {0} {1}", NAVVesselScheduleCode, LineNo));
_serviceProxy.Update(VesselS);
}
using (SqlCommand cmdUpdateMates = new SqlCommand())
{
SqlConnection con2 = new SqlConnection(ConnectionString);
con2.Open();
cmdUpdateMates.Connection = con2;
cmdUpdateMates.CommandText = "ProcessedVessSched";
cmdUpdateMates.CommandType = CommandType.StoredProcedure;
cmdUpdateMates.Parameters.AddWithValue("#VesselSched", NAVVesselScheduleCode);
cmdUpdateMates.Parameters.AddWithValue("#LineNo", LineNo);
cmdUpdateMates.ExecuteNonQuery();
i++;
Console.WriteLine("Created/Updated" + " " + i);
}
}
catch (Exception e)
{
InitialiseCRMConnection = true;
InfoLogger.Exception(e);
LogMessage("Exception " + e);
}
}
}
}
catch (SqlException e)
{
InfoLogger.Exception(e);
LogMessage("SQL Exception " + e);
}
catch (Exception e)
{
InitialiseCRMConnection = true;
InfoLogger.Exception(e);
LogMessage("Exception " + e);
}
}
public void LogMessage(string Message)
{
LogEventInfo myEvent = new LogEventInfo(LogLevel.Debug, "", Message);
myEvent.LoggerName = logger.Name;
logger.Log(myEvent);
}
private new_vesselschedule FindVessleSchedule(string NAVVesselScheduleCode, int LineNo, out bool Create)
{
QueryExpression query = new QueryExpression(new_vesselschedule.EntityLogicalName);
query.ColumnSet.AllColumns = true;
query.Criteria = new FilterExpression();
query.Criteria.AddCondition("new_navvesselschedulecode", ConditionOperator.Equal, NAVVesselScheduleCode);
query.Criteria.AddCondition("new_lineno", ConditionOperator.Equal, LineNo);
EntityCollection entitycollection = _serviceProxy.RetrieveMultiple(query);
if (entitycollection.Entities.Count == 0)
{
new_vesselschedule n = new new_vesselschedule();
n.new_navvesselschedulecode = NAVVesselScheduleCode;
n.new_lineno = LineNo;
Create = true;
return n;
}
Create = false;
return (new_vesselschedule)entitycollection.Entities[0];
}
}
}
Am I missing something here?
I found the issue in my code, I had forgotten to sent InitialiseCRMConnection = true; in my SQL Exception thus it could never go through the motions of reInitialising the connection as it would always return;
Fix:
catch (SqlException e)
{
InitialiseCRMConnection = true;
InfoLogger.Exception(e);
LogMessage("SQL Exception " + e);
}

FileSystem Watcher Firing multiple events

It seems like my file system watcher is firing mulitple events and then ending up giving me an error:
The process cannot access the file, file is in use.
Here is my code:
private void button1_Click(object sender, EventArgs e)
{
// Form2 popup = new Form2();
if (Directory.Exists(this.textBox2.Text) && string.IsNullOrWhiteSpace(textBox2.Text))
{
MessageBox.Show("Please Select Source Folder");
return;
}
else if (Directory.Exists(this.textBox3.Text) && string.IsNullOrWhiteSpace(textBox3.Text))
{
MessageBox.Show("Please Select Destination Folder");
return;
}
else WatchFile();
private void WatchFile(/*string watch_folder*/)
{
FileSystemWatcher _watcher = new FileSystemWatcher();
_watcher.Path = textBox2.Text;
_watcher.NotifyFilter = NotifyFilters.LastWrite;
_watcher.Filter = "*.log";
_watcher.Changed += new FileSystemEventHandler(InitList);
_watcher.EnableRaisingEvents = true;
_watcher.IncludeSubdirectories = false;
listBox1.Items.Add("Started Monitoring Directory " + textBox2.Text);
listBox1.SelectedIndex = listBox1.Items.Count - 1;
}
private object lockObject = new Object();
public void InitList(object source, FileSystemEventArgs f)
{
_recordList = new List<MyData>();
string fileName = f.FullPath;
string filePath = f.Name;
string trPath = fileName;
string[] arrstringPath = new string[3];
arrstringPath[0] = filePath.Substring(2, 2);
arrstringPath[1] = filePath.Substring(4, 2);
arrstringPath[2] = filePath.Substring(6, 2);
string tempPath = "LG" + arrstringPath[0] + arrstringPath[1] + arrstringPath[2] + ".001";
string v15nativePath = textBox3.Text + tempPath;
_watcher.EnableRaisingEvents = false;
if (!Monitor.TryEnter(lockObject))
{
return;
}
else
try
{
//_watcher.EnableRaisingEvents = false;
_watcher.Changed -= new FileSystemEventHandler(InitList);
FileStream trFS = new FileStream(trPath, FileMode.Open, FileAccess.Read);
StreamReader trSR = new StreamReader(trFS);
// FileStream v15FS = new FileStream(v15nativePath, FileMode.Open, FileAccess.Write);
StreamWriter v15SR = new StreamWriter(v15nativePath, false);
var timeIndex = "S";
Func<string, MyData> values = new Func<string, MyData>(
(x) =>
{
if ((x[0].ToString()) == "S")
{
var temptime = x.IndexOf("S");
timeIndex = x.Substring(temptime + 1, 4);
}
if ((x[0].ToString()) == "C")
{
var trackIndex = x.IndexOf(":");
var titleidString = x.Substring(11, 6);
var trackString = x.Substring(17, 40);
var trackDuration = x.Substring(57, 5);
return new MyData { Time = timeIndex, Duration = trackDuration, TitleID = titleidString, Track = trackString };
}
else
return null;
});
while (trSR.Peek() != -1)
{
var data = trSR.ReadLine();
MyData my = values(data);
if (my != null)
_recordList.Add(my);
}
trFS.Close();
trSR.Close();
var groupData = from data in _recordList
select new
{
Name = data.Track,
Duration = data.Duration,
Time = data.Time,
ID = data.TitleID
};
foreach (var item in groupData)
{
var newstringLen = item.Name.Truncate(27);
var v15timeString = item.Duration;
var v15fileString = "C" + item.Time + ":" + "00" + item.ID + " " + newstringLen + v15timeString;
v15SR.WriteLine(v15fileString);
v15SR.Flush();
}
v15SR.Close();
this.Invoke((MethodInvoker)delegate { listBox1.Items.Add(string.Format("File is Translated")); });
_watcher.Changed += new FileSystemEventHandler(InitList);
}
catch (Exception e)
{
//listBox1.Items.Add("The process failed: "+" "+e.ToString());.
MessageBox.Show("The Process Failed:" + e.ToString());
}
finally
{
Monitor.Exit(lockObject);
_watcher.Path = textBox2.Text;
_watcher.EnableRaisingEvents = true;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
I have called _watcher.EnableRaisingEvents = false; before the try block and then make it true in the final block yet. the watching get's disabled while I do the processing then why does it run the InitList method again after it finishes. This seems like a mulitple run on the same file, and so causing this exception

Windows service shuts off after running first record

I have a windows service that is supposed to check for a record, email a report for that record, delete the record and then repeat for the table. It checks for the record, emails a report for the first record then shuts off. Any ideas??
Service code:
namespace ReportSender
{
public partial class EmailReportService : ServiceBase
{
private EmailReportApp _app = new EmailReportApp();
public Timer serviceTimer = new Timer();
public EmailReportService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
//Set interval (from App Settings) and enable timer
serviceTimer.Elapsed += new ElapsedEventHandler(ServiceTimer_OnElapsed);
//Use Conversion utility to determine next start date/time based on properties, use DateTime.Subtract() to find milliseconds difference between Now and the next start time
//serviceTimer.Interval = Date.AddInterval(Properties.Settings.Default.IntervalType, Properties.Settings.Default.Interval).Subtract(DateTime.Now).TotalMilliseconds;
serviceTimer.Interval = 600000;
serviceTimer.Enabled = true;
}
protected override void OnStop()
{
//Stop and disable timer
serviceTimer.Enabled = false;
}
private void ServiceTimer_OnElapsed(object source, ElapsedEventArgs e)
{
try
{
//Stop the timer to prevent overlapping runs
serviceTimer.Stop();
//Start service
//Run your app.Start() code
_app = new EmailReportApp();
_app.Start();
}
catch (Exception ex)
{
}
finally
{
//Re-start the timer
serviceTimer.Start();
}
}
}
}
Code the service is supposed to execute:
namespace ReportSender
{
class EmailReportApp
{
// Private fields
private Thread _thread;
private EventLog _log;
private void Execute()
{
try
{
// Check for a new record
DataClasses1DataContext dc = new DataClasses1DataContext();
foreach (var item in dc.reportsSent1s)
{
string matchedCaseNumber = item.CaseNumberKey;
(new MyReportRenderer()).RenderTest(matchedCaseNumber);
dc.reportsSent1s.DeleteOnSubmit(item);
dc.SubmitChanges();
}
}
catch (ThreadAbortException ex)
{
_log.WriteEntry(ex.StackTrace.ToString());
}
}
public void Start()
{
if (!EventLog.SourceExists("EventLoggerSource"))
EventLog.CreateEventSource("EventLoggerSource", "Event Logger");
_log = new EventLog("EventLoggerSource");
_log.Source = "EventLoggerSource";
_thread = new Thread(new ThreadStart(Execute));
_thread.Start();
}
public void Stop()
{
if (_thread != null)
{
_thread.Abort();
_thread.Join();
}
}
}
public class MyReportRenderer
{
private rs2005.ReportingService2005 rs;
private rs2005Execution.ReportExecutionService rsExec;
public void RenderTest(String matchedCaseNumber)
{
string HistoryID = null;
string deviceInfo = null;
string encoding = String.Empty;
string mimeType = String.Empty;
string extension = String.Empty;
rs2005Execution.Warning[] warnings = null;
string[] streamIDs = null;
rs = new rs2005.ReportingService2005();
rsExec = new rs2005Execution.ReportExecutionService();
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
rsExec.Credentials = System.Net.CredentialCache.DefaultCredentials;
rs.Url = "http://***.**.***.**/ReportServer_DEVELOPMENT/ReportService2005.asmx";
rsExec.Url = "http://***.**.***.**/ReportServer_DEVELOPMENT/ReportExecution2005.asmx";
try
{
// Load the selected report.
rsExec.LoadReport("/LawDept/LawDeptTIC", HistoryID);
// Set the parameters for the report needed.
rs2005Execution.ParameterValue[] parameters = new rs2005Execution.ParameterValue[1];
parameters[0] = new rs2005Execution.ParameterValue();
parameters[0].Name = "CaseNumberKey";
parameters[0].Value = matchedCaseNumber;
rsExec.SetExecutionParameters(parameters, "en-us");
// get pdf of report
Byte[] results = rsExec.Render("PDF", deviceInfo,
out extension, out encoding,
out mimeType, out warnings, out streamIDs);
//pass paramaters for email
DataClasses1DataContext db = new DataClasses1DataContext();
var matchedBRT = (from c in db.GetTable<vw_ProductClientInfo>()
where c.CaseNumberKey == matchedCaseNumber
select c.BRTNumber).SingleOrDefault();
var matchedAdd = (from c in db.GetTable<vw_ProductClientInfo>()
where c.CaseNumberKey == matchedCaseNumber
select c.Premises).SingleOrDefault();
//send email with attachment
MailMessage message = new MailMessage("234#acmetaxabstracts.com", "georr#gmail.com", "Report for BRT # " + matchedAdd, "Attached if the Tax Information Certificate for the aboved captioned BRT Number");
MailAddress copy = new MailAddress("a123s#gmail.com");
message.CC.Add(copy);
SmtpClient emailClient = new SmtpClient("***.**.***.**");
message.Attachments.Add(new Attachment(new MemoryStream(results), String.Format("{0}" + matchedBRT + ".pdf", "BRT")));
emailClient.Send(message);
}
catch (Exception ex)
{
}
}
}
}
The 'ServiceBase' is losing scope once the OnStart method is called. A 'ManualResetEvent' will keep the service open for you.
Use member:
ManualResetEvent stop = new ManualResetEvent(false);
Try this in your main Start():
do
{
try
{
_app = new EmailReportApp();
_app.Start();
}
catch(Exception e)
{
... handle error or log however you want
}
}
while(!stop.WaitOne(0, false))
in Stop(), make sure to do stop.Set()

Streamreader locks file

I have a c# app (Windows Service) that fires a timer event that reads files in a directory and sends out SMS using the data in the files. Next time the event fires, it tries to move the processed files in the "Processed" directory to a "Completed" directory before processing the new files. I keep getting a "File in use by another process" exception, although I am pretty sure that I dispose of everything that uses the files. If I stop the service and start it again, the files is released. Any ideas?
//Code that fires the timer
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 SmsWindowsService
{
public partial class SmsWindowsService : ServiceBase
{
private static System.Timers.Timer aTimer;
public SmsWindowsService()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("MatterCentreSMSSource"))
{
System.Diagnostics.EventLog.CreateEventSource(
"MatterCentreSMSSource", "MatterCentreSMSLog");
}
elMatterCentreSMS.Source = "MatterCentreSMSSource";
elMatterCentreSMS.Log = "MatterCentreSMSLog";
}
protected override void OnStart(string[] args)
{
string logText = string.Empty;
logText = "MatterCentreSMS Service started successfully on " + DateTime.Now;
WriteEventLog(logText);
//Create a timer with a ten second interval.
aTimer = new System.Timers.Timer(10000);
//Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
//Set the Interval to 5 minutes.
//aTimer.Interval = 300000;
aTimer.Interval = 60000;
aTimer.Enabled = true;
// If the timer is declared in a long-running method, use
// KeepAlive to prevent garbage collection from occurring
// before the method ends.
//GC.KeepAlive(aTimer);
GC.Collect();
}
protected override void OnStop()
{
string logText = string.Empty;
logText = "MatterCentreSMS Service stopped on " + DateTime.Now;
WriteEventLog(logText);
}
private void WriteEventLog(string logText)
{
elMatterCentreSMS.WriteEntry(logText);
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
string ex = string.Empty;
SendSms s = new SendSms();
ex = s.ProcessSms();
if (ex.Length > 1)
WriteEventLog(ex);
//ex = RestartService("SmsWindowsService", 60000);
//WriteEventLog(ex);
}
public string RestartService(string serviceName, int timeoutMilliseconds)
{
ServiceController service = new ServiceController(serviceName);
try
{
int millisec1 = Environment.TickCount;
TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
// count the rest of the timeout
int millisec2 = Environment.TickCount;
timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds - (millisec2 - millisec1));
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
return "MatterCentreSMS Service successfully restarted on " + DateTime.Now;
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
}
}
//Code that reads the file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
namespace SmsWindowsService
{
class Message
{
private string filePath;
public Message(string filePath)
{
this.filePath = filePath;
}
public string readSMS(string filePath)
{
const string searchmessage = "[B-->]";
StreamReader smsmessage = new StreamReader(filePath);
try
{
FileInfo filenameinfo = new FileInfo(filePath);
if (filenameinfo.Exists == false)
throw new SMSReaderException(String.Format("SMS Message {0} cannot be found ...", filePath), filePath);
smsmessage = filenameinfo.OpenText();
string smsoutput = smsmessage.ReadToEnd();
int endpos = smsoutput.IndexOf(searchmessage);
smsoutput = smsoutput.Substring(endpos + searchmessage.Length);
smsoutput = smsoutput.Replace("&", "&");
smsoutput = smsoutput.Replace("\"", """);
smsoutput = smsoutput.Replace("'", "'");
filenameinfo = null;
smsmessage.Close();
smsmessage.Dispose();
return smsoutput;
}
catch(Exception e)
{
throw new Exception("Help", e.InnerException);
}
finally
{
smsmessage.Close();
smsmessage.Dispose();
}
}
}
public class SMSReaderException : System.IO.FileNotFoundException
{
public SMSReaderException(string message, string filename)
: base(message, filename)
{
}
}
}
//Code that connects to web service and send sms
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Net;
using System.Configuration;
using SmsWindowsService.EsendexSendSmsService;
namespace SmsWindowsService
{
class SendSms
{
string filePath = string.Empty;
string directoryPath = string.Empty;
string directoryPathProcessing = string.Empty;
string directoryPathCompleted = string.Empty;
string smsLogfileDirectory = string.Empty;
string smsLogfilePath = string.Empty;
string mattercentreSMS = string.Empty;
string messageBody = string.Empty;
string messageId = string.Empty;
string messageStatus = string.Empty;
string dateTodayString = string.Empty;
long mobileNumber;
EsendexSendSmsService.SendService send;
public SendSms()
{
directoryPath = ConfigurationSettings.AppSettings[#"directoryPath"];
directoryPathProcessing = ConfigurationSettings.AppSettings[#"directoryPathProcessing"];
directoryPathCompleted = ConfigurationSettings.AppSettings[#"directoryPathCompleted"];
smsLogfileDirectory = ConfigurationSettings.AppSettings[#"smsLogfileDirectory"];
dateTodayString = DateTime.Now.ToString("yyyy/MM/dd");
smsLogfilePath = smsLogfileDirectory + dateTodayString.Replace(#"/", "_") + ".txt";
send = new EsendexSendSmsService.SendService();
}
public string ProcessSms()
{
string ex = string.Empty;
try
{
DirectoryInfo di = new DirectoryInfo(directoryPathProcessing);
ex = MoveFilesToCompleted(directoryPathProcessing, directoryPathCompleted);
if (ex.Length > 1)
return ex;
ex = MoveFilesToProcessing(directoryPath, directoryPathProcessing);
if (ex.Length > 1)
return ex;
FileInfo[] subFilesProcessing = di.GetFiles();
foreach (FileInfo subFile in subFilesProcessing)
{
filePath = directoryPathProcessing + subFile.Name;
Message sms = new Message(filePath);
mattercentreSMS = sms.readSMS(filePath);
MessageDetails d = new MessageDetails(mattercentreSMS);
mobileNumber = d.GetMobileNumber();
messageBody = d.GetMessageBody();
ex = SetHeader();
if (ex.Length > 1)
return ex;
ex = SetProxy();
if (ex.Length > 1)
return ex;
//Send the message and get the returned messageID and send status
messageId = send.SendMessage(Convert.ToString(mobileNumber), messageBody, EsendexSendSmsService.MessageType.Text);
messageStatus = Convert.ToString(send.GetMessageStatus(messageId));
ex = WriteLogFile(messageId, subFile.Name, messageStatus);
if (ex.Length > 1)
return ex;
send.Dispose();
}
di = null;
subFilesProcessing = null;
return ex;
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
private string MoveFilesToCompleted(string directoryPathProcessing, string directoryPathCompleted)
{
DirectoryInfo din = new DirectoryInfo(directoryPathProcessing);
try
{
FileInfo[] subFiles = din.GetFiles();
foreach (FileInfo subFile in subFiles)
{
subFile.MoveTo(directoryPathCompleted + subFile.Name);
}
subFiles = null;
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
finally
{
din = null;
}
}
private string MoveFilesToProcessing(string directoryPath, string directoryPathProcessing)
{
DirectoryInfo din = new DirectoryInfo(directoryPath);
try
{
FileInfo[] subFiles = din.GetFiles();
foreach (FileInfo subFile in subFiles)
{
subFile.MoveTo(directoryPathProcessing + subFile.Name);
}
subFiles = null;
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
finally
{
din = null;
}
}
private string SetHeader()
{
try
{
//Setup account details in the header
EsendexSendSmsService.MessengerHeader header = new EsendexSendSmsService.MessengerHeader();
header.Account = ConfigurationSettings.AppSettings[#"smsServiceUrl"];
header.Username = ConfigurationSettings.AppSettings[#"smsServiceUsername"];
header.Password = ConfigurationSettings.AppSettings[#"smsServicePassword"];
// set the SOAP header Authentication values
send.MessengerHeaderValue = header;
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
private string SetProxy()
{
try
{
//Create a web proxy object as the proxy server block direct request to esendex
WebProxy myProxy = new WebProxy(ConfigurationSettings.AppSettings[#"proxyaddress"], true);
myProxy.Credentials = new NetworkCredential(ConfigurationSettings.AppSettings[#"username"], ConfigurationSettings.AppSettings[#"password"]);
WebRequest.DefaultWebProxy = myProxy;
send.Proxy = myProxy;
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
private string WriteLogFile(string messageId, string smsFileName, string messageStatus)
{
try
{
if (File.Exists(smsLogfilePath))
{
//file is not empty - append log entry to file
using (StreamWriter writeSmsLog = File.AppendText(smsLogfilePath))
{
writeSmsLog.WriteLine(messageId + " " + smsFileName + " " + DateTime.Now + " " + messageStatus);
writeSmsLog.Close();
}
}
else
{
FileStream fs = File.OpenWrite(smsLogfilePath);
fs.Flush();
fs.Close();
fs.Dispose();
using (StreamWriter writeSmsLog = new StreamWriter(smsLogfilePath, true))
{
writeSmsLog.WriteLine("Message_ID File_Name Date_Sent Status");
writeSmsLog.WriteLine("======================================================================================================================================");
writeSmsLog.WriteLine(messageId + " " + smsFileName + " " + DateTime.Now + " " + messageStatus);
writeSmsLog.Close();
}
}
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
}
}
Any ideas?
You're running a virus checker in an entirely different process. It is detecting that the file has changed and is locking it momentarily in order to check it to see if the edit you just performed to the file introduced a virus. It'll unlock it in a couple of milliseconds.
Disabling your virus checker is a bad idea. Instead, you're just going to have to live with it; write your code to be robust in a world where there are lots of processes vying for locks on files.
StreamReader smsmessage = new StreamReader(filePath);
try
{
FileInfo filenameinfo = new FileInfo(filePath);
....
smsmessage = filenameinfo.OpenText();
...
You are initializing smsmessage twice, but only disposing one of those instances. The first line constructs a StreamReader, and then you overwrite your reference to that instance with the instance created by filenameinfo.OpenText(). That leaves you with an instance that no longer has any references and hasn't been disposed. That instance might be holding a lock on the file and you have no guarantees on when it will be disposed. Even if it isn't holding a lock, you should still fix this.

Categories