C#에서는 Windows 서비스를 작성하는 것이 매우 간단합니다. 저는 콘솔 응용 프로그램과 서비스를 결합하는 것을 좋아합니다. 왜냐하면 콘솔 응용 프로그램을 디버깅하는 것이 더 낳고 프로덕션에서는 서비스가 더 좋기 때문입니다. 서비스 기지로 난 항상 사용
Program.cs :
#define __USE_AS_CONSOLE___
using MyService.Service;
using System;
using System.Collections.Generic;
using System.Configuration.Install;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Diagnostics;
namespace MyService
{
public class Program
{
#region Private Member
private static ASServiceBase myServiceBase;
private static string serviceName;
#endregion
#region Console
const bool ShowConsole = true;
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool FreeConsole();
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool AddDllDirectory(string lpPathName);
#endregion
static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += ResolveError;
string installCommand = "";
serviceName = GetServiceName();
foreach(string arg in args)
{
if (arg.ToLower().StartsWith("/install"))
{
installCommand = "/install";
}
else if (arg.ToLower().StartsWith("/uninstall"))
{
installCommand = "/uninstall";
}
}
if (System.Environment.UserInteractive)
{
string parameter = "";
foreach (string arg in args)
{
parameter += arg;
if (!arg.EndsWith(" "))
{
parameter += "";
}
}
switch (installCommand)
{
case "/install":
if (!IsAdministrator())
{
System.Console.WriteLine("Die Anwendung muss als Administrator installiert werden.");
System.Console.ReadLine();
return;
}
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
return;
break;
case "/uninstall":
if (!IsAdministrator())
{
System.Console.WriteLine("Die Anwendung muss als Administrator installiert werden.");
System.Console.ReadLine();
return;
}
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
return;
break;
}
AllocConsole();
myServiceBase = new ASServiceBase();
myServiceBase.Start();
System.Console.ReadLine();
}
else
{
// ===============================================
// Start Console
AllocConsole();
System.Console.WriteLine("Version 1.0");
myServiceBase = new ASServiceBase();
//Start service
System.ServiceProcess.ServiceBase.Run(myServiceBase);
}
}
public static bool IsAdministrator()
{
var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
#region [Resolve Error]
/// <summary>
/// Resolve Error
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static Assembly ResolveError(object sender, ResolveEventArgs args)
{
try
{
Assembly cMyAssembly = null;
string strTempAssmbPath = string.Empty;
Assembly objExecutingAssemblies = Assembly.GetExecutingAssembly();
AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies();
AssemblyName myAssemblyName = Array.Find<AssemblyName>(arrReferencedAssmbNames, a => a.Name == args.Name);
if (myAssemblyName != null)
{
cMyAssembly = Assembly.LoadFrom(myAssemblyName.CodeBase);
}
else
{
string rootFolder = GetAssemblyPath(args, "");
if (!string.IsNullOrEmpty(rootFolder))
{
if (File.Exists(rootFolder))
{
// Loads the assembly from the specified path.
cMyAssembly = Assembly.LoadFrom(rootFolder);
}
}
string assemblyFolder = GetAssemblyPath(args, "Assemblies\\");
if (!string.IsNullOrEmpty(assemblyFolder))
{
if (File.Exists(assemblyFolder))
{
// Loads the assembly from the specified path.
cMyAssembly = Assembly.LoadFrom(assemblyFolder);
}
}
}
// Returns the loaded assembly.
return cMyAssembly;
}
catch (Exception exc)
{
FileLog.WriteLog("Fehler in Init.ResolveError:\r\n" + exc.ToString());
return null;
}
}
private static string GetAssemblyPath(ResolveEventArgs args, string AdditionalDirectory)
{
string returnValue = null;
string cRMSAssemblyFolder = GlobalSettings.StudioPath + "\\" + AdditionalDirectory;
Assembly cMyAssembly = null;
string strTempAssmbPath = string.Empty;
Assembly objExecutingAssemblies = Assembly.GetExecutingAssembly();
AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies();
AssemblyName myAssemblyName = Array.Find<AssemblyName>(arrReferencedAssmbNames, a => a.Name == args.Name);
if (myAssemblyName == null)
{
if (args.Name.Contains(","))
{
strTempAssmbPath = Path.Combine(cRMSAssemblyFolder, args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll");
}
else
{
strTempAssmbPath = Path.Combine(cRMSAssemblyFolder, args.Name + ".dll");
}
returnValue = strTempAssmbPath;
}
return returnValue;
}
#endregion
}
}
서비스 설치 :
using System;
using System.Configuration.Install;
using System.ComponentModel;
using System.ServiceProcess;
using System.IO;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Configuration;
using System.Diagnostics;
/// <summary>
/// Installerklasse für den Service
/// </summary>
[RunInstaller(true)]
public class QServiceInstaller : Installer
{
#region private Member
private ServiceInstaller myThisService;
private IContainer components;
private ServiceProcessInstaller myThisServiceProcess;
#endregion
public QServiceInstaller()
{
myThisService = new ServiceInstaller();
myThisServiceProcess = new ServiceProcessInstaller();
string Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
myThisServiceProcess.Account = ServiceAccount.LocalSystem;
myThisService.ServiceName = "Your application name";
myThisService.StartType = ServiceStartMode.Automatic;
Installers.Add(myThisService);
Installers.Add(myThisServiceProcess);
}
private void InitializeComponent()
{
}
}
서비스 기반 :
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading;
namespace MyService.Service
{
public class ASServiceBase : ServiceBase
{
#region Private Member
private Thread myServiceThread;
private bool myDoStop;
#endregion
#region Constructor
/// <summary>
/// Constructor
/// </summary>
public ASServiceBase()
{
myDoStop = false;
}
#endregion
#region Public Methods
#region OnStart
protected override void OnStart(string[] args)
{
Start();
}
/// <summary>
/// Start
/// </summary>
public void Start()
{
myServiceThread = new Thread(new ThreadStart(Do));
myServiceThread.Start();
MainThread = myServiceThread;
}
#endregion
#region Do Anything
/// <summary>
/// Execute
/// </summary>
public void Do()
{
while (!myDoStop)
{
// Do some stuff
Thread.Sleep(10);
}
LoggingManager.Singleton.Deactivate();
// =====================================================================================
// Stop anything
// =====================================================================================
}
#endregion
#region OnStop
protected override void OnStop()
{
Stop();
}
/// <summary>
/// Stop
/// </summary>
public void Stop()
{
myDoStop = true;
}
#endregion
#endregion
#region Private Methods
#endregion
#region Public Member
/// <summary>
/// Main Thread
/// </summary>
public static Thread MainThread
{
get;
set;
}
#endregion
}
}
내 코드의 도움을 희망합니다. 문의 사항이 있으시면
우수합니다, 감사합니다 - 이것은 나를 분석하기위한 좋은 예입니다 –
Actualy 그것은 반 패턴입니다. 설치를 위해서는 MSI를 만들어야합니다. 표준이며 모든 관리자는 해당 명령 줄 호지를 선호합니다. Wix 툴셋은 수년 동안이 표준입니다. – TomTom
@TomTom 귀하의 진술을지지합니다. 그러나 저는 두 가지 방법을 모두 관리자에게 제공하는 것을 좋아합니다. WiX의 ServiceControl은 다음과 같이 훌륭합니다. http://wixtoolset.org/documentation/manual/v3/xsd/wix/servicecontrol.html – BendEg