[windows] 서버에 동일한 Windows 서비스의 여러 인스턴스 설치

그래서 우리는 클라이언트 응용 프로그램에 데이터를 공급하는 Windows 서비스를 생성했으며 모든 것이 잘 진행되고 있습니다. 클라이언트는 동일한 서버에서 실행되고 별도의 데이터베이스를 가리 키도록 구성된이 서비스의 두 인스턴스가 필요한 재미있는 구성 요청을 내놓았습니다.

지금까지 나는 이런 일이 일어나지 않았고 동료 stackoverflow 구성원이 이유에 대한 힌트를 줄 수 있기를 바랐습니다.

현재 설정 :

Windows 서비스가 포함 된 프로젝트를 설정했습니다. 이제부터는 AppService라고 부르겠습니다. App.config의 키를 기반으로 서비스 이름을 설정하는 사용자 지정 설치 단계를 처리하는 ProjectInstaller.cs 파일은 다음과 같습니다. :

this.serviceInstaller1.ServiceName = Util.ServiceName;
this.serviceInstaller1.DisplayName = Util.ServiceName;
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;

이 경우 Util은 구성 파일에서 서비스 이름을로드하는 정적 클래스입니다.

여기서부터 나는 두 서비스를 설치하기 위해 두 가지 다른 방법을 시도했지만 둘 다 동일한 방식으로 실패했습니다.

첫 번째 방법은 단순히 서비스의 첫 번째 복사본을 설치하고 설치된 디렉터리를 복사하고 이름을 바꾼 다음 앱 구성을 수정하여 원하는 서비스 이름을 변경 한 후 다음 명령을 실행하는 것입니다.

InstallUtil.exe /i AppService.exe

그래도 작동하지 않을 때 두 번째 설치 프로그램 프로젝트를 만들고 구성 파일을 편집하고 두 번째 설치 프로그램을 만들려고했습니다. 설치 프로그램을 실행했을 때 제대로 작동했지만 서비스가 services.msc에 표시되지 않았으므로 두 번째 설치된 코드베이스에 대해 이전 명령을 실행했습니다.

두 번 모두 InstallUtil에서 다음 출력을 받았습니다 (관련 부품 만 해당).

트랜잭션 된 설치 실행.

설치의 설치 단계를 시작합니다.

서비스 App Service Two 설치 중 … Service App Service Two가 성공적으로 설치되었습니다. 로그 애플리케이션에서 EventLog 소스 App Service Two를 만드는 중 …

설치 단계 중에 예외가 발생했습니다. System.NullReferenceException : 개체 참조가 개체의 인스턴스로 설정되지 않았습니다.

설치의 롤백 단계가 시작됩니다.

소스 App Service Two의 이벤트 로그를 이전 상태로 복원합니다. 서비스 앱 서비스 2가 시스템에서 제거되고 있습니다 … 서비스 앱 서비스 2가 시스템에서 성공적으로 제거되었습니다.

롤백 단계가 성공적으로 완료되었습니다.

거래 된 설치가 완료되었습니다. 설치에 실패했으며 롤백이 수행되었습니다.

긴 게시물에 대해 죄송합니다. 관련 정보가 충분한 지 확인하고 싶었습니다. 지금까지 저를 당황하게 만든 부분은 서비스 설치가 성공적으로 완료되고 NullReferenceException이 발생하는 것처럼 보이는 EventLog 소스를 생성 한 후에야 만 서비스 설치가 완료되었다는 것입니다. 그래서 누군가 내가 뭘 잘못하고 있는지 알고 있거나 더 나은 접근 방식을 가지고 있다면 대단히 감사하겠습니다.



답변

sc / service controller util을 사용해 보셨습니까? 유형

sc create

명령 줄에서 도움말 항목을 제공합니다. 이전에 Subversion에 대해이 작업을 수행했으며이 기사 를 참조로 사용했다고 생각합니다 .

http://svn.apache.org/repos/asf/subversion/trunk/notes/windows-service.txt


답변

  sc create [servicename] binpath= [path to your exe]

이 솔루션은 저에게 효과적이었습니다.


답변

다음을 수행하여 동일한 서비스의 여러 버전을 실행할 수 있습니다.

1) 서비스 실행 파일 및 구성을 자체 폴더에 복사하십시오.

