将控制台应用程序转换为服务?

问题描述:

我正在寻找不同的方法来将我们长期使用的控制台应用程序转换为Windows服务的长处/弱点。我们为ActiveMQ使用了一个名为java service wrapper的东西,我相信有人告诉我你可以用它来包装任何东西。这并不是说你应该用它来包装任何东西;我们遇到了有关此设置的问题。将控制台应用程序转换为服务?

控制台应用程序是一个.NET控制台应用程序,默认情况下会将很多信息记录到控制台,尽管这是可配置的。

任何reccomendations?

我们应该在Visual Studio中重建它作为服务吗?使用包装?哪一个?

我会试图创建一个空的windows服务项目,并且只是抓住处理服务的位;它不是很多 - 几个参考文献和Main中的一些代码。实际上,你可以有你的现有的控制台工作作为服务作为控制台 - 无论是通过检查参数传递给Main和使用(例如)“-console”开关,或者我相信你可以检查Environment.UserInteractive

如果它处于“控制台”模式,请像现在这样运行代码;如果它处于服务模式,请运行您从模板项目中抓取的代码。

有关信息,您可以具有相同的exe作为服务的安装程序/ uninstaller!我使用“-install”/“-uninstall”开关执行此操作。例如,see here

的几点思考:

Create windows service with VS 2005

install .Net Service

我一些几年前写了一个基于Perl可执行文件集(theads)等,这似乎已经到了你类似的要求.. 。

有些东西要记住:

  • 确实有debuggin开关(你应该有一个当出现真的错了)
  • 输出到控制台和文件(尝试例如log4net的)
  • 建立与未来的正则表达式解析你的日志记
  • 如果有一些inderdependant过程中,学习如何杀死他们,停止和重新启动他们
  • 如果有一些inderdependant进程试图向他们传达

这里是一个小控制台例如输出到数据库,文件,控制台log4net的

