在服务器上安装同一 Windows 服务的多个实例

发布于 2024-08-01 20:28:06 字数 1472 浏览 3 评论 0原文

因此,我们创建了一个 Windows 服务来将数据提供给我们的客户端应用程序,一切都很顺利。 客户端提出了一个有趣的配置请求,该请求需要在同一服务器上运行该服务的两个实例,并配置为指向不同的数据库。

到目前为止,我还没有能够实现这一点,并希望我的 stackoverflow 成员能够给出一些关于原因的提示。

当前设置:

我已经设置了包含 Windows 服务的项目,从现在起我们将其称为 AppService,以及处理自定义安装步骤以根据应用程序中的键设置服务名称的 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 的以下输出(仅相关部分):

运行事务安装。

开始安装的安装阶段。

正在安装服务应用服务二... 服务应用服务二已成功安装。 在日志应用程序中创建EventLog源应用程序服务二...

安装阶段发生异常。 System.NullReferenceException:未将对象引用设置为对象的实例。

安装的回滚阶段即将开始。

将源应用服务二的事件日志恢复到之前的状态。 正在从系统中删除服务应用程序服务二... 服务应用服务二已成功从系统中删除。

回滚阶段成功完成。

事务安装已完成。 安装失败,已回滚。

很抱歉这篇冗长的文章,想确保有足够的相关信息。 到目前为止让我感到困惑的是,它指出服务的安装成功完成,并且只有在创建 EventLog 源之后,NullReferenceException 似乎才会被抛出。 因此,如果有人知道我做错了什么或有更好的方法,我将不胜感激。

So we've produced a windows service to feed data to our client application and everything is going great. The client has come up with a fun configuration request that requires two instances of this service running on the same server and configured to point at separate databases.

So far I haven't been able to get this to happen and was hoping my fellow stackoverflow members might be able to give some hints as to why.

Current setup:

I've set up the project that contains the windows service, we'll call it AppService from now on, and the ProjectInstaller.cs file that handles custom installation steps to set the service name based on a key in the App.config like so:

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

In this case Util is just a static class tha tloads the service name from the config file.

From here forward I have tried two different ways to get both services installed and both have failed in an identical way.

The first way was to simply install the first copy of the service, copy the installed directory and renamed it, and then ran the following command after modifying the app config to change the desired service name:

InstallUtil.exe /i AppService.exe

When that didn't work I tried to create a second installer project, edited the config file and built the second installer. When I ran the installer it worked fine but the service did not show up in services.msc so I ran the previous command against the second installed code base.

Both times i received the following output from InstallUtil (relevant parts only):

Running a transacted installation.

Beginning the Install phase of the installation.

Installing service App Service Two...
Service App Service Two has been successfully installed.
Creating EventLog source App Service Two in log Application...

An exception occurred during the Install phase.
System.NullReferenceException: Object reference not set to an instance of an object.

The Rollback phase of the installation is beginning.

Restoring event log to previous state for source App Service Two.
Service App Service Two is being removed from the system...
Service App Service Two was successfully removed from the system.

The Rollback phase completed successfully.

The transacted install has completed.
The installation failed, and the rollback has been performed.

Sorry for the long winded post, wanted to make sure there is enough relevant information. The piece that so far has me stumped is that it states that the installation of the service completes successfully and its only after it goes to create the EventLog source that the NullReferenceException seems to get thrown. So if anyone knows what I'm doing wrong or has a better approach it would be much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

百善笑为先 2024-08-08 20:28:06

您尝试过 sc / 服务控制器 util 吗? 在命令行中键入

sc create

,它将为您提供帮助条目。 我想我过去已经为 Subversion 做过这个并使用 本文作为参考:

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

Have you tried the sc / service controller util? Type

sc create

at a command line, and it will give you the help entry. I think I've done this in the past for Subversion and used this article as a reference:

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

乖不如嘢 2024-08-08 20:28:06
  sc create [servicename] binpath= [path to your exe]

这个解决方案对我有用。

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

This solution worked for me.

毁梦 2024-08-08 20:28:06

