개발 산출물을 배포할 때에는 고려해야 할 항목들이 정말 많은 거 같다.
사용자가 느끼는 불편함이 곧 서비스에 대한 불만족이기 때문에 부정적인 요소들을 최대한 배제해야 한다.
윈도우 서비스 배포 시에는 아래 항목들을 주의해야 한다.
P.S. 해당 포스트는 Visual Studio 2022로 작성되었습니다.
Properties의 AssemblyInfo.cs에는 속성 값이 저장되어 있다.
[assembly: AssemblyTitle("타이틀입니다")]
[assembly: AssemblyDescription("설명입니다")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("회사명입니다")]
[assembly: AssemblyProduct("제품명입니다")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
프로젝트가 bin에 빌드 되면서 .exe 파일이 생성되는데 해당 파일에 대한 정보이다.

이걸 굳이 왜 넣어야 되냐면 개발사 정보 및 저작권에 대해 명시되어 있기도 하고,
현장에 설치 및 운영하던 중 이슈가 발생했을 때, 파일의 버전으로 추적이 용이해지기 때문이다.
(현장 방문이 어려운 상황일 때, 프로그램 버전만 알 수 있다면 사무실에서 클론 시험이 가능하다.)
윈도우 서비스 프로젝트는 아래와 같이 생성된다.

Service1.cs 디자인 뷰에서 우클릭 시 나타나는 설치 관리자를 추가를 클릭해 보자
(Visual Studio 2015~2019에서는 Service1.cs 속성에 설치 관리자가 있었던 거 같다.)

그럼 아래와 같은 파일들이 생성된다.

ProjectInstaller.Designer.cs 파일에 서비스 설치와 관련한 코드가 작성되어 있다.
this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
//
// serviceProcessInstaller1
//
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
//
// serviceInstaller1
//
// 서비스 설치 시 서비스 명칭이다. 배포 시 수정 필요
this.serviceInstaller1.ServiceName = "Service1";
//
// ProjectInstaller
//
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
this.serviceProcessInstaller1,
this.serviceInstaller1});
윈도우 OS에 서비스를 등록하기 위해 흔히들 SVC 라이브러리나 별도 툴을 이용한다.
하지만 C#에서는 코드 상에서 현재 실행 중인 바이너리를 서비스에 등록할 수 있다.
private static string binaryPath = Assembly.GetExecutingAssembly().Location;
static void fnServiceInstall() {
ManagedInstallerClass.InstallHelper(new string[] {
binaryPath
});
}
static void fnServiceUninstall() {
ManagedInstallerClass.InstallHelper(new string[] {
'/u', binaryPath
});
}
Arguments로 커맨드를 받아서 서비스 install, uninstall, start, stop을 처리한다.
실제 install 명령을 Arguments로 실행해 보면 아래와 같은 팝업이 표출된다.

서비스 로그인 계정을 매번 입력하기 불편하니 코드 상에서 계정 정보를 넣어줄 수 있다.
위에서 생성했던 ProjectInstaller.Designer.cs 파일에 아래 계정 코드를 추가하자.
// 추가
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
// 기존 코드
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
사무실에서 명세서만 보고 개발한 산출물은 현장 구축, 운영 시 문제점이 발생하기 마련이다.
그렇다고 현장에 IDE를 설치할 수 없는 노릇이니, 프로그램 자체적인 디버그 방법을 마련해 현장에서 이슈에 대한 원인 분석 및 해결이 가능하도록 해야 한다.
가장 좋은 것은 모든 로직에 로그 생성 기능을 포함하는 것이다.
로그 레벨을 설정하고, Info, Error, Warning에 대한 로그를 찍으면 원인 추적이 가능해진다.
또 다른 방법은 CMD로 실행 시 콘솔 출력을 하는 것이다.
CMD로 프로그램을 실행할 때 Arguments로 디버그 모드임을 알려주고, 프로그램은 그에 따라 콘솔 출력을 수행한다. 프롬프트에는 콘솔에 출력한 내용들이 표출될 것이므로, 로그 파일을 뒤져보지 않더라도 좀 더 간편한 방법으로 디버깅이 가능하다.