Windows 서비스로서의 .NET 콘솔 어플리케이션
콘솔 응용 프로그램이 있고 Windows 서비스로 실행하고 싶습니다. VS2010에는 콘솔 프로젝트를 연결하고 Windows 서비스를 빌드 할 수있는 프로젝트 템플릿이 있습니다. 별도의 서비스 프로젝트를 추가하지 않고 가능한 경우 서비스 응용 프로그램 코드를 콘솔 응용 프로그램에 통합하여 콘솔 응용 프로그램을 콘솔 응용 프로그램으로 실행할 수있는 하나의 프로젝트 또는 스위치를 사용하여 명령 줄에서 실행할 경우 Windows 서비스로 유지할 수 있습니다.
어쩌면 누군가가 C # 콘솔 응용 프로그램을 서비스로 빠르고 쉽게 변환 할 수있는 클래스 라이브러리 또는 코드 스 니펫을 제안 할 수 있습니까?
나는 보통 다음 기술을 사용하여 콘솔 응용 프로그램이나 서비스와 동일한 응용 프로그램을 실행합니다.
public static class Program
{
#region Nested classes to support running as service
public const string ServiceName = "MyService";
public class Service : ServiceBase
{
public Service()
{
ServiceName = Program.ServiceName;
}
protected override void OnStart(string[] args)
{
Program.Start(args);
}
protected override void OnStop()
{
Program.Stop();
}
}
#endregion
static void Main(string[] args)
{
if (!Environment.UserInteractive)
// running as service
using (var service = new Service())
ServiceBase.Run(service);
else
{
// running as console app
Start(args);
Console.WriteLine("Press any key to stop...");
Console.ReadKey(true);
Stop();
}
}
private static void Start(string[] args)
{
// onstart code here
}
private static void Stop()
{
// onstop code here
}
}
Environment.UserInteractive
콘솔 앱의 경우 일반적으로 true이고 서비스의 경우 false입니다. 기술적으로 사용자 대화 형 모드에서 서비스를 실행할 수 있으므로 대신 명령 줄 스위치를 확인할 수 있습니다.
TopShelf는 콘솔 앱 또는 Windows 서비스로 실행할 수있는 .NET Windows 앱을 쉽게 만들 수 있도록 설계된 Nuget 패키지입니다. 서비스 시작 및 중지 이벤트와 같은 이벤트를 신속하게 연결하고, 코드를 사용하여 실행 계정을 설정하고, 다른 서비스에 대한 종속성을 구성하고, 오류로부터 복구하는 방법을 구성 할 수 있습니다.
패키지 관리자 콘솔 (Nuget)에서 :
설치 패키지 상단 선반
시작 하려면 코드 샘플 을 참조하십시오 .
예:
HostFactory.Run(x =>
{
x.Service<TownCrier>(s =>
{
s.ConstructUsing(name=> new TownCrier());
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc => tc.Stop());
});
x.RunAsLocalSystem();
x.SetDescription("Sample Topshelf Host");
x.SetDisplayName("Stuff");
x.SetServiceName("stuff");
});
또한 TopShelf는 서비스 설치를 관리하므로 많은 시간을 절약하고 솔루션에서 상용구 코드를 제거 할 수 있습니다. .exe를 서비스로 설치하려면 명령 프롬프트에서 다음을 실행하십시오.
myservice.exe install -servicename "MyService" -displayname "My Service" -description "This is my service."
ServiceInstaller를 연결할 필요가 없으며 TopShelf가 모든 것을 지원합니다.
다음은 전체 연습입니다.
- 새 콘솔 응용 프로그램 프로젝트 (예 : MyService)를 만듭니다.
- 두 개의 라이브러리 참조 (System.ServiceProcess 및 System.Configuration.Install)를 추가하십시오.
- 아래에 인쇄 된 3 개의 파일을 추가하십시오.
- 프로젝트를 빌드하고 "InstallUtil.exe c : \ path \ to \ MyService.exe"를 실행하십시오.
- 이제 서비스 목록에 MyService가 표시됩니다 (run services.msc).
* InstallUtil.exe는 일반적으로 다음 위치에 있습니다. C : \ windows \ Microsoft.NET \ Framework \ v4.0.30319 \ InstallUtil.exe
Program.cs
using System;
using System.IO;
using System.ServiceProcess;
namespace MyService
{
class Program
{
public const string ServiceName = "MyService";
static void Main(string[] args)
{
if (Environment.UserInteractive)
{
// running as console app
Start(args);
Console.WriteLine("Press any key to stop...");
Console.ReadKey(true);
Stop();
}
else
{
// running as service
using (var service = new Service())
{
ServiceBase.Run(service);
}
}
}
public static void Start(string[] args)
{
File.AppendAllText(@"c:\temp\MyService.txt", String.Format("{0} started{1}", DateTime.Now, Environment.NewLine));
}
public static void Stop()
{
File.AppendAllText(@"c:\temp\MyService.txt", String.Format("{0} stopped{1}", DateTime.Now, Environment.NewLine));
}
}
}
MyService.cs
using System.ServiceProcess;
namespace MyService
{
class Service : ServiceBase
{
public Service()
{
ServiceName = Program.ServiceName;
}
protected override void OnStart(string[] args)
{
Program.Start(args);
}
protected override void OnStop()
{
Program.Stop();
}
}
}
MyServiceInstaller.cs
using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;
namespace MyService
{
[RunInstaller(true)]
public class MyServiceInstaller : Installer
{
public MyServiceInstaller()
{
var spi = new ServiceProcessInstaller();
var si = new ServiceInstaller();
spi.Account = ServiceAccount.LocalSystem;
spi.Username = null;
spi.Password = null;
si.DisplayName = Program.ServiceName;
si.ServiceName = Program.ServiceName;
si.StartType = ServiceStartMode.Automatic;
Installers.Add(spi);
Installers.Add(si);
}
}
}
당신이 사용할 수있는
reg add HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run /v ServiceName /d "c:\path\to\service\file\exe"
And it will appear int the service list. I do not know, whether that works correctly though. A service usually has to listen to several events.
There are several service wrapper though, that can run any application as a real service. For Example Microsofts SrvAny from the Win2003 Resource Kit
I hear your point at wanting one assembly to stop repeated code but, It would be simplest and reduce code repetition and make it easier to reuse your code in other ways in future if...... you to break it into 3 assemblies.
- One library assembly that does all the work. Then have two very very slim/simple projects:
- one which is the commandline
- one which is the windows service.
Firstly I embed the console application solution into the windows service solution and reference it.
Then I make the console application Program class public
/// <summary>
/// Hybrid service/console application
/// </summary>
public class Program
{
}
I then create two functions within the console application
/// <summary>
/// Used to start as a service
/// </summary>
public void Start()
{
Main();
}
/// <summary>
/// Used to stop the service
/// </summary>
public void Stop()
{
if (Application.MessageLoop)
Application.Exit(); //windows app
else
Environment.Exit(1); //console app
}
Then within the windows service itself I instantiate the Program and call the Start and Stop functions added within the OnStart and OnStop. See below
class WinService : ServiceBase
{
readonly Program _application = new Program();
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] servicesToRun = { new WinService() };
Run(servicesToRun);
}
/// <summary>
/// Set things in motion so your service can do its work.
/// </summary>
protected override void OnStart(string[] args)
{
Thread thread = new Thread(() => _application.Start());
thread.Start();
}
/// <summary>
/// Stop this service.
/// </summary>
protected override void OnStop()
{
Thread thread = new Thread(() => _application.Stop());
thread.Start();
}
}
This approach can also be used for a windows application / windows service hybrid
Maybe you should define what you need, as far as I know, you can't run your app as Console or Service with command line, at the same time. Remember that the service is installed and you have to start it in Services Manager, you can create a new application wich starts the service or starts a new process running your console app. But as you wrote
"keep console application as one project"
Once, I was in your position, turning a console application into a service. First you need the template, in case you are working with VS Express Edition. Here is a link where you can have your first steps: C# Windows Service, this was very helpful for me. Then using that template, add your code to the desired events of the service.
To improve you service, there's another thing you can do, but this is not quick and/or easily, is using appdomains, and creating dlls to load/unload. In one you can start a new process with the console app, and in another dll you can just put the functionality the service has to do.
Good luck.
You need to seperate the functionality into a class or classes and launch that via one of two stubs. The console stub or service stub.
As its plain to see, when running windows, the myriad services that make up the infrastructure do not (and can't directly) present console windows to the user. The service needs to communicate with the user in a non graphical way: via the SCM; in the event log, to some log file etc. The service will also need to communicate with windows via the SCM, otherwise it will get shutdown.
It would obviously be acceptable to have some console app that can communicate with the service but the service needs to run independently without a requirement for GUI interaction.
The Console stub can very useful for debugging service behaviour but should not be used in a "productionized" environment which, after all, is the purpose of creating a service.
I haven't read it fully but this article seems to pint in the right direction.
I use a service class that follows the standard pattern prescribed by ServiceBase
, and tack on helpers to easy F5 debugging. This keeps service data defined within the service, making them easy to find and their lifetimes easy to manage.
I normally create a Windows application with the structure below. I don't create a console application; that way I don't get a big black box popping in my face every time I run the app. I stay in in the debugger where all the action is. I use Debug.WriteLine
so that the messages go to the output window, which docks nicely and stays visible after the app terminates.
I usually don't bother add debug code for stopping; I just use the debugger instead. If I do need to debug stopping, I make the project a console app, add a Stop
forwarder method, and call it after a call to Console.ReadKey
.
public class Service : ServiceBase
{
protected override void OnStart(string[] args)
{
// Start logic here.
}
protected override void OnStop()
{
// Stop logic here.
}
static void Main(string[] args)
{
using (var service = new Service()) {
if (Environment.UserInteractive) {
service.Start();
Thread.Sleep(Timeout.Infinite);
} else
Run(service);
}
}
public void Start() => OnStart(null);
}
참고URL : https://stackoverflow.com/questions/7764088/net-console-application-as-windows-service
'development' 카테고리의 다른 글
JSON 객체의 항목이“json.dumps”를 사용하여 순서가 잘못 되었습니까? (0) | 2020.06.28 |
---|---|
영문자와 만 일치하는 정규식 (0) | 2020.06.28 |
jQuery“속성이없는”선택기? (0) | 2020.06.28 |
Enterprise Library Unity 및 기타 IoC 컨테이너 (0) | 2020.06.28 |
PDO 데이터베이스 쿼리를 디버깅하는 방법? (0) | 2020.06.28 |