将ac#命令行应用程序转换为Windows服务

我找到了很多部分答案,但没有什么真的足够。

案例:App是一个工作的命令行应用程序,没有用户交互,除了能够在输入停止时接收按键,这已经以一种方式写入,即使不运行时也禁用环境.UserInteractive ==真正。

我正在使用Visual Studio 2010。

问题是我需要将此应用程序转换为Windows服务。 是“只是”将新的类文件作为服务,并让它在现有应用程序上调用我的启动和停止方法?

如何安装程序(VS’默认的msi安装程序),现有的安装程序项目是否可以“升级”以处理服务安装?

我之前搞砸了这个,最后得到了一个拒绝安装的安装程序,因为它一直检测到服务已经安装,停止安装过程然后立即回滚所有内容。 它检测到的服务是刚安装的服务。

要将控制台应用程序作为Windows服务或控制台应用程序运行,请编写单个控制台应用程序并使用命令行参数来确定是应该直接运行还是启动该服务。 包含安装程序/卸载程序,以使用正确的命令行参数安装为Windows服务。

这是我们使用的基类,它提供了这个function。

using System; using System.Collections; using System.Configuration.Install; using System.Diagnostics; using System.IO; using System.Reflection; using System.ServiceProcess; using System.Windows.Forms; using Microsoft.Win32; namespace Console40 { public abstract class AbstractService : ServiceBase { public static AbstractService Current { get; private set; } protected virtual string HelpTextPattern { get { #region Help Text return @" USAGE {0} [command] WHERE [command] is one of /console - run as a console application, for debugging /service - run as a windows service /install - install as a windows service /uninstall - uninstall windows service "; #endregion } } public abstract string DisplayName { get; } public ServiceExecutionMode ServiceExecutionMode { get; private set; } protected abstract Guid UninstallGuid { get; } protected virtual string UninstallRegKeyPath { get { return @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"; } } protected AbstractService(string serviceName) { ServiceName = serviceName; if (Current != null) { throw new InvalidOperationException(String.Format( "Service {0} is instantiating but service {1} is already instantiated as current. References to AbstractService.Current will only point to the first service.", GetType().FullName, Current.GetType().FullName)); } Current = this; } public void Run(string[] args) { Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory; if (args.Length == 0 && Debugger.IsAttached) { args = new[] { "/console" }; } if (args.Length == 0) { Console.WriteLine(HelpTextPattern, Path.GetFileName(GetType().Assembly.CodeBase)); } else { switch (args[0].ToLower()) { case "/service": ServiceExecutionMode = ServiceExecutionMode.Service; Run(new[] { this }); break; case "/console": ServiceExecutionMode = ServiceExecutionMode.Console; Console.WriteLine("Starting Service..."); OnStart(new string[0]); OnStartCommandLine(); OnStop(); break; case "/install": ServiceExecutionMode = ServiceExecutionMode.Install; InstallService(); break; case "/uninstall": ServiceExecutionMode = ServiceExecutionMode.Uninstall; UninstallService(); break; case "/uninstallprompt": ServiceExecutionMode = ServiceExecutionMode.Uninstall; if (ConfirmUninstall()) { UninstallService(); InformUninstalled(); } break; default: if (!OnCustomCommandLine(args)) { Console.WriteLine(HelpTextPattern, Path.GetFileName(GetType().Assembly.CodeBase)); } break; } } } protected override void OnStart(string[] args) { OnStartImpl(args); AppDomain.CurrentDomain.UnhandledException += OnCurrentDomainUnhandledException; } protected virtual void OnStartCommandLine() { Console.WriteLine("Service is running... Hit ENTER to break."); Console.ReadLine(); } protected abstract void OnStartImpl(string[] args); void OnCurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) { // do something useful here, log it.. } protected override void OnShutdown() { Stop(); } protected override void OnStop() { OnStopImpl(); } protected abstract void OnStopImpl(); protected virtual bool OnCustomCommandLine(string[] args) { // for extension return false; } private void InstallService() { GetInstaller(".InstallLog").Install(new Hashtable()); InstallServiceCommandLine(); CreateUninstaller(); } private void InstallServiceCommandLine() { string keyParent = @"SYSTEM\CurrentControlSet\Services\" + ServiceName; const string VALUE_NAME = "ImagePath"; try { using (RegistryKey key = Registry.LocalMachine.OpenSubKey(keyParent, true)) { if (key == null) { throw new InvalidOperationException("Service not found in registry."); } var origPath = key.GetValue(VALUE_NAME) as string; if (origPath == null) { throw new Exception("HKLM\\" + keyParent + "\\" + VALUE_NAME + " does not exist but was expected."); } key.SetValue(VALUE_NAME, origPath.Replace("\"\"", "\"") + " /service"); } } catch (Exception ex) { throw new Exception( "Error updating service command line after installation. Unable to write to HKLM\\" + keyParent, ex); } } private void CreateUninstaller() { using (RegistryKey parent = Registry.LocalMachine.OpenSubKey(UninstallRegKeyPath, true)) { if (parent == null) { throw new Exception(String.Format("Uninstall registry key '{0}' not found.", UninstallRegKeyPath)); } try { RegistryKey key = null; try { string guidText = UninstallGuid.ToString("B"); key = parent.OpenSubKey(guidText, true) ?? parent.CreateSubKey(guidText); if (key == null) { throw new Exception(String.Format("Unable to create uninstaller '{0}\\{1}'", UninstallRegKeyPath, guidText)); } Assembly asm = GetType().Assembly; Version v = asm.GetName().Version; string exe = "\"" + asm.CodeBase.Substring(8).Replace("/", "\\\\") + "\""; key.SetValue("DisplayName", DisplayName); key.SetValue("ApplicationVersion", v.ToString()); key.SetValue("Publisher", "B-Line Medical"); key.SetValue("DisplayIcon", exe); key.SetValue("DisplayVersion", v.ToString(2)); key.SetValue("URLInfoAbout", "http://www.blinemedical.com"); key.SetValue("Contact", "support@blinemedical.com"); key.SetValue("InstallDate", DateTime.Now.ToString("yyyyMMdd")); key.SetValue("UninstallString", exe + " /uninstallprompt"); } finally { if (key != null) { key.Close(); } } } catch (Exception ex) { throw new Exception( "An error occurred writing uninstall information to the registry. The service is fully installed but can only be uninstalled manually through the command line.", ex); } } } private bool ConfirmUninstall() { string title = "Uninstall " + DisplayName; string text = "Are you sure you want to remove " + DisplayName + " from your computer?"; return DialogResult.Yes == MessageBox.Show(text, title, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); } private void InformUninstalled() { string title = "Uninstall " + DisplayName; string text = DisplayName + " has been uninstalled."; MessageBox.Show(text, title, MessageBoxButtons.OK, MessageBoxIcon.Information); } private void UninstallService() { GetInstaller(".UninstallLog").Uninstall(null); RemoveUninstaller(); } private TransactedInstaller GetInstaller(string logExtension) { var ti = new TransactedInstaller(); ti.Installers.Add(new ServiceProcessInstaller { Account = ServiceAccount.LocalSystem }); ti.Installers.Add(new ServiceInstaller { DisplayName = DisplayName, ServiceName = ServiceName, StartType = ServiceStartMode.Automatic }); string basePath = Assembly.GetEntryAssembly().Location; String path = String.Format("/assemblypath=\"{0}\"", basePath); ti.Context = new InstallContext(Path.ChangeExtension(basePath, logExtension), new[] { path }); return ti; } private void RemoveUninstaller() { using (RegistryKey key = Registry.LocalMachine.OpenSubKey(UninstallRegKeyPath, true)) { if (key == null) { return; } try { string guidText = UninstallGuid.ToString("B"); RegistryKey child = key.OpenSubKey(guidText); if (child != null) { child.Close(); key.DeleteSubKey(guidText); } } catch (Exception ex) { throw new Exception( "An error occurred removing uninstall information from the registry. The service was uninstalled will still show up in the add/remove program list. To remove it manually delete the entry HKLM\\" + UninstallRegKeyPath + "\\" + UninstallGuid, ex); } } } } public enum ServiceExecutionMode { Unknown, Service, Console, Install, Uninstall, Custom } } 

保持C#应用程序运行

 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); } } 

检查上面的链接。 我提供了一些代码以及描述使用控制台进行双重控制的链接作为控制台和服务。 我将使用控制台项目并在作为服务运行之前检查UserInteractive。 这样您就可以调试它就像是一个控制台,但是将它作为服务安装在生产服务器上。

关于安装,我没有从.msi安装的经验,但是我们使用批处理脚本来安装服务(使用sc.exe),然后只需更新文件即可更新代码。

最好的办法是将新项目作为Windows服务启动。 在这个新项目中,您将找到Service1.cs,这是将从start运行的文件。 以下代码将在文件中:

 namespace WindowsService1 { public partial class Service1 : ServiceBase { public Service1() { InitializeComponent(); } protected override void OnStart(string[] args) { } protected override void OnStop() { } } } 

从这里弄清楚要做什么并不难。 只需将您的类添加到项目中,并确保在OnStart()函数中复制主代码。 当然,您可能需要稍微编辑代码以确保其中没有读取行。

现在您必须创建并安装。 您可以在此处找到如何执行此操作: http : //msdn.microsoft.com/en-us/library/zt39148a%28v=vs.100%29.aspx

我希望这有帮助:D

亲切的问候

罗哈斯