您可以通过执行以下操作来运行同一服务的多个版本:

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());
            }
        }
    }
}

You can run multiple versions of the same service by doing the following:

1) Copy the Service executable and config to its own folder.

2) Copy Install.Exe to the service executable folder (from .net framework folder)

3) Create a config file called Install.exe.config in the service executable folder
with the following contents (unique service names):

<?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) Create a batch file to install the service with the following contents:

REM Install
InstallUtil.exe YourService.exe
pause

5) While your there, create an uninstall batch file

REM Uninstall
InstallUtil.exe -u YourService.exe
pause

EDIT:

Note sure if I missed something, here is the ServiceInstaller Class (adjust as required):

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());
            }
        }
    }
}
情话难免假 2024-08-08 20:28:06

ServiceNameDisplayName 指定自定义值的另一种快速方法是使用 installutil 命令行参数。

  1. 在您的 ProjectInstaller 类中重写虚拟方法 Install(IDictionary stateSaver)Uninstall(IDictionary savingState)

    公共覆盖 void Install(System.Collections.IDictionary stateSaver) 
      { 
          获取自定义服务名称(); 
          基础安装(stateSaver); 
      } 
    
      公共覆盖无效卸载(System.Collections.IDictionarysavedState) 
      { 
          获取自定义服务名称(); 
          卸载(savedState); 
      } 
    
      //从installutil命令行参数中检索自定义服务名称 
      私有无效 GetCustomServiceName() 
      { 
          string customServiceName = Context.Parameters["服务名称"]; 
          if (!string.IsNullOrEmpty(customServiceName)) 
          { 
              serviceInstaller1.ServiceName = 自定义服务名称; 
              serviceInstaller1.DisplayName = 自定义服务名称; 
          } 
      } 
      
  2. 构建您的项目
  3. 使用 installutil 安装服务,并使用 /servicename 参数添加您的自定义名称:

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

请注意,如果您不指定 /servicename< /code> 在命令行中,服务将使用 ProjectInstaller 属性/配置中指定的 ServiceName 和 DisplayName 值进行安装

Another quick way to specify a custom value for ServiceName and DisplayName is using installutil command line parameters.

  1. In your ProjectInstaller class override virtual methods Install(IDictionary stateSaver) and 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. Build your project
  3. Install the service with installutil adding your custom name using /servicename parameter:

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

Please note that if you do not specify /servicename in the command line the service will be installed with ServiceName and DisplayName values specified in ProjectInstaller properties/config

能怎样 2024-08-08 20:28:06

老问题,我知道,但我很幸运地使用了 InstallUtil.exe 上的 /servicename 选项。 但我没有看到它在内置帮助中列出。

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

我不太确定我第一次读到这篇文章的地方,但从那以后我就再也没有见过它。 YMMV。

Old question, I know, but I've had luck using the /servicename option on InstallUtil.exe. I don't see it listed in the built-in help though.

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

I'm not entirely sure where I first read about this but I haven't seen it since. YMMV.

假装爱人 2024-08-08 20:28:06

当使用我们的自动化部署软件频繁安装/卸载并行 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

这将使用以下内容创建服务:名称“很棒的服务-UAT”。 我们使用它来运行在一台机器上并行运行的同一服务的 DEVINT、TESTING 和 ACCEPTANCE 版本。 每个版本都有自己的一组文件/配置 - 我还没有尝试安装指向同一组文件的多个服务。

注意:您必须使用相同的 /ServiceSuffix 参数来卸载服务,因此您需要执行以下命令来卸载:

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

I didn't have much luck with the above methods when using our automated deployment software to frequently install/uninstall side-by-side windows services, but I eventually came up with the following which allows me to pass in a parameter to specify a suffix to the service name on the command line. It also allows the designer to function properly and could easily be adapted to override the entire name if necessary.

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;
  }
}

With this in mind, I can do the following:
If I've called the service "Awesome Service" then I can install a UAT verison of the service as follows:

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