2) Install.Exe를 서비스 실행 폴더 (.net framework 폴더에서)로 복사합니다.

3) 다음 내용 (고유 서비스 이름)으로 서비스 실행 폴더에 Install.exe.config라는 구성 파일을 만듭니다.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="ServiceName" value="The Service Name"/>
    <add key="DisplayName" value="The Service Display Name"/>
  </appSettings>
</configuration>

4) 다음 내용으로 서비스를 설치할 배치 파일을 만듭니다.

REM Install
InstallUtil.exe YourService.exe
pause

5) 거기에있는 동안 제거 배치 파일을 만듭니다.

REM Uninstall
InstallUtil.exe -u YourService.exe
pause

편집하다:

내가 뭔가를 놓친 경우 ServiceInstaller 클래스가 있는지 확인하십시오 (필요에 따라 조정).

using System.Configuration;

namespace Made4Print
{
    partial class ServiceInstaller
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        private System.ServiceProcess.ServiceInstaller FileProcessingServiceInstaller;
        private System.ServiceProcess.ServiceProcessInstaller FileProcessingServiceProcessInstaller;

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.FileProcessingServiceInstaller = new System.ServiceProcess.ServiceInstaller();
            this.FileProcessingServiceProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller();
            // 
            // FileProcessingServiceInstaller
            // 
            this.FileProcessingServiceInstaller.ServiceName = ServiceName;
            this.FileProcessingServiceInstaller.DisplayName = DisplayName;
            // 
            // FileProcessingServiceProcessInstaller
            // 
            this.FileProcessingServiceProcessInstaller.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
            this.FileProcessingServiceProcessInstaller.Password = null;
            this.FileProcessingServiceProcessInstaller.Username = null;
            // 
            // ServiceInstaller
            // 
            this.Installers.AddRange(new System.Configuration.Install.Installer[] { this.FileProcessingServiceInstaller, this.FileProcessingServiceProcessInstaller });
        }

        #endregion

        private string ServiceName
        {
            get
            {
                return (ConfigurationManager.AppSettings["ServiceName"] == null ? "Made4PrintFileProcessingService" : ConfigurationManager.AppSettings["ServiceName"].ToString());
            }
        }

        private string DisplayName
        {
            get
            {
                return (ConfigurationManager.AppSettings["DisplayName"] == null ? "Made4Print File Processing Service" : ConfigurationManager.AppSettings["DisplayName"].ToString());
            }
        }
    }
}


답변

이전 질문은 알고 있지만 InstallUtil.exe에서 / servicename 옵션을 사용하여 운이 좋았습니다. 그래도 기본 제공 도움말에 나와 있지 않습니다.

InstallUtil.exe /servicename="My Service" MyService.exe

나는 이것에 대해 처음 읽은 곳이 확실하지 않지만 그 이후로는 보지 못했습니다. YMMV.


답변

ServiceName및에 대한 사용자 지정 값을 지정하는 또 다른 빠른 방법 DisplayNameinstallutil명령 줄 매개 변수를 사용하는 것입니다.

  1. 당신의에 ProjectInstaller클래스의 가상 메소드를 오버라이드 (override) Install(IDictionary stateSaver)Uninstall(IDictionary savedState)

    public override void Install(System.Collections.IDictionary stateSaver)
    {
        GetCustomServiceName();
        base.Install(stateSaver);
    }
    
    public override void Uninstall(System.Collections.IDictionary savedState)
    {
        GetCustomServiceName();
        base.Uninstall(savedState);
    }
    
    //Retrieve custom service name from installutil command line parameters
    private void GetCustomServiceName()
    {
        string customServiceName = Context.Parameters["servicename"];
        if (!string.IsNullOrEmpty(customServiceName))
        {
            serviceInstaller1.ServiceName = customServiceName;
            serviceInstaller1.DisplayName = customServiceName;
        }
    }
  2. 프로젝트 구축
  3. 매개 변수를 installutil사용하여 사용자 정의 이름 을 추가하여 서비스를 설치하십시오 /servicename.

    installutil.exe /servicename="CustomServiceName" "c:\pathToService\SrvcExecutable.exe"
    

/servicename명령 줄에 지정하지 않으면 ProjectInstaller 속성 / 구성에 지정된 ServiceName 및 DisplayName 값으로 서비스가 설치됩니다.


답변

