What exactly is involved when you schedule a task or chron job? I have an application that my manager wants to run daily at a certain time, the application relies on user input but its designed to save user preferences and load those in as well, as soon as the user clicks a button it will perform the task. How do I go about forcing this to happen daily, assuming all data entered is valid. This is in MVC / ASP.NET so it would be on windows. But if someone can explain how it works with cron jobs in linux I can figure it out from there as well. Do i need to write a script that calls my mvc code? or any suggestions?
This is a sample windows service that run every day on given set of time, i think this will help you.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
namespace DemoWinService
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
System.Timers.Timer _timer;
List<TimeSpan> timeToRun = new List<TimeSpan>();
public void OnStart(string[] args)
{
string timeToRunStr = "19:01;19:02;19:00"; //Time interval on which task will run
var timeStrArray = timeToRunStr.Split(';');
CultureInfo provider = CultureInfo.InvariantCulture;
foreach (var strTime in timeStrArray)
{
timeToRun.Add(TimeSpan.ParseExact(strTime, "g", provider));
}
_timer = new System.Timers.Timer(60 * 100 * 1000);
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
ResetTimer();
}
void ResetTimer()
{
TimeSpan currentTime = DateTime.Now.TimeOfDay;
TimeSpan? nextRunTime = null;
foreach (TimeSpan runTime in timeToRun)
{
if (currentTime < runTime)
{
nextRunTime = runTime;
break;
}
}
if (!nextRunTime.HasValue)
{
nextRunTime = timeToRun[0].Add(new TimeSpan(24, 0, 0));
}
_timer.Interval = (nextRunTime.Value - currentTime).TotalMilliseconds;
_timer.Enabled = true;
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
_timer.Enabled = false;
Console.WriteLine("Hello at " + DateTime.Now.ToString()); //You can perform your task here
ResetTimer();
}
}
}
Related
I am new to C# and the code below is a mashup of a Microsoft tutorial and a simple program that I created (which works on its own), so I apologize now.
The service part appears to be working. Windows is running the service and I am getting event log messages saying that the service is running.
What I am not seeing is that the server is connected to the Brainbox device (192.168.10.174) I can see this by looking at the webpage of the Brainbox device. I am guessing that I am missing something really obvious. As the Brainbox_Data program runs perfectly well on its own in a console app.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Configuration;
using Brainboxes.IO;
namespace MyNewService
{
public partial class MyNewService : ServiceBase
{
public MyNewService()
{
InitializeComponent();
eventLog1 = new System.Diagnostics.EventLog();
if (!System.Diagnostics.EventLog.SourceExists("MySource"))
{
System.Diagnostics.EventLog.CreateEventSource(
"MySource", "MyNewLog");
}
eventLog1.Source = "MySource";
eventLog1.Log = "MyNewLog";
}
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("In OnStart. NEW");
BrainboxData();
Timer timer = new Timer();
timer.Interval = 60000; // 60 seconds
timer.Elapsed += new ElapsedEventHandler(this.OnTimer);
timer.Start();
}
protected override void OnStop()
{
eventLog1.WriteEntry("In OnStop.");
}
private int eventId = 1;
public void OnTimer(object sender, ElapsedEventArgs args)
{
// TODO: Insert monitoring activities here.
eventLog1.WriteEntry("Monitoring the System", EventLogEntryType.Information, eventId++);
}
static void BrainboxData()
{
string provider = ConfigurationManager.AppSettings
["provider"];
string connectionString = ConfigurationManager.AppSettings
["connectionString"];
DbProviderFactory factory = DbProviderFactories.GetFactory(provider);
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
connection.Open();
DbCommand command = factory.CreateCommand();
command.Connection = connection;
using (EDDevice ed = EDDevice.Create("192.168.10.174"))
{
ed.Label = "TrumpfE";
ed.Inputs[0].IOLineRisingEdge += (line, device, changeType) =>
{
command.CommandText = "INSERT INTO dbo.Brainbox_Data (datetimestamp, iolintimee, value, IPAddress) VALUES (GETDATE(),'" + line + "' , 1, '192.168.10.174')";
command.ExecuteNonQuery();
};
ed.Inputs[1].IOLineRisingEdge += (line, device, changeType) =>
{
command.CommandText = "INSERT INTO dbo.Brainbox_Data (datetimestamp, iolintimee, value, IPAddress) VALUES (GETDATE(),'" + line + "' , 0, '192.168.10.174')";
command.ExecuteNonQuery();
};
}
}
}
}
}
Any help would be greatly accepted.
I need to monitor a list of hosts continuously. After N seconds, i need to check the list again. So, I tried to use the async ping inside a Windows Service.
I tried to follow tips from other posts related to the topic, but always my service stops shortly after starting it.
There are a problem with await in "OnElapsedTime" function.
Any one have an idea what is wrong? Bellow my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Net.NetworkInformation;
namespace PingAsyncService
{
public partial class HyBrazil_Ping : ServiceBase
{
Timer timer = new Timer();
List<string> IPList = new List<string>(); //List of IPs
public HyBrazil_Ping()
{
IPList.Add("192.168.0.1");
IPList.Add("192.168.0.254");
InitializeComponent();
}
protected override void OnStart(string[] args)
{
WriteToFile("Service is started at " + DateTime.Now);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 5000; //number in miliseconds
timer.Enabled = true;
}
protected override void OnStop()
{
WriteToFile("Service is stopped at " + DateTime.Now);
}
private async void OnElapsedTime(object source, ElapsedEventArgs e)
{
//WriteToFile("Service is recall at " + DateTime.Now);
var ResultList = await PingAsync();
foreach(PingReply reply in ResultList)
{
WriteToFile(reply.Address.ToString() + ";" + reply.Status.ToString());
}
}
private async Task<PingReply> PingAndProcessAsync(Ping pingSender, string ip)
{
var result = await pingSender.SendPingAsync(ip, 2000);
return result;
}
private async Task<List<PingReply>> PingAsync()
{
Ping pingSender = new Ping();
var tasks = IPList.Select(ip => PingAndProcessAsync(pingSender, ip));
var results = await Task.WhenAll(tasks);
return results.ToList();
}
public void WriteToFile(string Message)
{
string path = AppDomain.CurrentDomain.BaseDirectory + "\\Logs";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string filepath = AppDomain.CurrentDomain.BaseDirectory + "\\Logs\\ServiceLog_" + DateTime.Now.Date.ToShortDateString().Replace('/', '_') + ".txt";
if (!File.Exists(filepath))
{
// Create a file to write to.
using (StreamWriter sw = File.CreateText(filepath))
{
sw.WriteLine(Message);
}
}
else
{
using (StreamWriter sw = File.AppendText(filepath))
{
sw.WriteLine(Message);
}
}
}
}
}
Thanks a lot!
In one of the comments you mentioned the error message as
"An asynchronous call is already in progress. It must be completed or canceled before you can call this method."
Chances are, the Ping object does not let simultaneous asynchronous calls.
Using a new Ping object everytime, on each call, might help as below.
private async Task<List<PingReply>> PingAsync()
{
// Ping pingSender = new Ping();
var tasks = IPList.Select(ip =>
{
using (var p= new Ping())
{
return PingAndProcessAsync(p, ip);
}
});
var results = await Task.WhenAll(tasks);
return results.ToList();
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Timer time = new Timer();
time.Elapsed += new ElapsedEventHandler(action);
time.Interval = 5000;
time.Enabled = true;
time.Start();
}
static void action(Object sender, ElapsedEventArgs args)
{
Console.WriteLine("haha\n");
}
}
}
This piece of code doesnt have any output. Could anyone tell me what the problem is? Thank you very much. I followed exact code on MSDN.. http://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.71).aspx
Timer goes out of scope immediately and thus is never called. The program exits before it has a chance to fire the action.
You can make your main method sleep by adding this after time.start():
TimeSpan interval = new TimeSpan(0, 0, 2);
Thread.Sleep(interval);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
class Program
{
static void Main(string[] args)
{
while(true)
{
Timer time = new Timer();
time.Elapsed += new ElapsedEventHandler(action);
time.Interval = 100;
time.Enabled = true;
time.Start();
string line = Console.ReadLine(); // Get string from user
if (line == "exit") // Check for exit condition
{
break;
}
}
Console.WriteLine("End of Program\n");
}
static void action(Object sender, ElapsedEventArgs args)
{
Console.WriteLine("haha\n");
}
}
NEED A SOLUTION
Background agent is working only once. After There is no occurrence of a background agent. It works at the first time and it works perfectly as soon as the page opens. however, after that it takes forever and ever to do that again. sometimes page close and open doesn't work. that would probably because of not removing the agenet
My background Agent Code:
#define DEBUG_AGENT
using System;
using System.Windows;
using Microsoft.Phone.Scheduler;
using Microsoft.Phone.Shell;
using Microsoft.Phone.Info;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using System.Threading;
using Microsoft.Xna.Framework.Media;
using System.Windows.Input;
using Microsoft.Devices;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows.Media.Imaging;
using System.Net.Sockets;
using System.Text;
using System.Net;
namespace ScheduledTaskAgent1
{
public class ScheduledAgent : ScheduledTaskAgent
{
private static volatile bool _classInitialized;
//private DispatcherTimer s;
Socket _socket = null;
ManualResetEvent _clientDone = new ManualResetEvent(false);
const int TIMEOUT_MILLISECONDS = 5000;
const int MAX_BUFFER_SIZE = 2048;
double lat = 7.16126666666667;
static ScheduledAgent()
{
// Subscribe to the managed exception handler
Deployment.Current.Dispatcher.BeginInvoke(delegate
{
Application.Current.UnhandledException += UnhandledException;
});
}
/// Code to execute on Unhandled Exceptions
private static void UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
System.Diagnostics.Debugger.Break();
}
}
protected override void OnInvoke(ScheduledTask task)
{
//TODO: Add code to perform your task in background
string toastTitle = "";
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
lat += 0.001;
string snmea = DD2NMEA(lat, 80.44506);
string dates = DateTime.UtcNow.ToString("ddMMyy");
string UTCTime = DateTime.UtcNow.ToString("hhmmss") + ".000";
string s1 = Checksum("$FRCMD,869444005499999,_SendMessage,,0809.67600,N,8050.70360,E,1.0,1.08,3.0,141013,055642.000,1,Button1=1,Button2=0,Switch1=1,Switch2=0,Analog1=4.00,Analog2=5.00,SosButton=0,BatteryLow=0,Text1=Text1,Text2=Text2*00");
string s = Send("$FRCMD,869444005499999,_SendMessage,," + snmea + ",1.0,1.08,3.0," + dates + "," + UTCTime + ",1,Button1=1,Button2=0,Switch1=1,Switch2=0,Analog1=4.00,Analog2=5.00,SosButton=0,BatteryLow=0,Text1=Text1,Text2=Text2*00");
startToastTask(task, toastTitle);
}
private void startToastTask(ScheduledTask task, string toastTitle)
{
#if DEBUG_AGENT
ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(10));
#endif
// Call NotifyComplete to let the system know the agent is done working.
NotifyComplete();
}
}
}
My Page from app which calls the agent
PeriodicTask toastPeriodicTask;
const string toastTaskName = "ToastPeriodicAgent";
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
toastPeriodicTask = ScheduledActionService.Find(toastTaskName) as PeriodicTask;
StartPeriodicAgent(toastTaskName);
}
private void StartPeriodicAgent(string taskName)
{
toastPeriodicTask = ScheduledActionService.Find(taskName) as PeriodicTask;
if (toastPeriodicTask != null)
{
RemoveAgent(taskName);
}
toastPeriodicTask = new PeriodicTask(taskName);
toastPeriodicTask.Description = periodicTaskDesc;
try
{
ScheduledActionService.Add(toastPeriodicTask);
#if(DEBUG_AGENT)
ScheduledActionService.LaunchForTest(taskName, TimeSpan.FromSeconds(2));
#endif
}
catch (InvalidOperationException exception)
{
if (exception.Message.Contains("BNS Error: The action is disabled"))
{
MessageBox.Show("Background agents for this application have been disabled by the user.");
}
else if (exception.Message.Contains("BNS Error: The maximum number of ScheduledActions of this type have already been added."))
{
MessageBox.Show("BNS Error: The maximum number of ScheduledActions of this type have already been added.");
}
else
{
MessageBox.Show("An InvalidOperationException occurred.");
}
}
catch (SchedulerServiceException)
{
}
}
Ensure that your project has DEBUG_AGENT defined. This is a setting within your project properties. To set this flag, follow these steps
Right click the project within VS and select Properties
Select the Build tab
Add DEBUG_AGENT to the "Conditional compilation symbols" field.
If that is set, I've found it's best to give at least 30 seconds in the LaunchForTest. Sometimes it doesn't quite schedule it when you tell it to.
hi friends i was trying to make my service act dynamically... i have set time for my service about for 2 min ,if suppose it was doin huge amount of work means it will exceeds that 2 min time limit then we need to check the service condition if work is pending means we need to run that instance until upto finish
so that i have tried this below code on googling ... i m having method were i need to cooperate in below service, can any one help me
public static void StartService(string serviceName, int timeoutMilliseconds)
{
ServiceController service = new ServiceController(serviceName);
try
{
TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
}
catch
{
// ...
}
}
as of now i m doing this below logic
protected override void OnStart(string[] args)
{
// my service name
Workjob("FTSCSVGenerator");
// ad 1: handle Elapsed event and CsvGenFromDatabase is method which i have to executed
timerjob.Elapsed += new ElapsedEventHandler(CsvGenFromDatabase);
// ad 2: set interval to 1 minute (= 60,000 milliseconds)
timerjob.Interval = Convert.ToDouble(DueTime);
// ////ad 3: enabling the timer
timerjob.Enabled = true;
eventLog1.WriteEntry("my service started");
}
protected override void OnStop()
{
eventLog1.WriteEntry("my service stopped");
}
private void Workjob(string servicename )
{
ServiceController servicecsv = new ServiceController(servicename);
if ((servicecsv.Status.Equals(ServiceControllerStatus.Stopped)) || (servicecsv.Status.Equals(ServiceControllerStatus.StopPending)))
{
// Start the service if the current status is stopped.
servicecsv.Start( );
}
else
{
// Stop the service if its status is not set to "Stopped".
servicecsv.Stop();
}
}
I have built services that operate in a similar manner before, my advice would be to NOT start and stop the service from external code. Instead, apply the Timer methodology within the service itself, which should always be running. On TimerElapsed, do work and then return to an idle state. Thus alleviating the need to start and stop.
Further, I would protect the "stop" of a service to not allow the stop if the service is "working"
Sample Code
Note: I employ a process I call "zeroing" with my timer. Zeroing, in my context, is the process of getting the events to fire on zero seconds of every minute. To do that, I first set the time to fire every second and I check to see if the seconds part of the current time is zero, once that occurs I switch the timer elapse to every minute. I do this to give myself some sanity while testing.
Also, my scheduling is configurable so every minute when it "ticks" i check my config to see if the process "should" execute. I do so with the following Xml Schema:
<?xml version="1.0" encoding="utf-8"?>
<ScheduleDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ScheduleInterval>1</ScheduleInterval>
<ScheduleUnits>min</ScheduleUnits>
<DailyStartTime>1753-01-01T08:00:00</DailyStartTime>
<ExcludedWeekDays>
<string>Sunday</string>
<string>Saturday</string>
</ExcludedWeekDays>
<ExcludedDates>
<string>12/25</string>
<string>02/02</string>
<string>03/17</string>
</ExcludedDates>
<DailyRunTimes>
<!-- code ommitted for size // -->
</DailyRunTimes>
</ScheduleDefinition>
Finally, this code sample is for a DataSync Services, so any references to "DataMigrationService" or "DataMigrationManager" are my own custom classes and are used as an abstraction to give me an object to control within the service.
... here's the code:
using System;
using System.Diagnostics;
using System.Reflection;
using System.ServiceProcess;
using System.Threading;
using System.Xml;
using System.Xml.Serialization;
using DataMigration.Configuration;
using DataMigration.ObjectModel;
namespace DataSyncService
{
public partial class DataSyncService : ServiceBase
{
#region Private Members
private System.Timers.Timer _timer = null;
private SimpleScheduleManager.ScheduleDefinition _definition = null;
private DataMigrationManager _manager = new DataMigrationManager();
#endregion
#region Constructor(s)
public DataSyncService()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(AssemblyResolver.Resolve);
InitializeComponent();
}
~DataSyncService()
{
_manager = null;
_definition = null;
_timer = null;
}
#endregion
#region Public Method(s)
protected override void OnStart(string[] args)
{
Assembly assembly = Assembly.GetExecutingAssembly();
_manager.ProcessMonitor.Logger.Debug("Assembly Version: ", assembly.GetName().FullName);
assembly = null;
SetScheduleFromConfigurationFile();
_timer = new System.Timers.Timer(1000);
_timer.AutoReset = true;
_timer.Enabled = true;
_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_ZeroingProcess);
_timer.Start();
}
protected override void OnStop()
{
_timer.Stop();
_timer.Enabled = false;
_timer = null;
// block if the Process is active!
if (_manager.State == DataMigrationState.Processing)
{
// I invented my own CancellableAsyncResult (back in the day), now you can use CancellationTokenSource
CancellableAsyncResult result = _manager.RequestCancel() as CancellableAsyncResult;
while (!result.IsCompleted) { Thread.Sleep(ServiceConstants.ThreadSleepCount); }
try
{
result.EndInvoke();
}
catch (Exception ex)
{
ProcessMonitorMessage message = ProcessMonitorMessage.GetErrorOccurredInstance();
message.EventType = ProcessMonitorEventType.ProcessAlert;
message.Severity = ProcessMessageSeverity.ErrorStop;
message.SubjectLine = "Error while stopping service. ";
message.EventDescription = ex.Message;
_manager.ProcessMonitor.ReportError(message);
}
}
}
#endregion
#region Private Method(s)
private bool MigrationIsScheduledToRunNow()
{
DateTime now = DateTime.Now;
foreach (string dowString in _definition.ExcludedWeekDays)
{
if (now.DayOfWeek.ToString().Equals(dowString))
{
Trace.WriteLine("Today is " + dowString, "Excluded by Schedule definition");
return false;
}
}
foreach (string datePart in _definition.ExcludedDates)
{
string dateString = datePart + "/2008"; // 2008 is a leap year so it "allows" all 366 possible dates.
DateTime excludedDate = Convert.ToDateTime(dateString);
if (excludedDate.Day.Equals(now.Day) && excludedDate.Month.Equals(now.Month))
{
Trace.WriteLine("Today is " + datePart, "Excluded by Schedule definition");
return false;
}
}
foreach (DateTime runTime in _definition.DailyRunTimes)
{
if (runTime.Hour.Equals(now.Hour) && runTime.Minute.Equals(now.Minute))
{
Trace.WriteLine("Confirmed Scheduled RunTime: " + runTime.TimeOfDay.ToString(), "Included by Schedule definition");
return true;
}
}
return false;
}
/// <summary>
/// Load Scheduling Configuration Options from the Xml Config file.
/// </summary>
private void SetScheduleFromConfigurationFile()
{
string basePath = AppDomain.CurrentDomain.BaseDirectory;
if (basePath.EndsWith("\\")) { basePath = basePath.Substring(0, basePath.Length - 1); }
string path = string.Format("{0}\\Scheduling\\scheduledefinition.xml", basePath);
_manager.ProcessMonitor.Logger.Debug("Configuration File Path", path);
XmlSerializer serializer = new XmlSerializer(typeof(SimpleScheduleManager.ScheduleDefinition));
XmlTextReader reader = new XmlTextReader(path);
reader.WhitespaceHandling = WhitespaceHandling.None;
_definition = serializer.Deserialize(reader) as SimpleScheduleManager.ScheduleDefinition;
reader = null;
serializer = null;
}
#endregion
#region Timer Events
private void _timer_ZeroingProcess(object sender, System.Timers.ElapsedEventArgs e)
{
if (DateTime.Now.Second.Equals(0))
{
_timer.Interval = 60000;
_timer.Elapsed -= new System.Timers.ElapsedEventHandler(_timer_ZeroingProcess);
_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
_timer_Elapsed(sender, e);
}
}
private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
_manager.ProcessMonitor.Logger.Info("Timer Elapsed", DateTime.Now.ToString());
if (MigrationIsScheduledToRunNow())
{
switch (_manager.State)
{
case DataMigrationState.Idle:
_manager.ProcessMonitor.Logger.Info("DataMigration Manager is idle. Begin Processing.");
_manager.BeginMigration();
break;
case DataMigrationState.Failed:
_manager.ProcessMonitor.Logger.Warn("Data Migration is in failed state, Email <NotificationRecipients> alerting them.");
break;
default:
_manager.ProcessMonitor.Logger.Warn("DataMigration Manager is still processing. Skipping this iteration.");
break;
}
}
}
#endregion
}
}