How to write c# service that I can also run as a winforms program?
c#, installation, service, windows-services, winforms
Solution
You basically have two choices. Either expose an API on the service which you can then call from the UI app OR enable the service to run either as a winforms app or a service.
The first option is pretty easy - use remoting or WCF to expose the API.
The second option can be achieved by moving the "guts" of your app into a separate class then create a service wrapper and a win-forms wrapper that both call into your "guts" class.
static void Main(string[] args)
{
Guts guts = new Guts();
if (runWinForms)
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
FormWrapper fw = new FormWrapper(guts);
System.Windows.Forms.Application.Run(fw);
}
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new ServiceWrapper(guts) };
ServiceBase.Run(ServicesToRun);
}
}
Problem
I have a windows service written in C# that acts as a proxy for a bunch of network devices to the back end database. For testing and also to add a simulation layer to test the back end I would like to have a GUI for the test operator to be able run the simulation. Also for a striped down version to send out as a demo. The GUI and service do not have to run at the same time. What is the best way to achieve this duel operation? Edit: Here is my solution combing stuff from this question , Am I Running as a Service and Install a .NET windows service without InstallUtil.exe using this excellent code by Marc Gravell It uses the following line to test if to run the gui or run as service. ``` if (arg_gui || Environment.UserInteractive || Debugger.IsAttached) ``` Here is the code. ``` using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using System.ComponentModel; using System.ServiceProcess; using System.Configuration.Install; using System.Diagnostics; namespace Form_Service { static class Program { /// /// The main entry point for the application. /// [STAThread] static int Main(string[] args) { bool arg_install = false; bool arg_uninstall = false; bool arg_gui = false; bool rethrow = false; try { foreach (string arg in args) { switch (arg) { case "-i": case "-install": arg_install = true; break; case "-u": case "-uninstall": arg_uninstall = true; break; case "-g": case "-gui": arg_gui = true; break; default: Console.Error.WriteLine("Argument not expected: " + arg); break; } } if (arg_uninstall) { Install(true, args); } if (arg_install) { Install(false, args); } if (!(arg_install || arg_uninstall)) { if (arg_gui || Environment.UserInteractive || Debugger.IsAttached) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } else { rethrow = true; // so that windows sees error... ServiceBase[] services = { new Service1() }; ServiceBase.Run(services); rethrow = false; } } return 0; } catch (Exception ex) { if (rethrow) throw; Console.Error.WriteLine(ex.Message); return -1; } } static void Install(bool undo, string[] args) { try { Console.WriteLine(undo ? "uninstalling" : "installing"); using (AssemblyInstaller inst = new AssemblyInstaller(typeof(Program).Assembly, args)) { IDictionary state = new Hashtable(); inst.UseNewContext = true; try { if (undo) { inst.Uninstall(state); } else { inst.Install(state); inst.Commit(state); } } catch { try { inst.Rollback(state); } catch { } throw; } } } catch (Exception ex) { Console.Error.WriteLine(ex.Message); } } } [RunInstaller(true)] public sealed class MyServiceInstallerProcess : ServiceProcessInstaller { public MyServiceInstallerProcess() { this.Account = ServiceAccount.NetworkService; } } [RunInstaller(true)] public sealed class MyServiceInstaller : ServiceInstaller { public MyServiceInstaller() { this.Description = "My Service"; this.DisplayName = "My Service"; this.ServiceName = "My Service"; this.StartType = System.ServiceProcess.ServiceStartMode.Manual; } } } ```