This will create the service with the name "Awesome Service - UAT". We've used this to run DEVINT, TESTING and ACCEPTANCE versions of the same service running side-by-side on a single machine. Each version has its own set of files/configs - I haven't tried this to install multiple services pointing at the same set of files.

NOTE: you have to use the same /ServiceSuffix parameter to uninstall the service, so you'd execute the following to uninstall:

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

小忆控 2024-08-08 20:28:06

为了完成这项工作,我所做的是将服务名称和显示名称存储在我的服务的 app.config 中。 然后在我的安装程序类中,我将 app.config 作为 XmlDocument 加载,并使用 xpath 获取值并将它们应用到 ServiceInstaller.ServiceName 和 ServiceInstaller.DisplayName,然后再调用 InitializeComponent()。 这假设您尚未在 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 或类似的内容读取配置文件会像安装程序运行时一样工作,它是在上下文中运行的InstallUtil.exe 的,而不是服务的 .exe。 您也许可以使用 ConfigurationManager.OpenExeConfiguration 执行某些操作,但是就我而言,这不起作用,因为我试图获取未加载的自定义配置部分。

What I've done to make this work is to store the service name and display name in an app.config for my service. Then in my installer class, I load the app.config as an XmlDocument and use xpath to get the values out and apply them to ServiceInstaller.ServiceName and ServiceInstaller.DisplayName, before calling InitializeComponent(). This assumes you're not already setting these properties in InitializeComponent(), in which case, the settings from your config file will be ignored. The following code is what I'm calling from my installer class constructor, before 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;
          }
      }

I don't believe reading the configuration file directly from ConfigurationManager.AppSettings or something similar will work as when the installer runs, it's run in the context of InstallUtil.exe, not your service's .exe. You may be able to do something with ConfigurationManager.OpenExeConfiguration, however in my case, this didn't work as I was trying to get at a custom configuration section that was not loaded.

超可爱的懒熊 2024-08-08 20:28:06

为了提高@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";
            }
        }

Just to improve perfect answer of @chris.house.00 this, you can consider following function to read from your app settings:

 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";
            }
        }
一张白纸 2024-08-08 20:28:06

我遇到了类似的情况,我需要有一个以前的服务,以及一个更新的服务在同一台服务器上并行运行。 (这不仅仅是数据库更改,也是代码更改)。 所以我不能只运行同一个 .exe 两次。 我需要一个新的 .exe,它是用新的 DLL 编译的,但来自同一个项目。 仅更改服务名称和服务的显示名称对我来说不起作用,我仍然收到“服务已存在错误”,我认为这是因为我正在使用部署项目。 最终对我有用的是我的部署项目属性中有一个名为“ProductCode”的属性,它是一个 Guid。

输入图片说明此处

之后,将安装项目重建为新的 .exe 或 .msi,安装成功。

I had a similar situation, where i to needed have a previous service, and an updated service running side by side on the same server. (It was more than just a database change, it was code changes as well). So I couldn't just run the same .exe twice. I needed a new .exe that was compiled with new DLLs but from the same project. Just changing the service name and display name of the service did not work for me, I still received the "service already existed error" which I believe is because I am using a Deployment Project. What finally did work for me is within my Deployment Project Properties there is a property called "ProductCode" which is a Guid.

enter image description here

After that, rebuilding the Setup Project to a new .exe or .msi installed successfully.

深海少女心 2024-08-08 20:28:06

最简单的方法是基于 dll 名称的服务名称:

string sAssPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
string sAssName = System.IO.Path.GetFileNameWithoutExtension(sAssPath);
if ((this.ServiceInstaller1.ServiceName != sAssName)) {
    this.ServiceInstaller1.ServiceName = sAssName;
    this.ServiceInstaller1.DisplayName = sAssName;
}

The simplest approach is is based the service name on the dll name:

string sAssPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
string sAssName = System.IO.Path.GetFileNameWithoutExtension(sAssPath);
if ((this.ServiceInstaller1.ServiceName != sAssName)) {
    this.ServiceInstaller1.ServiceName = sAssName;
    this.ServiceInstaller1.DisplayName = sAssName;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文