我正在寻找不同的优势/劣势,将我们长期使用的控制台应用程序转换为Windows服务。我们为ActiveMQ使用了一个叫做java服务包装器的东西,我相信人们告诉我你可以用它包装任何东西。那并不是说你应该用它包装任何东西;我们在这个设置中遇到了问题。
控制台应用程序是一个.NET控制台应用程序,默认情况下会将大量信息记录到控制台,但这是可配置的。
任何推荐?
我们应该在Visual Studio中将其重建为服务吗?使用包装?哪一个?
答案 0 :(得分:11)
我很想创建一个空的Windows服务项目,只需抓住处理服务的位;它不是很多 - Main
中的一些参考和一些代码。您实际上可以将现有控制台 作为服务和作为控制台 - 通过检查Main
并使用(例如)a“ -console“切换,或者我相信你可以检查Environment.UserInteractive
。
如果它处于“控制台”模式,请像现在一样运行代码;如果它处于服务模式,请运行您从模板项目中获取的代码。
有关信息,您也可以与服务的安装程序/卸载程序具有相同的exe工作!我使用“-install”/“-uninstall”开关执行此操作。例如,see here。
答案 1 :(得分:2)
Vici WinService会将控制台应用程序变为自安装Windows服务。它是开源的,您可以下载源代码。即使您不想使用该库,您仍然可以从中获得一些想法。
答案 2 :(得分:0)
一些想法:
Create windows service with VS 2005
几年前我写了一套基于Perl的可执行文件(theads)等等,这似乎与你的要求类似......
要记住一些事情:
这是一个使用log4net
输出到db,file和console的小型控制台示例 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" />
答案 3 :(得分:0)
您的长期使用情况是什么? Windows服务可能就足够了......但Windows Server 2008 / IIS7通过Windows激活服务提供了一些有趣的新方式来托管和激活“服务”。 Windows服务将始终运行,可能需要一些特殊编码。使用WAS,您可以将主机编写为普通的WCF服务,并在请求进入时按需激活,在不使用时停用。还存在其他选项......例如MSMQ托管和实例化等。
答案 4 :(得分:0)
我遇到了同样的问题,我最后编写了自己的包装器,它只对最简单的情况有好处,但确实有它的好处。您可以在此处找到该工具:http://runasservice.com。一些额外的好处包括您可以将应用程序编码为控制台应用程序,该应用程序易于在IDE中进行测试和运行。设置服务涉及一个简单的命令,因此您无需编辑应用程序。您也可以使用不同的名称多次安装该服务,如果您想使用不同的参数运行每个名称,可能需要这样做。
就像我说的那样,它只涵盖了最简单的场景,应用程序本质上就是服务。那就是他们不断奔跑。我相信还有很多其他服务可以为您提供更多选择。
就我个人而言,我认为转换控制台应用程序并不是特别困难,但是测试可能会很麻烦。最后,虽然这取决于你想要多少控制。如果这对贵公司来说是一项非常重要的服务,那么我会说转换它。