我开发了c#应用程序,其中apllication输出类型是Console Applicatiuon。 我想将此应用程序作为服务运行。 当我从visual studio运行它或只需双击.exe时,Environment.UserInteractive始终为true。
以下是我的代码
static void Main(string[] args)
{
// Get the version of the current application.
Assembly assem = Assembly.GetExecutingAssembly();
AssemblyName assemName = assem.GetName();
Version ver = assemName.Version;
// Console.WriteLine("{0}, Version {1}", assemName.Name, ver.ToString());
Console.WriteLine("{0} version {1}", assemName.Name, ver.ToString());
TouchService touchService = new TouchService();
if (Environment.UserInteractive)
{
bool show_help = false;
bool install_service = false;
bool uninstall_service = false;
string servicename = "";
OptionSet p = new OptionSet()
.Add("h|?|help", delegate(string v) { show_help = v != null; })
.Add("s|servicename=", "name of installed service", delegate(string v) { servicename = v; })
.Add("i|install", "install program as a Windows Service. A valid servicename is needed.", delegate(string v) { install_service = v != null; })
.Add("u|uninstall", "uninstall program from Windows Services. A valid servicename is needed.", delegate(string v) { uninstall_service = v != null; });
List<string> extra;
try
{
extra = p.Parse(args);
}
catch (OptionException e)
{
Console.Write("TouchServer: ");
Console.WriteLine(e.Message);
Console.WriteLine("Try `TouchServer --help' for more information.");
return;
}
if (show_help)
{
ShowHelp(p);
return;
}
else if (install_service)
{
IntegratedServiceInstaller Inst = new IntegratedServiceInstaller();
Inst.Install(servicename, null, "Provides XML data over HTTP for Touch clients",
System.ServiceProcess.ServiceAccount.NetworkService,
System.ServiceProcess.ServiceStartMode.Manual);
return;
}
else if (uninstall_service)
{
IntegratedServiceInstaller Inst = new IntegratedServiceInstaller();
Inst.Uninstall(servicename);
return;
}
// start and run the server,
// and receive commands from the console
else
{
touchService.OnStart(args);
while(true)
{
Console.Write("TouchServer>");
string commandLine = Console.ReadLine().ToLower();
if (commandLine == "exit" || commandLine == "x")
{
break;
}
if (commandLine == "quit" || commandLine == "q")
{
break;
}
else if(commandLine == "version" || commandLine == "v")
{
Console.WriteLine("{0} version {1}", assem.GetName().Name, assem.GetName().Version.ToString());
}
else if (commandLine == "list" || commandLine == "l")
{
TouchServer.showURLs = (TouchServer.showURLs == false) ? true : false;
Console.WriteLine("List URLs: {0}", (TouchServer.showURLs ? "active" : "inactive"));
}
else if (commandLine == "status" || commandLine == "s")
{
Console.WriteLine("{0,-20} {1,8}", "Name", "Sessions");
Console.WriteLine("----------------------------");
foreach (Site site in TouchServer.siteCollection.All)
{
Console.WriteLine("{0,-20} {1,8}", site.Name, site.AllSessions.Length);
}
Console.WriteLine();
}
}
touchService.OnStop();
}
}
**else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new TouchService()
};
ServiceBase.Run(ServicesToRun);
}**
我如何将其作为服务运行,请帮助我。 提前致谢 桑吉塔
答案 0 :(得分:16)
使用文件 - &gt;新项目 - &gt; Visual C# - &gt; Windows-&gt; Windows服务,
将主代码添加到OnStart()和OnStop()事件处理程序,然后将其安装为服务:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
namespace MyWindowsService
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
}
答案 1 :(得分:7)
以下是我使用的解决方案,它在Visual Studio 2012和.NET 4.5下运行良好。当我在控制台模式下运行时,它运行正常,当我使用installutil.exe
作为服务运行时,它运行正常。
档案MainPayload.cs
。您可以忽略所有其他文件,并将长时间运行的代码插入此文件中。请注意CancellationTokenSource
,这样服务可以在服务停止时快速退出。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
//using Gurock.SmartInspect; // Only used if we are logging using SmartInspect (see www.SmartInspect.com).
namespace Demos___Service_Plus_Console
{
/// <summary>
/// Main entry point for both console and Windows service.
/// </summary>
public class MainPayload
{
private readonly CancellationTokenSource _cancellationTokenSource;
/// <summary>
/// Constructor; do not block in this call; it is for setup only.
/// </summary>
public MainPayload(CancellationTokenSource cancellationTokenSource)
{
// Do not block in this call; it is for setup only.
_cancellationTokenSource = cancellationTokenSource;
}
/// <summary>
/// Long running task here.
/// </summary>
public void Run()
{
while (_cancellationTokenSource.IsCancellationRequested == false)
{
//SiAuto.Main.LogMessage(".");
Console.WriteLine(".");
// This will break every N seconds, or immediately if on cancellation token.
_cancellationTokenSource.Token.WaitHandle.WaitOne(TimeSpan.FromSeconds(1));
}
//SiAuto.Main.LogMessage("Exited Run().");
Console.WriteLine("Exited Run().");
Thread.Sleep(500); // If we remove this line, then we will miss the final few writes to the console.
}
}
}
档案EntryPoint.cs
。这是控制台应用程序和服务的入口点。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
//using Gurock.SmartInspect; // Only used if we are logging using SmartInspect (see www.SmartInspect.com).
namespace Demos___Service_Plus_Console
{
internal static class EntryPoint
{
// Run in console mode.
private static readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private static Task _task;
/// <summary>
/// The main entry point for the application.
/// </summary>
public static void Main(string[] args)
{
//SiAuto.Si.Connections = "pipe(reconnect=\"true\", reconnect.interval=\"10\", backlog.enabled=\"true\", backlog.flushon=\"debug\", backlog.keepopen=\"true\")";
//SiAuto.Si.Enabled = true;
if (Environment.UserInteractive)
{
// Make sure that we can write to the console.
StreamWriter standardOutput = new StreamWriter(Console.OpenStandardOutput()) {AutoFlush = true};
Console.SetOut(standardOutput);
// If Ctrl-C is pressed in the console, we get to here.
Console.CancelKeyPress += new ConsoleCancelEventHandler(myHandler);
MainPayload myMain = new MainPayload(_cancellationTokenSource); // Pass the token into the task.
_task = Task.Run(() => myMain.Run());
// Wait for the payload task to finish.
while (_cancellationTokenSource.IsCancellationRequested == false)
{
// This will break every N seconds, or immediately if cancellation token is pinged.
_cancellationTokenSource.Token.WaitHandle.WaitOne(TimeSpan.FromSeconds(10));
}
}
else
{
// Run as Windows Service.
var ServicesToRun = new ServiceBase[]
{
new ServiceController()
};
ServiceBase.Run(ServicesToRun);
}
_task.Wait(TimeSpan.FromSeconds(10)); // Delay for console to write its final output.
}
static void myHandler(object sender, ConsoleCancelEventArgs args)
{
_cancellationTokenSource.Cancel();
//SiAuto.Main.LogMessage("CtrlC pressed.");
Console.WriteLine("CtrlC pressed.");
}
}
}
档案ProjectInstaller.cs
。这是该服务的安装程序。
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.Threading.Tasks;
namespace Demos___Service_Plus_Console
{
[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
InitializeComponent();
}
private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
{
}
private void serviceProcessInstaller1_AfterInstall(object sender, InstallEventArgs e)
{
}
}
}
档案ServiceController.cs
。其中包含服务的Start()
和Stop()
方法。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Demos___Service_Plus_Console
{
/// <summary>
/// When running in service mode.
/// </summary>
public partial class ServiceController : ServiceBase
{
public ServiceController()
{
InitializeComponent();
}
readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
// Initialize payload.
private MainPayload myMain;
protected override void OnStart(string[] args)
{
myMain = new MainPayload(cancellationTokenSource); // Pass the token into the task.
Task.Run(() => myMain.Run());
}
protected override void OnStop()
{
cancellationTokenSource.Cancel();
}
}
}
要将其安装为Windows服务,请使用installutil.exe ServiceName.exe
。要卸载,请使用installutil.exe ServiceName.exe -u
。这意味着您必须在Visual Studio 2012 x32 command prompt
中打开Visual Studio Tools
下的Start Menu
。如果要在32位模式下进行编译,请使用32位命令提示符,如果要在64位模式下进行编译,请打开64位命令提示符(这意味着路径设置正确,如{{1根据其32位还是64位而具有单独的版本。
打开installutil.exe
面板,然后查找名为Services
的新服务。当你启动它时,如果你打开了一个日志框架,那么你会看到每秒都会在日志中输入消息。
它看起来像很多代码,但它全部基于Visual Studio 2012中的ServiceController
项目模板。我创建了一个新的Windows服务,然后使用Windows Service
在控制台或服务。我添加了CancellationTokens以确保如果服务停止,任务也会很快停止(即使它有延迟)。
唯一的另一个技巧是右键单击&#34; Service1.cs&#34;的灰色背景。页面,then click "Add Installer" which adds the installer。如果您不这样做,那么Environment.UserInteracive
会给您一个错误。
您还必须右键点击installutil.exe
,然后选择serviceProcessInstaller1
并将Properties
设置为Account
,否则它将ask you for username credentials when you install the service。
以下是所需的额外参考资料(使用模板创建新的Windows服务时会自动添加这些参考资料):
您会注意到LocalService
和Gurock.SmartInspect
的引用。如果要观察正在运行的服务创建的日志,可以使用此或其他内容,如NLog或log4net。
答案 2 :(得分:5)
仅当Environment.UserInteractive实际作为服务运行时,它才为false。双击它或从Visual Studio启动它时;它作为普通的控制台应用程序运行,桌面可用,因此Environment.UserInteractive是真的。
您可以从ConsoleService类Squiggle's code base派生您的类,以创建一个也可以作为Windows服务运行的控制台应用程序。
public class ConsoleService : ServiceBase
{
public void RunConsole(string[] args)
{
Trace.Listeners.Add(new ConsoleTraceListener());
OnStart(args);
Trace.WriteLine(this.ServiceName + " running... Press any key to stop");
Trace.WriteLine("");
Console.ReadKey();
OnStop();
}
public static void Run<TService>(string[] args) where TService : ConsoleService, new()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
if (Environment.UserInteractive)
{
try
{
string option = args.Length > 0 ? args[0].ToUpperInvariant() : String.Empty;
switch (option)
{
case "-I":
case "/I":
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetCallingAssembly().Location });
break;
case "-U":
case "/U":
ManagedInstallerClass.InstallHelper(new string[] { "/U", Assembly.GetCallingAssembly().Location });
break;
default:
new TService().RunConsole(args);
break;
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
}
else
{
ServiceBase[] servicesToRun = new ServiceBase[] { new TService() };
ServiceBase.Run(servicesToRun);
}
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if (e.ExceptionObject is Exception)
Trace.WriteLine(((Exception)e.ExceptionObject).Message);
}
}
答案 3 :(得分:4)
我刚刚在Visual Studio 2013中对此进行了测试,但它确实有效。
以下是我的Program.cs的样子:
static class Program
{
/// <summary>
/// </summary>
static void Main()
{
if (!Environment.UserInteractive)
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
else
{
Console.Write("Hit any key to continue...");
Console.ReadKey();
}
}
}
您可以添加服务安装like this
您可以使用以下命令安装服务:installutil.exe /i YouExeName.exe
您可以使用以下命令卸载服务:installutil.exe /u YouExeName.exe