2009-05-31 8 views
8

Sto cercando modi diversi con punti di forza/debolezza per convertire un'applicazione console che utilizziamo a lungo termine in un servizio Windows. Usiamo qualcosa chiamato java service wrapper per ActiveMQ, e credo che le persone mi abbiano detto che puoi avvolgere qualsiasi cosa con esso. Questo non significa che dovresti avvolgere qualcosa con esso; abbiamo avuto i nostri problemi con questa configurazione.Conversione di un'applicazione console in un servizio?

L'app per console è un'applicazione di console .NET che per impostazione predefinita registra molte informazioni sulla console, sebbene sia configurabile.

Eventuali raccomandazioni?

Dovremmo semplicemente ricostruirlo in Visual Studio come servizio? Usa un wrapper? Quale?

risposta

11

Sarei tentato di creare un progetto di servizio di Windows vuoto, e basta prendere i bit che si occupano di un servizio; non è molto - alcuni riferimenti e parte del codice in Main. In realtà, la console esistente può funzionare come come servizio come un servizio e come console: controllando gli argomenti su Main e utilizzando (ad esempio) un commutatore "-console" o credo sia possibile controllare Environment.UserInteractive.

Se è in modalità "console", eseguire il codice come si fa ora; se è in modalità di servizio, esegui il codice che hai preso dal progetto del modello.

Per informazioni, è possibile anche avere lo stesso lavoro exe come il programma di installazione/disinstallazione per il servizio! Lo faccio con le opzioni "-install"/"-uninstall". Per un esempio, see here.

0

Alcuni pensieri:

Create windows service with VS 2005

install .Net Service

ho scritto qualche paio di anni fa una serie basata Perl di eseguibili (theads), ecc, che sembra avere requisiti simili ai tuoi .. .

Alcune cose da tenere a mente:

    .210
  • hanno interruttore debuggin (si dovrebbe avere uno quando qualcosa va veramente sbagliato)
  • uscita sia per console e file (provare log4net per esempio)
  • costruire la tua registrazione con il futuro l'analisi regex in mente
  • se ci sono alcuni processi inderdependant, imparare a ucciderli, arrestare e riavviare loro
  • se ci sono alcuni processi inderdependant cercano di comunicare loro

Ecco un piccolo esempio della console per l'output al db, file e la console con 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" /> 
2

Vici WinService trasforma un'app console in un servizio Windows autoinstallante. È open source e puoi scaricare il codice sorgente. Anche se non vuoi usare la libreria, puoi comunque ottenere qualche idea.

0

Qual è lo scenario di utilizzo a lungo termine? Un servizio Windows potrebbe essere sufficiente ... ma Windows Server 2008/IIS7 offre alcuni interessanti nuovi modi di hosting e attivazione di "servizi" tramite i servizi di attivazione di Windows. Un servizio Windows sarà sempre in esecuzione e potrebbe richiedere alcuni codici speciali. Con WAS, è possibile scrivere l'host come normale servizio WCF e attivarlo su richiesta quando le richieste arrivano e disattivato quando non viene utilizzato. Esistono anche altre opzioni ... come l'hosting MSMQ e l'istanza, ecc.

0

Mi sono imbattuto in questo stesso problema, ho finito per scrivere il mio wrapper, è solo buono per le situazioni più semplici ma ha i suoi vantaggi. È possibile trovare lo strumento qui: http://runasservice.com. Alcuni dei vantaggi includono il fatto che è possibile codificare la propria applicazione come un'applicazione di console che è facile da testare ed eseguire nell'IDE. L'impostazione di un servizio implica un semplice comando in modo da non dover modificare l'applicazione. Inoltre, puoi installare il servizio più volte con nomi diversi, che potresti voler fare se vuoi eseguire ognuno con parametri diversi.

Come ho detto anche se copre solo gli scenari più semplici, le applicazioni che sono già essenzialmente servizi. Quello è che corrono continuamente. Sono sicuro che ci sono molti altri servizi che ti offrono molte più opzioni.

Personalmente non penso che sia particolarmente difficile convertire un'applicazione console, ma può essere una seccatura da testare. Alla fine però dipende da quanto controllo si vuole. Se è un servizio veramente importante per la tua azienda, allora direi convertirlo.

Problemi correlati