그래서 우리는 클라이언트 응용 프로그램에 데이터를 공급하는 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
및에 대한 사용자 지정 값을 지정하는 또 다른 빠른 방법 DisplayName
은 installutil
명령 줄 매개 변수를 사용하는 것입니다.
-
당신의에
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; } }
- 프로젝트 구축
-
매개 변수를
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으로 뭔가를 할 수 있지만 제 경우에는로드되지 않은 사용자 지정 구성 섹션을 가져 오려고했기 때문에이 작업이 작동하지 않았습니다.