I am new in windows service c#. I have a class library called JobAdminLib which has a class call ArchiveAutomationAdministrator. This class has a method called CountJobs(). I have created a windows service which would run this particular method at the scheduled interval of time. But it does not seems to work for me. Log reports are saying its running but the function that the method is supposed to perform is not working.
I have attached code for reference
public class ArchiveAutomationAdministrator
{
JobRepository repository = new JobRepository();
public IEnumerable<LiveJobs> GetCurrentlyRetentionJobs(Func<LiveJobs, bool>
criteria = null)
{
return from job in repository.GetCurrentlyRetentionJobs() select job;
}
public void countJobs()
{
var count = from job in repository.GetCurrentlyRetentionJobs() select job;
int[] JobCount = new int[count.Count()];
for (int i = 1; i <= JobCount.Length; i++)
{
string jobnumber = repository.GetCurrentlyRetentionJobs().First().JobNumber;
JobAdministrator admin = new JobAdministrator(repository);
admin.ArchiveJob(jobnumber);
}
}
}
Following is my windows service
public partial class Scheduler : ServiceBase
{
private Timer timer1 = null;
public Scheduler()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer1 = new Timer();
this.timer1.Interval = 5000;
this.timer1.Elapsed += new
System.Timers.ElapsedEventHandler(this.timer1_Tick);
timer1.Enabled = true;
Library.WriteErrorLog("test windows service started");
}
public void timer1_Tick(object sender, ElapsedEventArgs e)
{
this.task();
Library.WriteErrorLog("Job running successfully");
}
protected override void OnStop()
{
timer1.Enabled = false;
Library.WriteErrorLog("Service Stopped");
}
public void task()
{
Library.WriteErrorLog("Inside task");
ArchiveAutomationAdministrator admin = new ArchiveAutomationAdministrator();
admin.countJobs();
}
}
check if windows servers has the authority to run
if it Ok
go to windows service list
1- open run cmd
2- type services.msc
3- right click on your service name
4- in login tab click on Local System Account and Check Allow Service To Interact with desktop
That countJobs method has a crazy way of enumerating a list. Its hard to tell if this will work but try the below...
public void countJobs()
{
foreach (var job in repository.GetCurrentlyRetentionJobs())
{
Library.WriteErrorLog("Archiving job " + job.JobNumber);
string jobnumber = job.JobNumber;
JobAdministrator admin = new JobAdministrator(repository);
admin.ArchiveJob(jobnumber);
}
}
that way you will get logging inside the loop and you'll be able to tell if there is anything to actually process.
Related
I'm using the Quartz.NET library to create a job in my C# application.
I have some registers in my database, so I have a table wich contains a column called "start_date". The job runs every 50 seconds, so I compare the dates from the column "start_date" with the date of my computer, and if the dates are equal, I want to instantiate a new Windows Form with a message and a button.
At the moment, the new Windows Form is opening at the right moment, but the message is not showed and the window stops to respond.
Basically, in my code I have something like this:
FormMessage.cs
public partial class FormMessage : Form
{
public FormMessage()
{
InitializeComponent();
}
public FormMessage(double minutes)
{
InitializeComponent();
string message = string.Format("You have {0} minutes!", minutes);
lblMessage.Text = message ;
}
private void btnOK_Click(object sender, EventArgs e)
{
this.Close();
}
}
JobMessage.cs
public class JobMessage: IJob
{
List<Information> informations;
public void Execute(IJobExecutionContext context)
{
//Class with methods to get registers from database.
InformationAPI infoAPI = new InformationAPI();
informations = infoAPI.GetInformations();
foreach (Information info in informations)
{
DateTime computerDateTime = DateTime.Now;
DateTime infoDateTime = info.StartDate;
double difference;
if (DateTime.Compare(computerDateTime, infoDateTime) < 0)
{
difference = Math.Round(infoDateTime.Subtract(computerDateTime).TotalMinutes);
if (difference == 5)
{
FormMessage formMessage = new FormMessage(difference);
formMessage.Show();
}
}
}
}
}
Someone have some idea of the reason why the FormMessage window stops to respond?
Thank you for your attention!
You can try Quartz Listeners to let them open the form to show the data and keep the execution out of the job scope:
Action<IJobExecutionContext, JobExecutionException> listenerAction = (c, e) => {
var dataMap = context.GetJobDetail().GetJobDataMap();
var difference = dataMap.GetIntValue("difference");
FormMessage formMessage = new FormMessage(difference);
formMessage.Show();
}
var listener = new SyncJobListener(listenerAction);
And add the listener in to the scheduler:
scheduler.ListenerManager.AddJobListener(listener,
GroupMatcher<JobKey>.GroupEquals("GroupName"));
Using this SyncJobListener:
public class SyncJobListener : IJobListener
{
private readonly Action<IJobExecutionContext, JobExecutionException> _syncExecuted;
public string Name { get; private set; }
public SyncJobListener(
Action<IJobExecutionContext, JobExecutionException> syncExecuted
)
{
Name = Guid.NewGuid().ToString();
_syncExecuted = syncExecuted;
}
public void JobToBeExecuted(IJobExecutionContext context)
{
}
public void JobExecutionVetoed(IJobExecutionContext context)
{
}
public void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException)
{
_syncExecuted(context, jobException);
}
}
I have not tested this so if the dataMap does not have any data, you are going to need to allow the persistance:
[PersistJobDataAfterExecution]
[DisallowConcurrentExecution]
public class JobMessage: IJob {}
Below you can see a simplified version of my SignalR self hosted hub on a windows service:
public static class SubscriptionHandler
{
public static int PriceFeedMembersCount = 0;
}
public class PriceHub : Hub
{
public Task SubscribeToPriceFeed()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<PriceHub>();
if (SubscriptionHandler.PriceFeedMembersCount == 0)
{
context.Clients.All.updatePriceSubscriptionStatus(true);
}
SubscriptionHandler.PriceFeedMembersCount++;
return context.Groups.Add(Context.ConnectionId, "PriceFeed");
}
public Task UnsubscribeFromPriceFeed()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<PriceHub>();
SubscriptionHandler.PriceFeedMembersCount--;
if (SubscriptionHandler.PriceFeedMembersCount == 0)
{
context.Clients.All.updatePriceSubscriptionStatus(false);
}
return context.Groups.Remove(Context.ConnectionId, "PriceFeed");
}
public void NotifySubscribers(Price price)
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<PriceHub>();
context.Clients.Group("PriceFeed").updatePrice(price);
}
}
And I have two types of clients for that hub: One of them is web applications and the other one is windows services. Here you can see a demo implementation for my windows service as a signalr client:
public partial class WinSer45 : ServiceBase
{
private HubConnection hubConnection;
private IHubProxy priceProxy;
private Timer timer = new Timer();
private bool hasSubscribers = false;
public WinSer45()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer.Interval = 1000; // saniyede bir
timer.Elapsed += timer_Elapsed;
timer.Enabled = true;
hubConnection = new HubConnection("http://localhost:8080/signalr", useDefaultUrl: false);
priceProxy = hubConnection.CreateHubProxy("PriceHub");
hubConnection.Start().Wait();
priceProxy.On<bool>("UpdatePriceSubscriptionStatus", hasSubscribers =>
{
this.hasSubscribers = hasSubscribers;
});
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (hasSubscribers)
{
TestPrice testPrice = new TestPrice() { Id = 1, Buy = 1.2345, Sell = 9.8765, Symbol = "EURUSD" };
priceProxy.Invoke("NotifySubscribers", testPrice).Wait();
}
}
protected override void OnStop()
{
}
}
As you see I use the hasSubscribers flag to minimize the messages between hub and clients. And hasSubscribers flag is changed by SubscribeToPriceFeed and UnsubscribeFromPriceFeed methods.
If you look carefully you see the line below in SubscribeToPriceFeed:
context.Clients.All.updatePriceSubscriptionStatus(true);
I don't want to send the message to all clients but my client windows service. How can I store the connection Id of a specific client in my hub? If I can do that, I know I can send message to a specific connectionId as in the line below:
context.Clients.Client(connectionId).updatePriceSubscriptionStatus(true);
Thanks in advance,
pass source during connection
like this
hubConnection = new HubConnection("http://localhost:8080/signalr","source=windows",useDefaultUrl: false);
HUB
public override Task OnConnected()
{
var source= Context.QueryString['source'];
return base.OnConnected();
}
create a class which will hold the user with source
public class user {
public string ConnectionID {set;get;}
public string Source {set;get;}
}
declare a list in the hub
List<user> userList=new List<user>();
Then push the user during OnConnected
public override Task OnConnected()
{
var us=new user();
us.Source = Context.QueryString['source'];
us.ConnectionID=Context.ConnectionId;
userList.Add(us);
return base.OnConnected();
}
and during broadcast just filter it by source
var windowsUser=userList.Where(o=>o.Source == "windows").ToList(); // you'll get the windows user list
I have searched and searched for Windows Service information and it is mostly non-existent or outdated. Further, there is no Windows Service template in VS 2013 (that I can find).
I am making a simple performance monitor that logs to a text file the CPU and RAM. I followed a couple outdated tutorials and came up with stuff on my own.
When I try running via F5 (a coworker's suggestion) the command prompt flashes open, closes and then the program ends. I don't think the OnStart method is ever invoked.
I can get the service installed fine from the VS command prompt but when trying to start the process I get an error that it does not start in a timely manner. I have even tried enabling interaction with the desktop in the Service Manager.
I have also tried both Debug and Release builds.
I have looked at other SO questions that suggested to do all initialization in the OnStart method, which I think I do (though I may be wrong -- I am obviously still learning).
The relevant code:
namespace SystemMonitorD
{
public class SystemMonitorD : ServiceBase
{
private Timer StateTimer { get; set; }
private TimerCallback TimerDelegate { get; set; }
private SystemMonitorL SysMon { get; set; }
public SystemMonitorD()
{
ServiceName = "SystemMonitorD";
CanStop = true;
CanPauseAndContinue = true;
AutoLog = true;
}
protected override void OnStart(string[] args)
{
SysMon = new SystemMonitorL();
TimerDelegate = SysMon.Log;
StateTimer = new Timer(TimerDelegate, null, SysMon.WaitTime, SysMon.WaitTime);
}
protected override void OnStop()
{
SysMon.StatusLog("Stop");
StateTimer.Dispose();
}
protected override void OnPause()
{
SysMon.StatusLog("Pause");
StateTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
protected override void OnContinue()
{
SysMon.StatusLog("Continue");
StateTimer.Change(SysMon.WaitTime, SysMon.WaitTime);
}
public static void Main()
{
}
}
public class SystemMonitorL
{
private readonly String _fileLocation = #"C:\Users\ian.elletson\Desktop\logD.txt";
public int WaitTime { get; private set; }
private IOutput Logger { get; set; }
private List<SystemMonitor> SystemMonitors { get; set; }
public SystemMonitorL()
{
WaitTime = 1000;
Logger = new Logger(_fileLocation);
SystemMonitors = new List<SystemMonitor>
{
SystemMonitorFactory.MakeSystemMonitor("CPU"),
SystemMonitorFactory.MakeSystemMonitor("RAM")
};
Logger.WriteLine(string.Format("Polling every {0} second(s)", WaitTime / 1000));
}
public void Log(Object stateObject)
{
foreach (var monitor in SystemMonitors)
{
Logger.WriteLine(monitor.ToString());
}
}
public void StatusLog(String status)
{
String message;
switch (status)
{
case "Stop" :
message = "stopped";
break;
case "Pause" :
message = "paused";
break;
case "Continue":
message = "continued";
break;
default:
message = "ERROR";
break;
}
Logger.WriteLine(string.Format("Logging {0} at {1}", message, TimeZone.CurrentTimeZone.ToLocalTime(DateTime.Now)));
}
}
[RunInstaller(true)]
public class SystemMonitorDInstaller : Installer
{
ServiceProcessInstaller ProcessInstaller { get; set; }
ServiceInstaller ServiceInstaller { get; set; }
public SystemMonitorDInstaller()
{
ProcessInstaller = new ServiceProcessInstaller();
ServiceInstaller = new ServiceInstaller();
ProcessInstaller.Account = ServiceAccount.LocalSystem;
ServiceInstaller.StartType = ServiceStartMode.Manual;
ServiceInstaller.ServiceName = "SystemMonitorD";
Installers.Add(ServiceInstaller);
Installers.Add(ProcessInstaller);
}
}
}
One thing that makes life easier dealing with while debugging windows services is to use the Debug\Release flag for your service. To step through the logic as a non-service.
static void Main()
{
#if (!DEBUG)
//RELEASE FLAG
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new MyService() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
#else
//DEBUG
MyService service = new MyService(); //<--Put breakpoint here before you run your service
service.OnStart(null);
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#endif
}
I discovered my problem. I was missing
ServiceBase.Run(new SystemMonitorD()); in my Main() method. That solved the problem. I found this from this MSDN link.
I created two separate Windows Forms applications in C# that use MSMQ for communicating. Here's how it works, it looked simple enough though:
App1 sends a details request to App2.
App2 creates an event to open the window.
App2 opens a "details" window.
The only problem I have is that when received the message, the "details" window freezes after appearing.
As I handle MSMQ messages handling in an object that uses threads, I suspect the problem comes from there... But I have no experience in handling MSMQ messages or specific events handling between parts of an application.
Here's part of the code I use for App2:
/*Class declared in the Core namespace*/
public class TaskMessageQueueHandler
{
public TaskMessageQueueHandler()
{
this.Start();
}
private Thread m_thread;
private ManualResetEvent m_signal;
public event System.EventHandler messageReceived;
public void Start()
{
m_signal = new ManualResetEvent(false);
m_thread = new Thread(MSMQReceiveLoop);
m_thread.Start();
}
public void Stop()
{
m_signal.Set();
}
protected virtual void SendEvent(object sender, EventArgs e)
{
if (messageReceived != null)
messageReceived(this.message, e);
}
public string message;
private void MSMQReceiveLoop()
{
bool running = true;
MessageQueue queue = new MessageQueue(#".\Private$\queue1");
while (running)
{
try
{
var message = queue.Receive();
message.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" });
this.message = message.Body.ToString();
string m = this.message;
SendEvent(m, System.EventArgs.Empty);
if (m_signal.WaitOne(10))
{
running = false;
}
}
catch
{
Console.WriteLine("ERROR");
running = false;
}
}
}
}
/*Main process, in the Program namespace*/
[...]
Core.TaskMessageQueueHandler tmqh = new Core.TaskMessageQueueHandler();
EventListener el = new EventListener();
tmqh.messageReceived += new System.EventHandler(el.ShowDetails);
[...]
/* Class in the Program namespace */
class EventListener
{
public void ShowDetails(object sender, EventArgs e)
{
int numero = int.Parse(sender as string);
Details details = new Details(numero);
details.Show();
}
}
Where did I go wrong? Where did I go right?
Thanks a lot,
Stephane.P
EDIT: if the MSMQ handler is stopped with Stop() anywhere around the event sending, the details window appears then disappears right away...
EDIT2: After the workaround given by Slugart, I managed to make this work:
class EventListener
{
Main control;
public EventListener(Main main)
{
control = main;
}
public void ShowDetails(object sender, EventArgs e)
{
int numero = int.Parse(sender as string);
control.Invoke((Action)(() => ShowDetails(numero)));
}
private void ShowDetails(int numero)
{
Details details = new Details(numero);
details.Show();
}
}
Which is used like:
Core.TaskMessageQueueHandler tmqh = new Core.TaskMessageQueueHandler();
EventListener el = new EventListener(this);
tmqh.messageReceived += new System.EventHandler(el.ShowDetails);
You're creating and displaying a form Details on a thread other than the main GUI thread and not an STA thread at that.
Your EventListener should have a reference to a running form (your main form perhaps) and then call form.Invoke() on it.
class EventListener
{
Control control; // A valid running winforms control/form created on an STA thread.
public void ShowDetails(object sender, string message)
{
int numero = int.Parse(message);
control.Invoke(() => ShowDetails(numero))
}
private void ShowDetails(int numero)
{
Details details = new Details(numero);
details.Show();
}
}
Also sending your event data as the sender is not really following the Event pattern that has been put in front of you. You want to use the EventArgs parameter for this, use the EventHandler delegate (EventHandler in your case).
There is an application that collects news from rss of news agencies maybe like Google Reader!.
I want to call a method to update my links in DB in a period of the time and it continues to the Application life time.
something like a clock !!!
without any pause
I know some info about Threading
but the problem is :
Where can I call my Update method?
I have some classes that some of them derive from others and I use to layer in my Project
I call the method in Global.asax:
protected void Application_Start(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(UpdateRss));
thread.Start();
Thread.Sleep(1000);
}
public void UpdateRss()
{
while (true)
{
using (LinkService linkSrv = new LinkService())
{
linkSrv.UpdateLinksFromRSS();
}
}
}
and the definition of UpdateLinksFromRSS in LinkService is:
public void UpdateLinksFromRSS()
{
List<RssInfo> q;
using (RssService RssSrv = new RssService())
{
q = RssSrv.GetRssInfoes();
}
foreach (var item in q)
{
AddLink(item);
}
}
Honestly the problem is i have a property in BaseService that is defined like this:
public static System.Web.Caching.Cache Cache
{
get { return HttpContext.Current.Cache; }
}
when I run the project!
I got an error from this line: return HttpContext.Current.Cache;