자동 배포 소프트웨어를 사용하여 side-by-side Windows 서비스를 자주 설치 / 제거 할 때 위의 방법으로 운이 좋지는 않았지만 결국에는 접미사를 지정하는 매개 변수를 전달할 수있는 다음을 생각해 냈습니다. 명령 줄의 서비스 이름에 추가합니다. 또한 디자이너가 제대로 작동 할 수 있으며 필요한 경우 전체 이름을 재정의하도록 쉽게 조정할 수 있습니다.

public partial class ProjectInstaller : System.Configuration.Install.Installer
{
  protected override void OnBeforeInstall(IDictionary savedState)
  {
    base.OnBeforeInstall(savedState);
    SetNames();
  }

  protected override void OnBeforeUninstall(IDictionary savedState)
  {
    base.OnBeforeUninstall(savedState);
    SetNames();
  }

  private void SetNames()
  {
    this.serviceInstaller1.DisplayName = AddSuffix(this.serviceInstaller1.DisplayName);
    this.serviceInstaller1.ServiceName = AddSuffix(this.serviceInstaller1.ServiceName);
  }

  private string AddSuffix(string originalName)
  {
    if (!String.IsNullOrWhiteSpace(this.Context.Parameters["ServiceSuffix"]))
      return originalName + " - " + this.Context.Parameters["ServiceSuffix"];
    else
      return originalName;
  }
}

이를 염두에두고 다음을 수행 할 수 있습니다. 서비스를 “Awesome Service”라고 불렀다면 다음과 같이 서비스의 UAT 버전을 설치할 수 있습니다.

InstallUtil.exe /ServiceSuffix="UAT" MyService.exe

그러면 “Awesome Service-UAT”라는 이름의 서비스가 생성됩니다. 이를 사용하여 단일 시스템에서 나란히 실행되는 동일한 서비스의 DEVINT, TESTING 및 ACCEPTANCE 버전을 실행했습니다. 각 버전에는 고유 한 파일 / 구성 세트가 있습니다. 동일한 파일 세트를 가리키는 여러 서비스를 설치하려고 시도한 적이 없습니다.

참고 : /ServiceSuffix서비스를 제거 하려면 동일한 매개 변수 를 사용해야 하므로 제거하려면 다음을 실행합니다.

InstallUtil.exe /u /ServiceSuffix="UAT" MyService.exe


답변

이 작업을 수행하기 위해 내가 한 것은 서비스 이름과 표시 이름을 내 서비스의 app.config에 저장하는 것입니다. 그런 다음 설치 프로그램 클래스에서 app.config를 XmlDocument로로드하고 xpath를 사용하여 값을 가져 와서 InitializeComponent ()를 호출하기 전에 ServiceInstaller.ServiceName 및 ServiceInstaller.DisplayName에 적용합니다. 이는 InitializeComponent ()에서 이러한 속성을 아직 설정하지 않았다고 가정합니다.이 경우 구성 파일의 설정이 무시됩니다. 다음 코드는 InitializeComponent () 전에 설치 프로그램 클래스 생성자에서 호출하는 코드입니다.

       private void SetServiceName()
       {
          string configurationFilePath = Path.ChangeExtension(Assembly.GetExecutingAssembly().Location, "exe.config");
          XmlDocument doc = new XmlDocument();
          doc.Load(configurationFilePath);

          XmlNode serviceName = doc.SelectSingleNode("/xpath/to/your/@serviceName");
          XmlNode displayName = doc.SelectSingleNode("/xpath/to/your/@displayName");

          if (serviceName != null && !string.IsNullOrEmpty(serviceName.Value))
          {
              this.serviceInstaller.ServiceName = serviceName.Value;
          }

          if (displayName != null && !string.IsNullOrEmpty(displayName.Value))
          {
              this.serviceInstaller.DisplayName = displayName.Value;
          }
      }

ConfigurationManager.AppSettings 등에서 직접 구성 파일을 읽는 것이 설치 프로그램이 실행될 때 서비스의 .exe가 아닌 InstallUtil.exe의 컨텍스트에서 실행되는 것처럼 작동한다고 생각하지 않습니다. ConfigurationManager.OpenExeConfiguration으로 뭔가를 할 수 있지만 제 경우에는로드되지 않은 사용자 지정 구성 섹션을 가져 오려고했기 때문에이 작업이 작동하지 않았습니다.