Run a C# .NET console application as a windows service (edit)
Run a C# .NET console application as a windows service
zaagan/HybridSvx: A Hybrid of a Windows Console App And a Windows Service (github.com)
manhng83/HybridSvx: A Hybrid of a Windows Console App And a Windows Service (github.com)
.NET Core
https://blog.computedcloud.com/background-services-in-net-core-console-app/
https://docs.hangfire.io/en/latest/deployment-to-production/making-aspnet-app-always-running.html
Task Scheduler in Windows
Chú ý: Phải add Users cho full quyền truy cập vào thư mục %LocalAppData%\HybridSvx\
How To Create a Scheduled Task in Windows 10 (c-sharpcorner.com)
Windows Admin: Using Task Scheduler to Run Processes Later (howtogeek.com)
Setup A Task Scheduler To Run Application Periodically In C# (c-sharpcorner.com)
Run a C# .NET console application as a windows service
Run a C# .NET console application as a windows service
Deploy to %LocalAppData%\HybridSvx\
Table Of Contents
Background
Most of the time, when I am assigned a new task like integrating a 3rd party tool or a plugin into my .NET based application, I simply rely on trying it out first hand via a simple Console application and quickly integrating the necessary parts. And that is what probably any .NET developer would do (some might have a different approach).
But, sometimes there are requirements where the task is to create a job or a service with a repetitive flow and made runnable in a scheduled fashion. Some common scenarios are creating a job for delivering messages and updates, performing backups, doing cleanups and many more of such stuffs.
There are many options to achieve these requirements by using a third party tool. Some of those tools are: Hangfire, Quartz, Topshelf etc.
But, since I would have already tried out and tested the feature via a console application, my next step would be simply to deploy the code as a service. This generally involves, creating a new windows service application and integrating my previously tested code.
But instead of creating a new application, I do some tweaks here and there, improvise the old console application and make it behave as a windows service and vice-versa. I can then easily install this console app as a windows service into my system whenever I want.
Lets see how it is done …
The Console Application
Basically we start by creating a new console application. Here is a simple console application that simply just writes to a file.
class Program { static void Main(string[] args) { DataProcessor dataProcessor = new DataProcessor(); dataProcessor.Execute(); } }
using System; using System.IO; using System.Reflection; namespace HybridSvx { internal class DataProcessor { internal void Execute() { try { LogMessage(); } catch (Exception e) { Console.WriteLine("Exception: " + e.Message); } } /// <summary> /// Writes a simple message to a file in the application directory /// </summary> private void LogMessage() { string assemblyName = Assembly.GetCallingAssembly().GetName().Name; string fileName = string.Format(assemblyName + "-{0:yyyy-MM-dd}.log", DateTime.Now); string filePath = AppDomain.CurrentDomain.BaseDirectory + fileName; string message = "Execution completed at " + DateTime.Now.ToShortTimeString(); Console.WriteLine(message); using (StreamWriter sw = new StreamWriter(filePath, true)) { sw.WriteLine(message); sw.Close(); } } } }
Setting Up The Windows Service
The next step would be to include the necessary libraries and write some code that are required in order to create a windows service. The steps are as follows:
Step 1: Add New Item
In your Visual Studio Console Project ⇒ Right click the project ⇒ Add ⇒ New Item
Step 2 : Add a new Windows Service
Search and select Windows Service ⇒ Provide a name eg: ‘HybridSvxService.cs‘ ⇒ Click Add
This will add a new file which will contain your code that needs to be executed by the windows service.
The Windows service needs to be running continuously, else it will automatically stop after it has completed its execution. Hence, in order to make the service run continuously, we will introduce a simple timer as follows :
using System.ServiceProcess; using System.Timers; namespace HybridSvx { partial class HybridSvxService : ServiceBase { private static Timer aTimer; public HybridSvxService() { InitializeComponent(); } protected override void OnStart(string[] args) { aTimer = new Timer(10000); // 10 Seconds aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); aTimer.Enabled = true; } private static void OnTimedEvent(object source, ElapsedEventArgs e) { DataProcessor dataProcessor = new DataProcessor(); dataProcessor.Execute(); } protected override void OnStop() { aTimer.Stop(); } } }
Step 3 : Setup the Installer Class
You first need to add a reference to the System.Configuration.Install assembly via Project ⇒ Add ⇒ Reference.
Next, Add a new Class with a meaningful name eg ‘HybridSvxServiceInstaller.cs‘ and paste in the following code :
using System.ComponentModel; using System.Configuration.Install; using System.ServiceProcess; namespace HybridSvx { [RunInstaller(true)] public class HybridSvxServiceInstaller : Installer { public HybridSvxServiceInstaller() { ServiceProcessInstaller serviceProcessInstaller = new ServiceProcessInstaller(); ServiceInstaller serviceInstaller = new ServiceInstaller(); // Setup the Service Account type per your requirement serviceProcessInstaller.Account = ServiceAccount.LocalSystem; serviceProcessInstaller.Username = null; serviceProcessInstaller.Password = null; serviceInstaller.ServiceName = "HybridSvx"; serviceInstaller.DisplayName = "HybridSvx Service"; serviceInstaller.StartType = ServiceStartMode.Automatic; serviceInstaller.Description = "My custom hybrid service"; this.Installers.Add(serviceProcessInstaller); this.Installers.Add(serviceInstaller); } } }
The above code will provide your windows service with the necessary foundation for custom installation like the Service name and description, service account type etc.
Configure Self Installer
Adding a Self installer within the windows service itself, removes the hurdle of depending on a tool like InstallUtil.exe for installation. This makes the installation much easier and straight forward.
In your project, create a new class file with the name SelfInstaller.cs and paste the following code:
using System.Configuration.Install; using System.Reflection; namespace HybridSvx { public class SelfInstaller { private static readonly string _exePath = Assembly.GetExecutingAssembly().Location; public static bool InstallMe() { bool result; try { ManagedInstallerClass.InstallHelper(new string[] { SelfInstaller._exePath }); } catch { result = false; return result; } result = true; return result; } public static bool UninstallMe() { bool result; try { ManagedInstallerClass.InstallHelper(new string[] { "/u", SelfInstaller._exePath }); } catch { result = false; return result; } result = true; return result; } } }
Customize Program.cs
The final tweak would be to customize the Program.cs to support the functioning of both a console application and the windows service.
Summary : If you install the application, it will work as a windows service and if you directly run it, it will behave as a console application.
Code :
using System; using System.ServiceProcess; namespace HybridSvx { class Program { static void Main(string[] args) { if ((!Environment.UserInteractive)) { Program.RunAsAService(); } else { if (args != null && args.Length > 0) { if (args[0].Equals("-i", StringComparison.OrdinalIgnoreCase)) { SelfInstaller.InstallMe(); } else { if (args[0].Equals("-u", StringComparison.OrdinalIgnoreCase)) { SelfInstaller.UninstallMe(); } else { Console.WriteLine("Invalid argument!"); } } } else { Program.RunAsAConsole(); } } } static void RunAsAConsole() { DataProcessor dataProcessor = new DataProcessor(); dataProcessor.Execute(); } static void RunAsAService() { ServiceBase[] servicesToRun = new ServiceBase[] { new HybridSvxService() }; ServiceBase.Run(servicesToRun); } } }
Running the Program
Now, you have a working application that can either run as a console application or be installed as a windows service. Here is how you can run the application in both ways :
As a Console Application
Simply double click to run the application
As a Windows Service
- Navigate to the project output directory and locate HybridSvx.exe.
- Fire up a command prompt with an administrator privilege.
- To Install ⇒ type HybridSvx.exe -i
- To Uninstall ⇒ type HybridSvx.exe -u
- To View the service ⇒ Press Win + R ⇒ type services.msc