installutil bindingRedirect

时间:2010-10-15 06:58:31

标签: windows-services installutil

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

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

有几个版本的API(1.0.0.0,1.1.0.0等)

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

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

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

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

2 个答案:

答案 0 :(得分:0)

我刚刚参与其中,我能找到的唯一解决方案来自https://connect.microsoft.com/VisualStudio/feedback/details/525564/installutil-exe-does-not-honor-app-config-especially-binding-information

  

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

答案 1 :(得分: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操作,而不是运行服务操作。 Install操作的CustomActionData属性如下所示: /FileName="[TARGETDIR]MyService.exe" /Args="/install" WindowStyle="Hidden"

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

无需编写Commit,AFAIK。

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

PS MyService.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("\\\\", "\\");
        }
    }
}