4

サード パーティの 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-especially-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 のアクションを実行します。Install アクションの 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 に答える