using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Text; 
    using log4net; 
    using log4net.Config; 
    using NUnit.Framework; 

    namespace ExampleConsoleApplication 
    { 
     [TestFixture] 
     class TestClass 
     { 

     //private static readonly ILog logger = 
     //  LogManager.GetLogger (typeof (TestClass)); 

     private static readonly log4net.ILog logger = log4net.LogManager.GetLogger (System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 

      static void Main (string[] args) 
      { 

       Console.WriteLine (" START "); 
       #region LoggerUsage 
       DOMConfigurator.Configure(); //tis configures the logger 
       logger.Debug ("Here is a debug log."); 
       logger.Info ("... and an Info log."); 
       logger.Warn ("... and a warning."); 
       logger.Error ("... and an error."); 
       logger.Fatal ("... and a fatal error."); 

       #endregion LoggerUsage 
       TestClass objTestClass = new TestClass(); 
       objTestClass.TestMethodNameOK(); 
       objTestClass.TestMethodNameNOK(); 

       Console.WriteLine (" END HIT A KEY TO EXIT "); 
       Console.ReadLine(); 
       } //eof method 

      [SetUp] 
      protected void SetUp() 
      { 
       //Add Here the Initialization of the objects 
      } 
      [Test (Description = "Add here the description of this test method ")] 
      protected void TestMethodNameOK() 
      { 
       //build ok use case scenario here - e.g. no exception should be raced ' 
       //Vegetable newCarrot = pool.GetItemByPropertyValue<Vegetable> ("WriongByPurpose", "Orange"); 
       //Assert.IsInstanceOfType (typeof (Vegetable), newCarrot); 
       //Assert.AreSame (newCarrot, carrot); 
       //logger.Info (" I got the newCarrot which is " + newCarrot.Color); 

      } //eof method 

      [Test (Description = "Add here the description of this test method ")] 
      protected void TestMethodNameNOK()   //e.g. the one that should raze Exception 
      { 
       //build ok use case scenario here - e.g. no exception should be raced ' 
       //Vegetable newCarrot = pool.GetItemByPropertyValue<Vegetable> ("WriongByPurpose", "Orange"); 
       //Assert.IsInstanceOfType (typeof (Vegetable), newCarrot); 
       //Assert.AreSame (newCarrot, carrot); 
       //logger.Info (" I got the newCarrot which is " + newCarrot.Color); 

      } //eof method 

     } //eof class 

    } //eof namespace 





    #region TheAppConfig 
// <?xml version="1.0" encoding="utf-8" ?> 
//<configuration> 
// <configSections> 
// <section name="log4net" 
//   type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> 
// </configSections> 

// <log4net> 
// <appender name="LogFileAppender" type="log4net.Appender.FileAppender"> 
//  <param name="File" value="Program.log" /> 
//  <param name="AppendToFile" value="true" /> 
//  <layout type="log4net.Layout.PatternLayout"> 
//  <!--<param name="Header" value="======================================" /> 
//  <param name="Footer" value="======================================" />--> 
//  <param name="ConversionPattern" value="%d [%t] %-5p - %m%n" /> 
//  </layout> 
// </appender> 

// <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender"> 
//  <mapping> 
//  <level value="ERROR" /> 
//  <foreColor value="Red" /> 
//  </mapping> 
//  <mapping> 
//  <level value="DEBUG" /> 
//  <foreColor value="HighIntensity" /> 
//  </mapping> 
//  <mapping> 
//  <level value="INFO" /> 
//  <foreColor value="Green" /> 
//  </mapping> 
//  <mapping> 
//  <level value="WARN" /> 
//  <foreColor value="Yellow" /> 
//  </mapping> 
//  <mapping> 
//  <level value="FATAL" /> 
//  <foreColor value="White" /> 
//  <backColor value="Red" /> 
//  </mapping> 

//  <layout type="log4net.Layout.PatternLayout"> 
//  <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> 
//  </layout> 
// </appender> 


// <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender"> 
//  <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.2.10.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> 
//  <connectionString value="data source=ysg;initial catalog=DBGA_DEV;integrated security=true;persist security info=True;" /> 
//  <commandText value="INSERT INTO [DBGA_DEV].[ga].[tb_Data_Log] ([Date],[Thread],[Level],[Logger],[Message]) VALUES (@log_date, @thread, @log_level, @logger, @message)" /> 

//  <parameter> 
//  <parameterName value="@log_date" /> 
//  <dbType value="DateTime" /> 
//  <layout type="log4net.Layout.PatternLayout" value="%date{yyyy'.'MM'.'dd HH':'mm':'ss'.'fff}" /> 
//  </parameter> 
//  <parameter> 
//  <parameterName value="@thread" /> 
//  <dbType value="String" /> 
//  <size value="255" /> 
//  <layout type="log4net.Layout.PatternLayout" value="%thread" /> 
//  </parameter> 
//  <parameter> 
//  <parameterName value="@domainName" /> 
//  <dbType value="String" /> 
//  <size value="255" /> 
//  <layout type="log4net.Layout.PatternLayout" value="%user" /> 
//  </parameter> 
//  <parameter> 
//  <parameterName value="@log_level" /> 
//  <dbType value="String" /> 
//  <size value="50" /> 
//  <layout type="log4net.Layout.PatternLayout" value="%level" /> 
//  </parameter> 
//  <parameter> 
//  <parameterName value="@logger" /> 
//  <dbType value="String" /> 
//  <size value="255" /> 
//  <layout type="log4net.Layout.PatternLayout" value="%logger" /> 
//  </parameter> 
//  <parameter> 
//  <parameterName value="@message" /> 
//  <dbType value="String" /> 
//  <size value="4000" /> 
//  <layout type="log4net.Layout.PatternLayout" value="%message" /> 
//  </parameter> 
// </appender> 
// <root> 
//  <level value="ALL" /> 
//  <appender-ref ref="LogFileAppender" /> 
//  <appender-ref ref="AdoNetAppender" /> 
//  <appender-ref ref="ColoredConsoleAppender" /> 
// </root> 
// </log4net> 
//</configuration> 
    #endregion TheAppconfig 

    //this is the xml added replace here your log4net and Nunit paths 
    //<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL"> 
    // <SpecificVersion>False</SpecificVersion> 
    // <HintPath>..\..\..\Log4Net\log4net-1.2.10\bin\net\2.0\release\log4net.dll</HintPath> 
    //</Reference> 
    //<Reference Include="nunit.framework, Version=2.4.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" /> 

Vici WinService将把控制台应用程序变成自行安装的Windows服务。它是开源的,你可以下载源代码。即使你不想使用图书馆,你仍然可以从中得到一些想法。

您的长期使用场景是什么?一个Windows服务可能就足够了......但Windows Server 2008/IIS7提供了一些有趣的新方法,通过Windows激活服务托管和激活“服务”。 Windows服务将始终运行,并可能需要一些特殊的编码。使用WAS,您可以将主机写为普通的WCF服务,并在请求进入时按需激活,并在不使用时停用。其他选项也存在...比如MSMQ托管和实例化等。

我遇到了同样的问题,最后我写了自己的包装,它只适用于最简单的情况,但它确实有它的特权。你可以在这里找到工具:http://runasservice.com。其中一些额外的优点包括,您可以将应用程序编写为易于在IDE中测试和运行的控制台应用程序。设置服务涉及一个简单的命令,因此您不必编辑您的应用程序。此外,您可以使用不同的名称多次安装该服务,如果要使用不同的参数运行每个名称,则可能需要执行该操作。

就像我说的,虽然它只涵盖了最简单的场景,应用程序本来就是服务。这是他们不断运行。我确信有很多其他的服务可以给你更多的选择。

就我个人而言,我认为转换控制台应用程序并不是特别困难,但它可能是一个麻烦的测试。最后,尽管它取决于你想要多少控制。如果这对您的公司来说真的是一项非常重要的服务,那么我会转换它。