I have created a Windows Service in Visual Studio 2012 that should run 2 services when executed.
static void Main()
{
// creates an array to hold all services that will run in this application
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
// services added here
new Service1(),
new Service2()
};
ServiceBase.Run(ServicesToRun);
}
I have already read various possible answers in various forums, etc. but I have not found a working solution for me.
I have added a Service Installer for each service and I also have one project installer.
When I install the service through the Developer Command Prompt I can see the Windows Service in the Computer Manager but I can also see Service1 and Service2.
When I run the Windows Service, it will only run Service1 and not Service2. However, both Service1 and Service2 can be started individually.
Anyone any suggestions? Been stuck on this for some time now!
EDIT
In the Service1 and Service2 OnStart() I have the following code:
CheckService();
try
{
motorTimer = new Timer();
// timer sets intervals for when quotes are checked after start up
motorTimer .Elapsed += new ElapsedEventHandler(QuoteTimerElapsed);
motorTimer .Interval = Convert.ToDouble(ConfigurationSettings.AppSettings["ServiceCheckInterval"]);
motorTimer .Start();
}
catch (Exception ex)
{
MotorServiceCheckLogDetail(ex.ToString());
OnStop();
}
As an answer to my problem I took the following approach. It might not be perfect and I slightly changed my approach but it was a way I was able to get my Service to work how I wanted.
Instead of creating 1 service with multiple 'services' being run within it, I created one service that instantiated various classes. I was able to include the functionality required in these classes and call the class when required.
As I say, this isn't the perfect answer to my original problem but it was a work around I discovered and as a result it may help others if they read this SO post.
I have already heard/read some problem that people are facing when they are using timer in windows service. Instead of using timer I'd recommend in OnStart method start a task that uses loop with integrated delay. something like following:
Task _task;
CancellationTokenSource _terminator;
protected override void OnStart()
{
_terminator = new CancellationTokenSource();
_task = Task.Factory.StartNew(TaskBody, _terminator.Token);
}
private void TaskBody(object arg)
{
var ct = arg as CancellationToken;
if (ct == null) throw new ArgumentException();
while(!ct.sCancellationRequested)
{
YourOnTimerMethod();
ct.WaitHandle.WaitOne(interval)
}
}
public override void OnClose()
{
_terminator.Cancel();
_task.Wait();
}
I had the same problem. Seems that the OnStart method is called only on the first Service passed to ServiceBase.Run.
Related
I am trying to learn about writing Windows Services, and I'm using C# to do it. I found a tutorial on Microsoft's site here:
https://msdn.microsoft.com/en-us/library/zt39148a%28v=vs.110%29.aspx
It shows you how to build a simple Windows Service that logs some messages to the Event Log. I more or less followed the instructions, and everything worked fine. But it instructs you to use Designers and mysterious drag-and-drop components, and to rely upon a bunch of IDE-autogenerated code. So, for the purposes of trying to actually understand what I was doing, I tried to make a (basically) equivalent Windows Service just from raw classes that I manually typed in, rather than from Designers and such.
It compiled fine, and installutil.exe successfully installed it as a service. But when I try to start the service, I get the following error:
Windows could not start the Bob Manual Service Display Name service on Local Computer.
Error 1053: The service did not respond to the start or control request in a timely fashion.
Eventually I figured out that Malwarebytes (my antivirus program) is quarantining my project's compiled exe whenever I try to start the service. It says it's infected with "Backdoor.Bot". I have tried both debug and release builds, and it quarantines both.
Obviously I could just whitelist the exe or temporarily disable Malwarebytes or whatever, but I am completely new to this Windows Service stuff, and I am concerned that I am perhaps unknowingly doing something flagrantly wrong or dangerous in my code.
I am attaching my code, which is intended to be based on the Microsoft sample code but very simple - three small classes, a Main, a System.ServiceProcess.ServiceBase, and a System.Configuration.Install.Installer.
Is there any reason why Malwarebytes should be quarantining this?
One thing that I imagine might look questionable is that I'm setting the account to ServiceAccount.LocalSystem, which that Microsoft tutorial says has "broad permissions" and so "might increase your risk of attacks from malicious software", but:
(1) That's what it is in Microsoft's sample code (and as I understand it, it's required for the EventLog stuff);
(2) I actually accidentally had it as LocalService at first, and the same error was happening.
namespace Project1
{
using System.ServiceProcess;
static class BobMain
{
static void Main()
{
ServiceBase[] ServicesToRun = { new BobManualService() };
ServiceBase.Run(ServicesToRun);
}
}
}
namespace Project1
{
using System.Diagnostics;
using System.ServiceProcess;
public class BobManualService : ServiceBase
{
private EventLog eventLog;
public BobManualService()
{
this.eventLog = new EventLog();
if (!EventLog.SourceExists("BobSource"))
{
EventLog.CreateEventSource("BobSource", "BobLog");
}
this.eventLog.WriteEntry("Super duper constructor!");
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
}
namespace Project1
{
using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;
[RunInstaller(true)]
public class BobInstaller : Installer
{
private ServiceProcessInstaller serviceProcessInstaller;
private ServiceInstaller serviceInstaller;
public BobInstaller()
{
this.serviceProcessInstaller = new ServiceProcessInstaller();
this.serviceInstaller = new ServiceInstaller();
this.serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
this.serviceProcessInstaller.Password = null;
this.serviceProcessInstaller.Username = null;
this.serviceProcessInstaller.AfterInstall +=
this.serviceProcessInstaller_AfterInstall;
this.serviceInstaller.Description =
"Bob Manual Service Description";
this.serviceInstaller.DisplayName =
"Bob Manual Service Display Name";
this.serviceInstaller.ServiceName = "BobManualService";
this.serviceInstaller.StartType = ServiceStartMode.Automatic;
this.Installers.AddRange(new Installer[]
{
this.serviceProcessInstaller,
this.serviceInstaller
});
}
private void serviceProcessInstaller_AfterInstall(
object sender,
InstallEventArgs e)
{
}
}
}
Looking at your code, in the OnStart(string[] args) method, there is no process being started that runs on a separate thread for a prolonged time. So your service starts and exists immediately. Please take a closer look at "To define what occurs when the service starts" in the tutorial that you've referenced.
Basically just add the code that sets up the timer to the OnStart(string[] args) method and your service should stay alive.
As a First step I created Windows Service project configured it properly and
On second Step I have added TopShelf Version 3.1.135.0 in my project If I run my service through (F5 Run) then it is loading Top-shelf Console and service is completed successfully.
However When I am running it to install and Start it from command prompt I am having below TimeOut Error.
Topshelf.Hosts.StartHost Error: 0 : The service failed to start., System.Service
Process.TimeoutException: Time out has expired and the operation has not been co
mpleted.
public class AppService
{
LoggingService loggingService = new LoggingService(typeof(AppService).Name);
public void Start()
{
loggingService.Info("SampleService is Started");
ExtractProcess.Start();
TransformProcess.Start();
}
public void Stop()
{
loggingService.Info("SampleService is Stopped");
}
}
-- Updated Code to fix this issue
public void Start()
{
loggingService.Info("MPS.GOA.ETLService is Started");
ThreadStart myThreadDelegate = new ThreadStart(StartService);
Thread myThread = new Thread(myThreadDelegate);
myThread.Start();
}
private void StartService()
{
timer.Elapsed += new System.Timers.ElapsedEventHandler(OnElapsedTime);
timer.Interval = 60000 * ServiceIntervalInMinutes; //1 minute 60000 milliseconds
timer.Enabled = true;
Process();
}
private void Process()
{
ExtractProcess.Start();
TransformProcess.Start();
}
Any Suggestions?
This error is happening because you are running the extract and process methods in the Start method of the service. This is OK in Visual Studio, but when you install the service and start it, the Service Control Manager waits for the Start method to return, and if it does not do so within a certain time (30 seconds by default) then it will return this error.
You have several options, all of which will allow the Start method to return immediately:
Invoke the extract and transform methods on a separate thread
Invoke the extract and transform methods asynchronously
Use a timer to start the extract and transform process
In case you (like me) is struggling to get the service to start - and all you've found so far is references to starting work in a separate thread (and you already did) this might be the solution right here..
My problem was that I had an external JSON config file being read from the project's directory path. What I needed was to get the assembly path, so that when the .NET application is published and installed with Topshelf - it looks for the config file at the right place.
string assemblyPath = Path.GetDirectoryName(typeof(MyConfigManagerClass).Assembly.Location);
var builder = new ConfigurationBuilder()
.SetBasePath(assemblyPath)
.AddJsonFile("config.json", optional: false);
myConfigurationObject = builder.Build();
Topshelf gave an error saying the service couldn't be started, but now I finally know why.
In my case it was neither of the above solutions that solved it, but actual permissions within the topshelf service, that required access to a file that resided in an external server.
TopShelf program running on test server
Log file located on Production server
Test server does not have access to external servers, for security
reasons.
So I changed the program to refer everything internally inside it's own server, and it worked fine.
I have a C# application that uses a Windows service that is not always on and I want to be able to send an email notification when the service starts and when it shuts down. I have the email script written, but I cannot seem to figure out how to detect the service status changes.
I have been reading up on the ServiceController class and I think that the WaitForStatus() method might be what I need, but I haven't been able to find an example with it being used on a service that is not yet started. EDIT: Due to the fact that the WaitForStatus() method busy-waits and I need to be executing the rest of the program run by the service while listening for the service to start/stop, I don't think that this is the method for me, unless someone has a solution that uses this method combined with multithreading and is clean and efficient.
More:
the service will not be started by the application - the application user will be starting that directly from the Services window in the Administrative Tools.
the service used is not a default Windows service - it is a custom service designed for use with this application
Thanks for your help!
P.S. please note that I'm fairly new to C# and am learning as I go here.
UPDATE:
I have managed to get the alert email to send each time the service starts: As I continued to read through the code that I have (which I, unfortunately, cannot post here), I noticed that the class used to create the service was extending the ServiceBase class and that someone made a custom OnStart() method to override the default one. I added the necessary method calls to the new OnStart() method and it successfully sent the notifications.
I attempted to do the same thing for the OnStop() method, but that did not work out so well for me - before I continue, I would like to add that I have been programming in Java for several years, and I am very familiar with Java design patterns.
What I attempted to do, which would have worked in Java, was override the ServiceBase class's OnStop() method with one that calls the email notification, cast MyService to be of type ServiceBase and then re-call the ServiceBase class's Stop() method (NOTE: OnStop() is a protected method so it could not be called directly - the Stop() method calls OnStop() and then continues with the necessary code to stop the service). I thought that casting to type ServiceBase would force the default OnStop() method to be called, instead of my custom one.
As you may imagine, I ended up with just under 10,000 emails successfully sent to my inbox before I managed to force my computer into a hard shutdown.
What I need now is a way to either use my overridden OnStop() method and then have it call the default method, or another solution to this problem. Any and all help is much appreciated. Thanks so much.
FOR THOSE OF YOU WITH MULTITHREADING SOLUTIONS:
protected override void OnStart(string[] args) {
string subject = "Notice: Service Started";
string body = "This message is to notify you that the service " +
"has been started. This message was generated automatically.";
EmailNotification em = new EmailNotification(subject, body);
em.SendNotification();
...INITIALIZE LISTENER FOR SERVICE STOPPING HERE...
...custom stuff to be run on start...
}
Also, remember that the class that this method is called in, let's call it Service, extends the ServiceBase class.
UPDATE TWO:
In regards the suggestion that I use NotifyServerStatusChange I have learned that it is not permitted for the solution to use system functions, due to various reasons. To clarify, only solutions that are purely within the scope of C# and .NET are viable. Thanks, again, for your help!
Here is the solution and why I could not find it before: As I said earlier, my class extended the ServiceBase class. In my first update, I posted that I attempted to solve this in the same way I would have solved it with Java: through casting. However, in C# casting apparently doesn't let you call the base method if you overrode it in the derived class. One of the things that I did not know when I first posted this question and this update (and clearly one of the things that no one thought of) was that C# includes the base constructor that can be used to call methods of the base class from a derived class. As the base constructor can be used for any class in C# it does not appear in the ServiceBase Class documentation.
Once I learned this, I was able to take my original solution and modify it to use the base class:
protected override void OnStop() {
string subject = "Notice: Service Stopped";
string body = "This message is to notify you that the service has " +
"been stopped. This message was generated automatically.";
EmailNotification em = new EmailNotification(subject, body);
em.SendNotification();
base.OnStop();
}
I figured this out when I was playing around with the code in Visual Studio and noticed base in my IntelliSense. I clicked to go to its definition and it sent me to ServiceBase (where it was obviously not defined). After noticing that base was not defined in my code and that it was an instance of the ServiceBase class I realized that it must have been some sort of constructor. After a quick Google search, I found what I was looking for. Way to go IntelliSense!
Thank you everyone for all your help!
If you want a .NET solution with no win32 api then check out my solution below. I'm inheriting from the ServiceController class and using the WaitForStatus() inside of a Task to make it non-blocking then raising events when the status changes. Perhaps it needs more testing but works for me:
CLASS DEFINITION
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.ServiceProcess; // not referenced by default
public class ExtendedServiceController: ServiceController
{
public event EventHandler<ServiceStatusEventArgs> StatusChanged;
private Dictionary<ServiceControllerStatus, Task> _tasks = new Dictionary<ServiceControllerStatus, Task>();
new public ServiceControllerStatus Status
{
get
{
base.Refresh();
return base.Status;
}
}
public ExtendedServiceController(string ServiceName): base(ServiceName)
{
foreach (ServiceControllerStatus status in Enum.GetValues(typeof(ServiceControllerStatus)))
{
_tasks.Add(status, null);
}
StartListening();
}
private void StartListening()
{
foreach (ServiceControllerStatus status in Enum.GetValues(typeof(ServiceControllerStatus)))
{
if (this.Status != status && (_tasks[status] == null || _tasks[status].IsCompleted))
{
_tasks[status] = Task.Run(() =>
{
try
{
base.WaitForStatus(status);
OnStatusChanged(new ServiceStatusEventArgs(status));
StartListening();
}
catch
{
// You can either raise another event here with the exception or ignore it since it most likely means the service was uninstalled/lost communication
}
});
}
}
}
protected virtual void OnStatusChanged(ServiceStatusEventArgs e)
{
EventHandler<ServiceStatusEventArgs> handler = StatusChanged;
handler?.Invoke(this, e);
}
}
public class ServiceStatusEventArgs : EventArgs
{
public ServiceControllerStatus Status { get; private set; }
public ServiceStatusEventArgs(ServiceControllerStatus Status)
{
this.Status = Status;
}
}
USAGE
static void Main(string[] args)
{
ExtendedServiceController xServiceController = new ExtendedServiceController("myService");
xServiceController.StatusChanged += xServiceController_StatusChanged;
Console.Read();
// Added bonus since the class inherits from ServiceController, you can use it to control the service as well.
}
// This event handler will catch service status changes externally as well
private static void xServiceController_StatusChanged(object sender, ServiceStatusEventArgs e)
{
Console.WriteLine("Status Changed: " + e.Status);
}
The ServiceController class has a WaitForStatus method. Internally it does polling, though.
If you can't PInvoke NotifyServiceStatusChange, then you'll have to poll the service. For example:
ServiceController sc = new ServiceController("Some Service");
Console.WriteLine("Status = " + sc.Status);
You can use wmi to monitor for events: technet.microsoft.com/en-us/library/ff730927.aspx
Be very carefull with the use of NotifyServiceStatusChange(), because it is only supported on Windows Vista/Windows 2008 (and above). If you target any platforms below, you can't use that API. (There are still lots of XP/Windows 2000-2003 systems out there.)
To make it even worse, polling will not be always reliable in case of service restarts, because if you are polling a service on a very fast system (SSD-drives or pre-buffered I/O on virtual machines), the service might restart between two polls.
First time posting long time reader.
I built a working filewatcher inside of a windows forms application functioning 100% properly before moving it to a windows Service and am now recieving two seperate issues. This file watcher reads a flatfile for line updates(lastwrite), deletes/recreates file(streamwriter), and finally parses through a strongly typed data set and then uploads to an SQL server.
(This is my first Windows Service)
Questions:
1. Does the double event trigger in filewatcher effect the service differently then a forms application?
2. Does anyone have an answer about why the thread will break if the class I am calling has no issue?
3. Are there any known issues with Windows Authentication through a windows service?
4. Does anyone have any strong debug methods for windows services?
Here is my code from the windows Service, thanks in advance and my apologies if there is a silly mistake in the code, again first time making a windows service.
FileMonitor m_FileMonitor;
public WindowsService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
Thread myThread = new Thread(DoTheWork);
myThread.Start();
}
catch
{
}
}
void DoTheWork()
{
m_FileMonitor = new FileMonitor(Properties.Settings.Default.PathToFileToWatch, Properties.Settings.Default.PathToErrorLog);
}
protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop your service.
}
For debugging, make sure your project type is Windows Application, and then use this:
[DllImport("kernel32")]
static extern bool AllocConsole();
private static void Main(string[] args)
{
var service = new MyService();
var controller = ServiceController.GetServices().FirstOrDefault(c => c.ServiceName == service.ServiceName);
if (null != controller && controller.Status == ServiceControllerStatus.StartPending)
{
ServiceBase.Run(service);
}
else
{
if (AllocConsole())
{
service.OnStart(args);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
service.OnStop();
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
If the code is running because the Windows Service was started, it will run as a Windows Service. Otherwise it will allocate a console, run the service, then wait for a key press before exiting the service. You could build on this for testing pause and continue.
For debugging:
You have to use the ServiceBase.Run method in Main() to execute as a windows service, but you can make a switch in the main method to run the same application as a normal console application (e.g. --standalone). I'm using this on all my services to make them easy to debug.
Regarding the other problems:
I'm not completely sure which problems you encounter and what you mean by "class break" and "double event trigger".
Windows services run under a special service account, which might or might not have permissions to watch the directory you are interested in. You can change the service account or give it permission for the directory if you need to.
Links:
Here is a link to a codeproject article who seems to have implemented a file watcher windows service. Maybe it helps:
http://www.codeproject.com/Articles/18521/How-to-implement-a-simple-filewatcher-Windows-serv
What's the best way in C# to set up a utility app that can be run from the command line and produce some output (or write to a file), but that could be run as a Windows service as well to do its job in the background (e.g. monitoring a directory, or whatever).
I would like to write the code once and be able to either call it interactively from PowerShell or some other CLI, but at the same time also find a way to install the same EXE file as a Windows service and have it run unattended.
Can I do this? And if so: how can I do this?
Yes you can.
One way to do it would be to use a command line param, say "/console", to tell the console version apart from the run as a service version:
create a Windows Console App and then
in the Program.cs, more precisely in the Main function you can test for the presence of the "/console" param
if the "/console" is there, start the program normally
if the param is not there, invoke your Service class from a ServiceBase
// Class that represents the Service version of your app
public class serviceSample : ServiceBase
{
protected override void OnStart(string[] args)
{
// Run the service version here
// NOTE: If you're task is long running as is with most
// services you should be invoking it on Worker Thread
// !!! don't take too long in this function !!!
base.OnStart(args);
}
protected override void OnStop()
{
// stop service code goes here
base.OnStop();
}
}
...
Then in Program.cs:
static class Program
{
// The main entry point for the application.
static void Main(string[] args)
{
ServiceBase[] ServicesToRun;
if ((args.Length > 0) && (args[0] == "/console"))
{
// Run the console version here
}
else
{
ServicesToRun = new ServiceBase[] { new serviceSample () };
ServiceBase.Run(ServicesToRun);
}
}
}
The best way to accomplish this from a design standpoint is to implement all your functionality in a library project and build separate wrapper projects around it to execute the way you want (ie a windows service, a command line program, an asp.net web service, a wcf service etc.)
Yes it can be done.
Your startup class must extend ServiceBase.
You could use your static void Main(string[] args) startup method to parse a command line switch to run in console mode.
Something like:
static void Main(string[] args)
{
if ( args == "blah")
{
MyService();
}
else
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new MyService() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
A Windows Service is quite different from a normal Windows program; you're better off not trying to do two things at once.
Have you considered making it a scheduled task instead?
windows service vs scheduled task