Calling a Console application through a Window Service - c#

I have a Window Service , that is running on my machine . I have separate console application in the same solution that is performing some functionality. In order to access the functions of the console application , I have add the *.exe file of the console application as a reference to the Window Service project.
public void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
{
// TODO: Insert monitoring activities here.
EventLog.WriteEntry("Monitoring the System", EventLogEntryType.Information);
string[] arr = new string[] { };
ConsoleApplication.Program.Main(null);
}
The Console application works perfectly file if I directly run through Visual Studio. However , If I call the Main() method from the Window Service I am getting a null pointer exception.
public static void Main(string[] args)
{
try
{
//CODE BREAKS HERE ON READING FROM CONFIG FILE
string genesis_sel= ConfigurationSettings.AppSettings["genesis_sel"].ToString();
}
catch (Exception ex)
{
//Exception code
}
}
Below is a snapshot of the Console application Project running in Visual Studio.
I am not sure what's causing the code to break while accessing the main method from a Window service.
Any suggestions?
Update: Added snapshot of the config file. I don't believe it's a rad access issue from the configuration file as it is reading correctly when I run the console application alone. There is an initialization issue when I access it through the window Service.
UPDATE Replaced the main method with a single event log , but still getting the same exception.

When you call the method it is running as part of your service, so it uses Environment and settings from your service. That means that you should have correct data in AppSettings of your service project. To bring more clarity: In this case function Main is part of your service and not a separate application root.
Otherwise you can run your console as separate process, but in that case you are loosing part of Control functions.
I would suggest, to separate common logic in a separate project/dll and call functions from it, it will be more clean and not so confusing

Related

Why the Windows Service not call the OnStart method?

