4

我有一个依赖于 3:rd 方 API 的 Windows 服务

API 已安装在客户端计算机上的 GAC 中

API 有多个版本(1.0.0.0、1.1.0.0 等)

我的服务适用于所有版本的 API

我在 app.config 文件中使用了 bindingRedirect 标记,该标记在运行服务时可以正常工作。

问题是运行 InstallUtil 时未使用 app.config 文件,因此在注册服务时出现绑定异常。

目前我使用“sc create”手动注册服务但有更好的方法吗?
(无需编辑 machine.config 等)

4

2 回答 2

0

我刚刚遇到这个,我能找到的唯一解决方案是来自https://connect.microsoft.com/VisualStudio/feedback/details/525564/installutil-exe-does-not-honor-app-config-special-binding -信息

作为一种解决方法,您可以通过修改 InstallUtil.exe.config 文件以包含绑定信息来完成这项工作。InstallUtil.exe.config 安装到 %WinDir%\Microsoft.NET\Framework\\InstallUtil.exe.config 您正在使用的框架版本。

于 2014-04-17T15:28:24.217 回答
0

我想出了另一种解决方法来安装具有绑定重定向的服务。由于我有很多服务,这就是我决定追求的。

  1. 将 Windows 安装程序更改为控制台应用程序并实现自行安装的功能(使用命令行和 ManagedInstallerClass.InstallHelper)。

  2. 实现一个能够在完全独立的程序集中执行命令行的安装程序类,例如CommandLineInstaller.DLL. CommandLineInstaller.DLL,应以相同的方式实现方法 Install/Uninstall/Rollback - 使用以下参数执行命令行: FileName, WorkingDirectory, Args, WindowStyle.

  3. 修改安装项目以部署 1) 服务和 b)CommandLineInstaller.DLL

  4. 修改安装项目自定义操作:运行 CommandLineInstaller.DLL 的操作,而不是运行服务的操作。安装操作的 CustomActionData 属性将如下所示: /FileName="[TARGETDIR]MyService.exe" /Args="/install" WindowStyle="Hidden"

    动作配置: 安装:myservice /install 回滚:myservice /uninstall 卸载:myservice /uninstall

无需编写提交,AFAIK。

现在,安装项目将在自己的进程中执行 CommandLineInstaller.DLL 安装程序。然后 CommandLineInstaller.DLL 将依次在其自己的进程中启动 MyService.exe,并按照应有的方式进行血腥绑定重定向。

PSMyService.exe可以使用退出代码机制来通知安装程序失败,我强烈建议从 CommandLineInstaller 检查它们。

希望这是一个足够好的大纲。

PS 请注意 TARGETDIR 在将其自身传递给目录时需要有一个斜杠: /WorkDir="[TARGETDIR]\"

安装 CustomActionData 的示例: /FileName="[TARGETDIR]\MyService.exe" /Args="/install" /WorkingDir="[TARGETDIR]\" /ValidExitCode="0" /WindowStyle="Normal"

一些代码:


using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;

namespace QT.Install
{
    [RunInstaller(true)]
    public partial class ExecuteCommandInstaller : System.Configuration.Install.Installer
    {
        public class CommandArgs
        {
            public string FileName { get; set; }
            public string WorkingDir { get; set; }
            public string Args { get; set; }
            public string ValidExitCode { get; set; }
            public ProcessWindowStyle WindowStyle { get; set; }
        }

        public ExecuteCommandInstaller()
        {
            InitializeComponent();
        }

        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);
            ExecuteCommand(stateSaver);
        }

        public override void Commit(IDictionary savedState)
        {
            base.Commit(savedState);
            ExecuteCommand(savedState);
        }

        public override void Uninstall(IDictionary savedState)
        {
            base.Uninstall(savedState);
            ExecuteCommand(savedState);
        }

        public override void Rollback(IDictionary savedState)
        {
            base.Rollback(savedState);
            ExecuteCommand(savedState);
        }
        private void ExecuteCommand(IDictionary stateSaver)
        {
            CommandArgs commandArgs = new CommandArgs()
            {
                FileName = StripDoubleSlash(Context.Parameters["FileName"] ?? ""),
                WorkingDir = StripDoubleSlash(Context.Parameters["WorkingDir"] ?? ""),
                Args = Context.Parameters["Args"] ?? "",
                ValidExitCode = Context.Parameters["ValidExitCode"] ?? "*"
            };

            try
            {
                commandArgs.WindowStyle = (ProcessWindowStyle)Enum.Parse(typeof(ProcessWindowStyle), Context.Parameters["WindowStyle"] ?? "Hidden");
            }
            catch (Exception err)
            {
                throw new Exception($"Invalid WindowStyle parameter value: {Context.Parameters["WindowStyle"]}", err);
            }
            InternalExecuteCommand(commandArgs);
        }

        private void InternalExecuteCommand(CommandArgs commandArgs)
        {
            if (string.IsNullOrEmpty(commandArgs.FileName))
                throw new Exception("FileName is not specified.");

            System.Diagnostics.ProcessStartInfo startInfo = new ProcessStartInfo(commandArgs.FileName, commandArgs.Args);

            if (!string.IsNullOrEmpty(commandArgs.WorkingDir))
                startInfo.WorkingDirectory = commandArgs.WorkingDir;

            startInfo.WindowStyle = commandArgs.WindowStyle;

            using (var process = Process.Start(startInfo))
            {
                process.WaitForExit();

                if (commandArgs.ValidExitCode != "*")
                {
                    if (process.ExitCode.ToString() != commandArgs.ValidExitCode)
                        throw new Exception($"Executing {commandArgs.FileName} {commandArgs.Args} returned exit code {process.ExitCode}. Expected exit code is: {commandArgs.ValidExitCode}.");
                }
            }
        }

        private static string StripDoubleSlash(string value)
        {
            return value.Replace("\\\\", "\\");
        }
    }
}

于 2019-08-20T22:56:25.777 回答