windows - 프로그램 - 윈도우 서비스란




서버에 동일한 Windows 서비스의 여러 인스턴스 설치 (6)

@ chris.house.00의 완벽한 답변을 향상시키기 위해 다음과 같은 기능을 고려하여 앱 설정에서 읽을 수 있습니다.

 public void GetServiceAndDisplayName(out string serviceNameVar, out string displayNameVar)
        {
            string configurationFilePath = Path.ChangeExtension(Assembly.GetExecutingAssembly().Location, "exe.config");
            XmlDocument doc = new XmlDocument();
            doc.Load(configurationFilePath);

            XmlNode serviceName = doc.SelectSingleNode("//appSettings//add[@key='ServiceName']");
            XmlNode displayName = doc.SelectSingleNode("//appSettings//add[@key='DisplayName']");


            if (serviceName != null && (serviceName.Attributes != null && (serviceName.Attributes["value"] != null)))
            {
                serviceNameVar = serviceName.Attributes["value"].Value;
            }
            else
            {
                serviceNameVar = "Custom.Service.Name";
            }

            if (displayName != null && (displayName.Attributes != null && (displayName.Attributes["value"] != null)))
            {
                displayNameVar = displayName.Attributes["value"].Value;
            }
            else
            {
                displayNameVar = "Custom.Service.DisplayName";
            }
        }

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

지금까지 나는이 일이 일어나지 못했고, 왜 내 동료 stackoverflow 멤버가 왜 그런지에 대한 힌트를 줄 수 있기를 바랬다.

현재 설정 :

Windows 서비스가 포함 된 프로젝트를 설정 했으므로 AppService를 지금부터 호출하고 AppInconfig의 키를 기반으로 서비스 이름을 설정하는 사용자 지정 설치 단계를 처리하는 ProjectInstaller.cs 파일을 호출합니다. :

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

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

여기에서 나는 두 가지 서비스를 모두 설치하고 두 가지 방법이 모두 실패한 두 가지 방법을 시도했다.

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

InstallUtil.exe /i AppService.exe

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

두 번 내가 InstallUtil (관련 부분에만)에서 다음과 같은 출력을 받았습니다 :

트랜잭션 설치 실행 중.

설치의 설치 단계 시작.

서비스 응용 프로그램 서비스 설치 두 ... 서비스 응용 프로그램 서비스 두 개가 성공적으로 설치되었습니다. 로그 응용 프로그램에서 EventLog 소스 App Service 2를 만드는 중 ...

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

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

원본 App Service 2의 이전 상태로 이벤트 로그를 복원합니다. 서비스 응용 프로그램 서비스 시스템에서 두 개가 제거되고 있습니다 ... 서비스 응용 프로그램 서비스 두 개가 시스템에서 성공적으로 제거되었습니다.

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

트랜잭션 설치가 완료되었습니다. 설치가 실패하고 롤백이 수행되었습니다.

장황한 게시물에 대해 유감스럽게도 충분한 관련 정보가 있는지 확인하고 싶었습니다. 지금까지 저를 괴롭혔던 부분은 서비스의 설치가 성공적으로 완료되었다는 것입니다. NullReferenceException이 발생하는 것으로 보이는 EventLog 소스를 생성하기 만하면됩니다. 그래서 누군가 내가 잘못하고있는 것을 알고 있거나 더 나은 접근법을 가지고 있다면 그것은 대단히 감사하게 될 것입니다.



비슷한 상황이 있었는데, 필요한 서비스가 이전 서비스 였고 동일한 서버에서 나란히 실행되는 업데이트 된 서비스가있었습니다. (그것은 단지 데이터베이스 변경 그 이상이었고, 코드 변경이었습니다). 따라서 동일한 .exe를 두 번 실행할 수는 없습니다. 새로운 DLL로 컴파일되었지만 같은 프로젝트의 새로운 .exe가 필요했습니다. 서비스 이름과 표시 이름을 변경하면 서비스가 작동하지 않습니다. 배포 프로젝트를 사용하고 있기 때문에 여전히 "서비스가 이미 존재합니다."오류가 발생했습니다. 마침내 나를 위해 일한 것은 내 배포 프로젝트 속성 내에 Guid 인 "ProductCode"라는 속성이 있습니다.

그런 다음 설치 프로젝트를 새 .exe 또는 .msi로 성공적으로 다시 빌드합니다.


위의 방법으로 자주 설치 / 제거 할 때 자동 배포 소프트웨어를 사용할 때 위의 방법과 관련해 많은 행운이 없었지만 필자는 접미사를 지정하기 위해 매개 변수를 전달할 수있는 다음과 같은 서비스를 제공했습니다. 명령 줄의 서비스 이름에 추가하십시오. 또한 디자이너가 제대로 작동하도록하고 필요한 경우 전체 이름을 재정의하도록 쉽게 적용 할 수 있습니다.

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 verison을 설치할 수 있습니다.

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

이렇게하면 "Awesome Service - UAT"라는 이름의 서비스가 생성됩니다. 우리는 이것을 단일 머신에서 나란히 실행되는 동일한 서비스의 DEVINT, TESTING 및 ACCEPTANCE 버전을 실행하는 데 사용했습니다. 각 버전마다 고유 한 파일 세트 / 구성이 있습니다. 동일한 파일 세트를 가리키는 여러 서비스를 설치하지 않았습니다.

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

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


이전 질문, 나도 알아,하지만 InstallUtil.exe에 / servicename 옵션을 사용하여 운이 좋았어요. 나는 내장 도움말에 나열된 것을 보지 못합니다.

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

나는 이것에 대해 처음 읽은 곳이 어디인지 확신 할 수는 없지만 그 이후로는 보지 못했습니다. YMMV.


ServiceNameDisplayName 대한 사용자 정의 값을 지정하는 또 다른 빠른 방법은 installutil 명령 행 매개 변수를 사용하는 것입니다.

  1. ProjectInstaller 클래스에서 가상 메서드 Install(IDictionary stateSaver)Uninstall(IDictionary savedState) 무시 Install(IDictionary stateSaver)

    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. /servicename 매개 변수를 사용하여 사용자 정의 이름을 추가하여 installutil 하여 서비스를 설치하십시오.

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

명령 줄에 /servicename 을 지정하지 않으면 서비스는 ProjectInstaller properties / config에 지정된 ServiceName 및 DisplayName 값과 함께 설치됩니다.





installutil