I have created a windows service app which has OnStart method. The method will read a path from the app.config file, create an object, then the service write the object's overridden ToString() method to a file with a StreamWriter.
This is working when I manually start this service with "net start". So the OnStart method called, object created and written its ToString method to a file.
I set it as an automatic running service, when the Windows starts up.
My problem is, that this OnStart method is not called after the service is being started by Windows. So I think when the windows starts running the services at start up, it launches my service just don't calling the OnStart method.
Does anybody have the same issue or somebody have a solution for it?
OnStart method:
protected override void OnStart(string[] args)
{
filePath = configReader.ReadConfig("FilePath");
DateEvent dateEvent = new DateEvent(DateTime.Now, TimeLoggerCore.Events.STARTUP.ToString());
writer.WriteToFile(dateEvent, filePath, true, false);
}
Constructor:
public TimeLoggerService()
{
InitializeComponent();
configReader = new AppConfigReader();
writer = new CSVWriter();
}
Program.cs:
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new TimeLoggerService()
};
ServiceBase.Run(ServicesToRun);
}
Since your service starts when you attempt to start it from a command-line using net.exe start [ServiceName] but fails to start when windows is started, perhaps it is encountering an exception during startup.
One important thing to note when building and working with a custom Windows service is that the Windows Event Log can be very helpful in tracking down problems. When errors occur in a service, it's worthwhile to log that error in the event log.
Another helpful to debug your running service in Visual Studio is to start your service then attach the VS debugger to it.
To get some Windows event log logging into your service, I suggest modifying your service's code to log its startup. Note that what I've posted here is simplified for this forum - I typically put all logging code into a separate class. This way I can use it throughout the life of my service. One important note - be sure to set the ServiceName property of your main service class with an appropriate name - this should be done in Visual Studio at design time in the Properties window of the service designer.
private EventLog _eventLog;
/*
* Use the EventId enumeration to store event IDs that will be written with events
* to the Windows event log.
*/
enum EventId
{
ServiceStarting = 10,
ServiceStartNormal = 100,
ServiceStartFailure = 999;
}
protected override void OnStart(string[] args)
{
try
{
// remember the event log
_eventLog = EventLog;
// log start
LogMessage(_eventLog, "Service starting", EventLogEntryType.Information, EventId.ServiceStarting);
filePath = configReader.ReadConfig("FilePath");
DateEvent dateEvent = new DateEvent(DateTime.Now, TimeLoggerCore.Events.STARTUP.ToString());
writer.WriteToFile(dateEvent, filePath, true, false);
LogMessage(_eventLog, "Service started", EventLogEntryType.Information, EventId.ServiceStartNormal);
}
catch(Exception e)
{
LogMessage(_eventLog, e.ToString(), EventLogEntryType.Error, EventId.ServiceStartFailure);
}
}
private static void LogMessage(EventLog eventLog, string message, EventLogEntryType entryType, EventId eventId)
{
/*
* If the event source we want to log doesn't exist, create it.
* Note that this take admin privs, and creating the log source should be
* done during service installation. This is here as a secondary means
* to create the log in the event that it doesn't already exist.
*/
if (!EventLog.SourceExists(eventLog.Source)
{
EventLog.CreateEventSource(eventLog.Source, eventLog.Log);
}
eventLog.WriteEntry(message, entryType, (int) eventId);
}
After adding this code to your service, re-deploy it, restart your system, and then check the event log. At a minimum you should see a message logged at service start.
I had the same issue with my service, and after a lot of digging I found out that the reason why OnStop and OnStart were not called is because of the windows fast startup option.
I put logging in all the functions of the ServiceBase that can be overriden and the one that was called when I shut down my laptop was OnPowerEvent, not OnStop.
My event log
Everything was working as expected when I was restarting windows instead of shutting them down.
Hope that this will help someone.
If the event viewer shows that the service was started successfully, your OnStart has been called and has been returned from. How did you determine that is was not called? I guess by the fact that your file has not been written to. The problem is likely not that your OnStart is not called but that the WriteToFile failed and/or it was written to a different location (e.g. you use a relative path which is different or unavailable during startup). I suggest the following procedure to check this:
Use System.Diagnostics.Trace.WriteLine to output debug messages in your OnStart
Download and install/copy the DebugView application from Microsoft.
Configure DebugView to 1) Capture Global Win32, 2) Set a filter on Process Name with your application name and 3) Enable Logging at Boot Time (see the DebugView help).
Experiment a bit with all setting to make sure they work as intended.
Finally, also note this remark in the OnStart documentation:
Do not use the constructor to perform processing that should be in OnStart. Use OnStart to handle all initialization of your service. The constructor is called when the application's executable runs, not when the service runs. The executable runs before OnStart. When you continue, for example, the constructor is not called again because the SCM already holds the object in memory. If OnStop releases resources allocated in the constructor rather than in OnStart, the needed resources would not be created again the second time the service is called.
As you mentioned Windows start up, did you place your executable in the startup folder? If yes, that will not work that way. You need to install the service in the windows service manager. Microsoft Description for installing services

Performance and diagnostics with "Cannot start service... A Windows Service must first be intalled (using installutil.exe)..."

Presently, I am attempting to profile a Windows service that I am working on using the new "Performance and Diagnostics" feature in Visual Studio 2013 (see http://blogs.msdn.com/b/visualstudioalm/archive/2013/07/12/performance-and-diagnostics-hub-in-visual-studio-2013.aspx). When I attempt to profile the service, I get this error message:
Cannot start service from the command line or a debugger. A Windows Service must first be intalled (using installutil.exe) and then started with the ServerExplorer, Windows Services Administrative Tool or the NET START command.
Normally when debugging the service, it works fine because I have the following code in Program.cs:
private static MySvc _serviceInstance;
private static readonly List<ServiceBase> _servicesToRun =
new List<ServiceBase>();
static void Main(string[] args)
{
_servicesToRun.Add(_serviceInstance);
if (Environment.UserInteractive)
{
_servicesToRun.ToArray().LoadServices();
}
else
{
ServiceBase.Run(_servicesToRun.ToArray());
}
}
static Program()
{
_serviceInstance = new MySvc();
}
Also, if I attempt to attach to a running app, in the dialog that appears it doesn't display any executing processes, and when I put the name of the service in there, it does not find it. Does anyone have any suggestions? TIA.
UPDATE: This is what I get when I attempt to attach to a process. Why doesn't the "Performance and Diagnostics" see any processes running on my computer? Why would it only connect to Windows Store apps instead of all exes? Please see this image:
The way I resolved the problem was the copy all the source code and make minor modifications to get everything to run in a Console application, then chose Debug->Performance and Diagnostics and ran the Console application using "Change Target" -> "Launch and executable file (.exe)"

.NET Web Service logging with Log4Net not working from separate client

In a basic .NET web service (asmx) which I am building locally, I'm trying to log using Log4NET to a file. This works fine if I fire up debugging mode in Visual Studio and test the service using the wsdl/test pages provided. But if I try using a separate client (I made a C# console app to call the service), I see the expected response, but get NO logging.
(The separate client code is listed below. I had to import a reference to the built DLL of the web service.)
I'm a bit new to this, but I speculate the issue is because outside of the VS server or IIS (which I am stuck without), Global.asax is not used (which contains my initialization command for logging). But I need to test from an external client. How can I get Global.asax to initialize from the client application perspective, or how can I avoid needing to? Does this sound like it would solve my logging issue?
Global.asax in my web service project contains this statement:
protected void Application_Start(object sender, EventArgs e)
{
log4net.Config.XmlConfigurator.Configure();
}
And my separate client (console) application looks like this:
static void Main(string[] args)
{
MyWebService proxy = new MyWebService();
MyWebService.Request request = new MyWebService.Request();
request.Type = "Test";
MyWebService.Response response = proxy.GetResponse(request);
Console.WriteLine("RESPONSE CODE: " + response.StatusCode);
Console.WriteLine("RESPONSE MSG: " + response.StatusMessage);
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
}
I'm also unclear how I would change this console app to reference the Visual Studio server instance (ex: localhost:1583/MyWebService.asmx?op=GetResponse) instead of creating a proxy instance of the web service. I think that would also do the trick, since the Visual Studio server utilizes Global.asax, no?
The simpler way
would be to move the log4net initialization inside static void Main:
static void Main(string[] args)
{
log4net.Config.XmlConfigurator.Configure();
}
Don't forget to include log4net configuration in app.config file of your new host.
The better way
would be to move your service to separate project (it is already so, right?) so it is complied into it's own assembly. Than apply
[assembly: log4net.Config.XmlConfigurator(Watch=true)]
attribute to the assemlyInfo.cs. Refer to log4net configuration manual for details (search for word assembly on the page). This way is better, because you'll not have to add that
log4net.Config.XmlConfigurator.Configure();
into the initialization of all host environments you have.
But make sure you have your log4net configuration in app.config, web.config or whatever configuration file you have.

Keep C# application running

I'm building a Windows Service that uses FileSystemWatcher, and runs in the background.
I don't want to keep on uninstalling and installing the service every time I want to debug, so would like to do most of my development in a normal program before moving it into a service. But I'm quite new to this, and when I run it, it just runs through the block and exits.
What would be a good way to keep the program running?
http://einaregilsson.com/run-windows-service-as-a-console-program/
I've used this before to debug my service as a Console application based on whether its running in an interactive user environment.
public partial class DemoService : ServiceBase
{
static void Main(string[] args)
{
DemoService service = new DemoService();
if (Environment.UserInteractive)
{
service.OnStart(args);
Console.WriteLine("Press any key to stop program");
Console.Read();
service.OnStop();
}
else
{
ServiceBase.Run(service);
}
}
while (true)
{
// Execute your program's functionality here.
}
I wrote a 7 part series a while ago titled: Building a Windows Service. It covers all the intricacies of building services, making them friendly to debug, and self-installing.
The basic feature set I was looking for was as follows:
Building a service that can also be used from the console
Proper event logging of service startup/shutdown and other activities
Allowing multiple instances by using command-line arguments
Self installation of service and event log
Proper event logging of service exceptions and errors
Controlling of start-up, shutdown and restart options
Handling custom service commands, power, and session events
Customizing service security and access control
The final result was a Visual Studio project template that creates a working service, complete with all of the above, in a single step. It's been a great time saver for me.
see Building a Windows Service – Part 7: Finishing touches for a link to the project template and install instructions.
Here’s documentation from MSDN # http://msdn.microsoft.com/en-us/library/7a50syb3(v=vs.80).aspx?ppud=4 . I have tried it before and it works under .NET Framework 3.x. I could not find my descriptive notes on it, at the moment.
Use the pragma #If DEBUG for debugging purposes like console outputs. Another is using the Debug object.
If you have any trouble with this, say so. I may be able to find my notes or make a Windows Service app myself, just to see if the steps on MSDN still work.

Windows Services for Console application in C#.net

I have made one console application for email notification in c#.
Can i convert this console application in to window service?
Thanks.
In visual studio, create a "Windows Service" project instead of a "Console Application". Look in the code that gets generated for you. There will be an OnStart() and OnStop() method. Those are the methods that will be called when your service is started and stopped. Put your code in those methods and you will have a Windows Service.
Contrary to some of the suggestions made by other answers, you probably can't do what you want using a Windows Service. It can't display the "notification" you expect because services can't display any kind of user interface.
The appropriate solution is to create a regular application that runs in the background without showing any windows. You can't do this with a console application (well, you can, but let's not overcomplicate things) because each time you run it, the console window will be displayed. But if you create a standard Windows application (either a Windows Forms or WPF application) then just don't create a window, everything will work out just fine.
You'll probably want to create and place an icon into the taskbar's notification area, which will handle displaying the notification upon the arrival of email. If you're creating a WinForms application, this can be done easily by using the NotifyIcon component.
Something like (warning, written without the aid of a compiler!):
static class Program
{
[STAThread]
static void Main()
{
// Standard infrastructure code
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Create a context menu and add item(s) to it
ContextMenu mnu = new ContextMenu();
MenuItem mnuExit = new MenuItem("E&xit");
mnu.MenuItems.Add(mnuExit);
mnuExit.Click += mnuExit_Click);
// Create the NotifyIcon
NotifyIcon ni = new NotifyIcon();
ni.Icon = new Icon(GetType(), "icon.ico");
ni.Text = "Email Notifier";
ni.ContextMenu = mnu;
ni.Visible = true;
// Run the application
Application.Run();
// Before exiting, remove the NotifyIcon from the taskbar
ni.Visible = false;
}
private static void mnuExit_Click(object Sender, EventArgs e)
{
Application.Exit();
}
}
When I go about this, I write the application in a class that does not consider its self a console application. By that I mean I dont write to the Console. I use log4net to write everything to... just log to Info. Use the console app to call the application class and in the app.config you can have an appender for console logging... so you get the console output. In the windows service this will just write to a file or not at all for the Info level logging. Its important to note the differences between a console app and a service... a service is not interactive and you can not input anything, so you app must consider this. For the windows service use the same class, but use the windows service project to start it.
ApplicationLogic: Has all the logic to run the application. Can take the arguments to make the app run the way it needs to, but does not interact with the console (can, but it would be bad design). Writes everything to logging (log4net maybe).
ConsoleApp: Is a wrapper around ApplicationLogic that can prompt the user for what ever it needs, can prompt for input and send it to ApplicationLogic. Has a log4net console appender if you need to see the output from ApplicationLogic.
WindowsService: Is a wrapper around ApplicationLogic. Has predetermined logic to keep it looping and running the Application logic. Logs to a file, no console output.

Categories